简体   繁体   English

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

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

I'd like to dump the VDSO to disk in a way that I can verify it is correct with objdump -D .我想以一种可以使用objdump -D验证它是否正确的方式将 VDSO 转储到磁盘。

We can get the base address of the VDSO with getauxval(AT_SYSINFO_EHDR) as documented in vdso(7) .我们可以使用getauxval(AT_SYSINFO_EHDR)获取 VDSO 的基地址,如vdso(7) But how does one get the size of the object?但是如何获得对象的大小呢?

I happen to know it is exactly two pages long, but I'm not certain I can rely on that.我碰巧知道它正好有两页长,但我不确定我是否可以依靠它。

I can't see anything in the ELF header that would indicate the size of the object as a whole, and I've also tried iterating and dumping the sections via dl_iterate_phdr(3) to no joy (presumably this would skip the ELF header?).我在 ELF 标头中看不到任何表示整个对象大小的内容,而且我还尝试通过dl_iterate_phdr(3)迭代和转储这些部分,但很dl_iterate_phdr(3) (大概这会跳过 ELF 标头? )。

Any ideas?有任何想法吗? Do I really have to scrape the size out of the proc maps?我真的必须从 proc 地图中删除大小吗?

The VDSO header gives you the start of the file. VDSO 标头为您提供了文件的开头。 To find the end, calculate the maximum of:要找到终点,请计算以下最大值:

  • the end of all segments from the program header table (offset + size)程序头表中所有段的结尾(偏移量+大小)
  • the end of the section header table节头表的结尾
  • the end of the program header table程序头表末尾

Then write everything between the start and end to disk.然后将开始和结束之间的所有内容写入磁盘。 The following program should do the trick:以下程序应该可以解决问题:

#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