繁体   English   中英

如何在 Linux x86_64 系统上获取 VDSO 的大小

[英]How to get the size of the VDSO on a Linux x86_64 system

我想以一种可以使用objdump -D验证它是否正确的方式将 VDSO 转储到磁盘。

我们可以使用getauxval(AT_SYSINFO_EHDR)获取 VDSO 的基地址,如vdso(7) 但是如何获得对象的大小呢?

我碰巧知道它正好有两页长,但我不确定我是否可以依靠它。

我在 ELF 标头中看不到任何表示整个对象大小的内容,而且我还尝试通过dl_iterate_phdr(3)迭代和转储这些部分,但很dl_iterate_phdr(3) (大概这会跳过 ELF 标头? )。

有任何想法吗? 我真的必须从 proc 地图中删除大小吗?

VDSO 标头为您提供了文件的开头。 要找到终点,请计算以下最大值:

  • 程序头表中所有段的结尾(偏移量+大小)
  • 节头表的结尾
  • 程序头表末尾

然后将开始和结束之间的所有内容写入磁盘。 以下程序应该可以解决问题:

#include <stdlib.h>
#include <stdio.h>
#include <sys/auxv.h>

struct elf_fhdr_64
{
    uint32_t magic;
    uint8_t ei_class;
    uint8_t ei_data;
    uint8_t ei_version;
    uint8_t ei_osabi;
    uint8_t ei_abiversion;
    uint8_t pad[7];
    uint16_t e_type;
    uint16_t e_machine;
    uint32_t e_version;
    uint64_t e_entry;
    uint64_t e_phoff; // program header offset
    uint64_t e_shoff;
    uint32_t e_flags;
    uint16_t e_ehsize;
    uint16_t e_phentsize;
    uint16_t e_phnum; // number of program headers
    uint16_t e_shentsize;
    uint16_t e_shnum;
    // ...
};

struct elf_phdr_64
{
    uint32_t p_type;
    uint32_t p_flags;
    uint64_t p_offset; // offset in file
    uint64_t p_vaddr;
    uint64_t p_paddr;
    uint64_t p_filesz;  // size in file
    // ...
};

struct elf_shdr_64
{
    uint32_t sh_name;
    uint32_t sh_type;
    uint64_t sh_flags;
    uint64_t sh_addr; // virtual addr when loaded
    uint64_t sh_offset; // offset in file
    uint64_t sh_size; // size in file
    // ...
};

int main(int argc, char **argv)
{
    unsigned long vdso_hdr = getauxval(AT_SYSINFO_EHDR);

    uint32_t elf_magic = * (uint32_t *)vdso_hdr;
    if (elf_magic == 0x464C457F) {
        printf("has elf magic, proceeding...\n");
    }
    else {
        printf("no elf magic.\n");
        exit(1);
    }

    struct elf_fhdr_64 * fhdrp = (struct elf_fhdr_64 *) vdso_hdr;

    int num_phdrs = fhdrp->e_phnum;
    uint16_t phentsize = fhdrp->e_phentsize;

    long max_offs = 0;

    for (int i = 0; i < num_phdrs; i++) {
        struct elf_phdr_64 * phdr = (struct elf_phdr_64 *)(vdso_hdr
            + fhdrp->e_phoff + i * phentsize);
        long file_offs = phdr->p_offset + phdr->p_filesz;
        if (max_offs < file_offs) max_offs = file_offs;
    }

    int num_shdrs = fhdrp->e_shnum;
    int shentsize = fhdrp->e_shentsize;

    for (int i = 0; i < num_shdrs; i++) {
        struct elf_shdr_64 * shdr = (struct elf_shdr_64 *)(vdso_hdr
            + fhdrp->e_shoff + i * shentsize);
        long file_offs = shdr->sh_offset + shdr->sh_size;
        if (max_offs < file_offs) max_offs = file_offs;
    }

    // section table:
    int section_table_max = fhdrp->e_shoff + (num_shdrs * shentsize);
    if (max_offs < section_table_max) max_offs = section_table_max;

    // phdrs table:
    int phdr_table_max = fhdrp->e_phoff + (num_phdrs * phentsize);
    if (max_offs < phdr_table_max) max_offs = section_table_max;

    FILE * outfile = fopen("test-vdso.so", "wb");
    if (outfile) {
        fwrite((void *) vdso_hdr, 1, max_offs, outfile);
        fclose(outfile);
    }

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM