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

如何在Linux x86_64系统上获取VDSO的大小,linux,vdso,Linux,Vdso,我想将VDSO转储到磁盘,以便使用objdump-d验证它是否正确 我们可以使用getauxval(AT_SYSINFO_EHDR)获取VDSO的基址,如VDSO(7)中所述。但是,如何得到物体的大小呢 我碰巧知道它正好有两页长,但我不确定我能依靠它 我在ELF头中看不到任何指示对象整体大小的内容,我还尝试通过dl\u iterate\u phdr(3)迭代并转储部分,但没有任何乐趣(可能会跳过ELF头?) 有什么想法吗?我真的必须从proc映射中删除大小吗?VDSO头提供文件的开头。要找到终点

我想将VDSO转储到磁盘,以便使用
objdump-d
验证它是否正确

我们可以使用
getauxval(AT_SYSINFO_EHDR)
获取VDSO的基址,如
VDSO(7)
中所述。但是,如何得到物体的大小呢

我碰巧知道它正好有两页长,但我不确定我能依靠它

我在ELF头中看不到任何指示对象整体大小的内容,我还尝试通过
dl\u iterate\u 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;
}
#包括
#包括
#包括
结构elf_fhdr_64
{
uint32_t魔术;
uint8级;
uint8_t ei_数据;
uint8_t ei_版本;
uint8_tei_osabi;
uint8_t ei_abiversion;
uint8_t垫[7];
uint16_t e_型;
uint16_t____机器;
uint32_t e_版本;
uint64\u t\u条目;
uint64\u t e\u phoff;//程序头偏移量
uint64_t e__shoff;
uint32_t e_旗;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;//程序头数
uint16_t e_shentsize;
uint16_t e_shnum;
// ...
};
结构elf_phdr_64
{
uint32_t p_类型;
uint32_t p_旗;
uint64\u t p\u offset;//文件中的偏移量
uint64_t p_vaddr;
uint64_t p_paddr;
uint64_t p_filesz;//文件大小
// ...
};
结构elf\U shdr\U 64
{
uint32_t sh__________名称;
uint32_t sh_型;
uint64_t sh_旗帜;
uint64\u t sh\u addr;//加载时的虚拟地址
uint64\u t sh\u offset;//文件中的偏移量
uint64\u t sh\u size;//文件中的大小
// ...
};
int main(int argc,字符**argv)
{
无符号长vdso_hdr=getauxval(在SYSINFO_EHDR);
uint32精灵魔法=*(uint32 t*)vdso\U hdr;
if(elf_magic==0x464C457F){
printf(“拥有精灵魔法,正在进行…\n”);
}
否则{
printf(“没有精灵魔法。\n”);
出口(1);
}
结构elf_fhdr_64*fhdrp=(结构elf_fhdr_64*)vdso_hdr;
int num_phdrs=fhdrp->e_phnum;
uint16_t phentsize=fhdrp->e_phentsize;
长最大值=0;
对于(int i=0;ie_phoff+i*phentsize);
长文件\u offs=phdr->p\u offset+phdr->p\u filesz;
如果(最大值<文件值)最大值=文件值;
}
int num_shdrs=fhdrp->e_shnum;
int shentsize=fhdrp->e_shentsize;
对于(int i=0;ie_shoff+i*shentsize);
长文件\u offs=shdr->sh\u offset+shdr->sh\u size;
如果(最大值<文件值)最大值=文件值;
}
//截面表:
int section_table_max=fhdrp->e_shoff+(num_shdrs*shentsize);
如果(最大偏差<截面偏差表最大偏差)最大偏差=截面偏差表最大偏差;
//phdrs表:
int phdr_table_max=fhdrp->e_phoff+(num_phdrs*phentsize);
如果(最大值
这里有@davmac的代码整理并放入git repo:Proc映射会更简单。