安全读取ELF文件头需先校验魔数\x7fELF,再据e_ident[EI_CLASS]选32/64位结构体,用ntohs/ntohl转换字段,并通过pread+e_phoff/e_shoff安全读取program/section header表,注意SHN_XINDEX和字符串表偏移。

怎么用 C++ 读取 ELF 文件头而不崩溃
直接 fread 读前 52 字节大概率出错,因为没校验魔数、没判断字节序、也没考虑对齐。ELF 文件开头必须是 \x7fELF,否则不是合法 ELF;32 位和 64 位结构体布局不同,e_ident[EI_CLASS] 决定后续怎么解析。
实操建议:
- 先用
open()打开文件,read()读前 16 字节,检查buf[0]==0x7f && buf[1]=='E' && buf[2]=='L' && buf[3]=='F' - 根据
buf[4](即EI_CLASS)选结构:值为1用Elf32_Ehdr,2用Elf64_Ehdr - 别直接
reinterpret_cast整块内存——文件可能是小端但运行环境是大端,e_type、e_machine等字段需用ntohs()/ntohl()转换 - 注意:Linux
readelf -h输出的 “Data” 字段对应e_ident[EI_DATA],1是小端,2是大端
如何安全遍历 ELF 的 program header 表
很多代码直接算地址:ehdr + e_phoff,但 e_phoff 是文件偏移,不是内存地址,且可能超出文件大小;e_phnum 也可能为 0 或超限。
常见错误现象:Segmentation fault、读到乱码、解析出负的 p_vaddr。
立即学习“C++免费学习笔记(深入)”;
实操建议:
- 读完
Elf*_Ehdr后,先检查e_phoff != 0 && e_phnum != 0,再lseek(fd, e_phoff, SEEK_SET) - 用
pread()比read()更安全:避免改变文件 offset,也省去反复lseek - 每个
Elf*_Phdr大小由e_phentsize给出,不能硬写sizeof(Elf64_Phdr)—— 某些工具链会 pad -
p_filesz和p_memsz可能不等,比如 BSS 段p_filesz==0但p_memsz>0,别直接 memcpy 整段
解析 section header 表时为什么字符串表老是读错
shstrtab(section name string table)索引在 e_shstrndx,但这个值可能是 SHN_XINDEX(0xffff),此时真实索引存在第 0 个 section 的 sh_link 字段里——这是最常被忽略的兼容性坑。
使用场景:想打印所有 section 名,结果 .text 变成乱码或空串。
实操建议:
- 先读
Elf*_Shdr表,确认e_shstrndx != SHN_UNDEF;若等于SHN_XINDEX,则读第 0 项的sh_link作为真实索引 - 字符串表本身也是个
section,得用它的sh_offset和sh_size去pread(),别假设它在文件末尾或紧挨着 header -
sh_name是相对于字符串表起始的偏移,不是指针,别char* s = strtab + shdr.sh_name后直接printf("%s", s)——得确保sh_name + 1 < strtab_size - 某些 stripped 文件删了
.shstrtab,e_shstrndx为SHN_UNDEF,这时没法还原 section 名,得接受这点
用 libelf 或 llvm ObjectFile 会不会更省事
会,但代价是引入依赖和构建复杂度。libelf 默认不校验完整性,elf_begin() 成功不代表文件结构有效;LLVM 的 object::ObjectFile 对 corrupt 文件更健壮,但编译它要拉整个 LLVM 工具链。
性能影响:libelf 内部做大量 mmap 和 lazy parsing,小文件反而比手撸 read 慢;LLVM 版本更新快,ELFFile<ELF64LE> 模板参数稍不匹配就编译失败。
实操建议:
- 只解析 header / phdr / shdr?手写更轻量、可控、调试方便
- 要 dump symbol、relocation、debug info?优先用
llvm-readobj或封装好的ObjectFile::createObjectFile() - 若选 libelf:务必检查
elf_kind(elf) == ELF_K_ELF,且每次gelf_getsym()前确认data->d_size >= sizeof(GElf_Sym) - 别信文档说的 “thread-safe”——libelf 的全局状态(如错误号)在多线程下仍需加锁
真正麻烦的从来不是读几个字段,而是面对 strip 过、packed、自修改、或交叉编译生成的 ELF 时,e_machine 和 e_type 组合的有效性没人替你兜底。



















