1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| typedef struct elf64_hdr { unsigned char e_ident[EI_NIDENT]; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } Elf64_Ehdr;
|

e_machine 取值
https://codebrowser.dev/glibc/glibc/elf/elf.h.html
1 2 3 4 5 6 7 8 9 10
| typedef struct elf64_phdr { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } Elf64_Phdr;
|
- 该段开始位置为基地址 + p_offset,长度为 p_memsz

p_flags

p_type
取值 |
代表 |
含义 |
00 |
PT_NULL |
此数组元素未用。结构中其他成员都是未定义的。 |
01 |
PT_LOAD |
此数组元素给出一个可加载的段,段的大小由 p_filesz 和 p_memsz 描述。文件中的字节被映射到内存段开始处。如果 p_memsz 大于 p_filesz,“剩余”的字节要清零。p_filesz 不能大于 p_memsz。可加载的段在程序头部表格中根据 p_vaddr 成员按升序排列。 |
02 |
PT_DYNAMIC |
数组元素给出动态链接信息。 |
03 |
PT_INTERP |
数组元素给出一个 NULL 结尾的字符串的位置和长度,该字符串将被当作解释器调用。这种段类型仅对与可执行文件有意义(尽管也可能在共享目标文件上发生)。在一个文件中不能出现一次以上。如果存在这种类型的段,它必须在所有可加载段项目的前面。 |
04 |
PT_NOTE |
此数组元素给出附加信息的位置和大小。 |
05 |
PT_SHLIB |
此段类型被保留,不过语义未指定。包含这种类型的段的程序与 ABI不符。 |
06 |
PT_PHDR |
此类型的数组元素如果存在,则给出了程序头部表自身的大小和位置,既包括在文件中也包括在内存中的信息。此类型的段在文件中不能出现一次以上。并且只有程序头部表是程序的内存映像的一部分时才起作用。如果存在此类型段,则必须在所有可加载段项目的前面。 |
0x70000000 |
PT_LOPROC |
此范围的类型保留给处理器专用语义。 |
0x7fffffff |
PT_HIPROC |
此范围的类型保留给处理器专用语义。 |
1 2 3 4 5 6 7 8 9 10 11 12
| typedef struct elf64_shdr { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } Elf64_Shdr;
|
成员 |
说明 |
sh_name |
节名称,是节区头字符串表节区中(Section Header String Table Section)的索引,因此该字段实际是一个数值。在字符串表中的具体内容是以 NULL 结尾的字符串。 |
sh_type |
根据节的内容和语义进行分类,具体的类型下面会介绍 |
sh_flags |
每一比特代表不同的标志,描述节是否可写,可执行,需要分配内存等属性。 |
sh_addr |
如果节区将出现在进程的内存映像中,此成员给出节区的第一个字节应该在进程镜像中的位置。否则,此字段为 0 |
sh_offset |
给出节区的第一个字节与文件开始处之间的偏移。SHT_NOBITS 类型的节区不占用文件的空间,因此其 sh_offset 成员给出的是概念性的偏移。 |
sh_size |
此成员给出节区的字节大小。除非节区的类型是 SHT_NOBITS ,否则该节占用文件中的 sh_size 字节。类型为 SHT_NOBITS 的节区长度可能非零,不过却不占用文件中的空间。 |
sh_link |
此成员给出节区头部表索引链接,其具体的解释依赖于节区类型 |
sh_info |
此成员给出附加信息,其解释依赖于节区类型。 |
sh_addralign |
某些节区的地址需要对齐。例如,如果一个节区有一个 doubleword 类型的变量,那么系统必须保证整个节区按双字对齐。也就是说sh_addr%sh_addralign = 0。 目前它仅允许为 0,以及 2 的正整数幂数。 0 和 1 表示没有对齐约束 |
sh_entsize |
某些节区中存在具有固定大小的表项的表,如符号表。对于这类节区,该成员给出每个表项的字节大小。反之,此成员取值为 0 |
- header中e_shstrndx记录了.shstrtab的索引位置,sh_name的字符串名为 :基地址 + shstrtab.sh_offset + section_h.sh_name
- section_h.sh_offset + section_h.sh_size = 下一个section的起始位置
- section_h.sh_size / section_h.sh_entsize = entry count (symtab count 和dynsym count)

sh_flags

sh_type
名称 |
取值 |
说明 |
SHT_NULL |
0 |
此值标志节区头部是非活动的,没有对应的节区。此节区头部中的其他成员取值无意义。 |
SHT_PROGBITS |
1 |
此节区包含程序定义的信息,其格式和含义都由程序来解释。 |
SHT_SYMTAB |
2 |
此节区包含一个符号表。目前目标文件对每种类型的节区都只能包含一个,不过这个限制将来可能发生变化。一般,SHT_SYMTAB 节区提供用于链接编辑(指 ld 而言)的符号,尽管也可用来实现动态链接。 |
SHT_STRTAB |
3 |
此节区包含字符串表。目标文件可能包含多个字符串表节区。 |
SHT_RELA |
4 |
此节区包含重定位表项,其中可能会有补齐内容(addend),例如 32 位目标文件中的 Elf32_Rela 类型。目标文件可能拥有多个重定位节区。 |
SHT_HASH |
5 |
此节区包含符号哈希表。所有参与动态链接的目标都必须包含一个符号哈希表。目前,一个目标文件只能包含一个哈希表,不过此限制将来可能会解除。 |
SHT_DYNAMIC |
6 |
此节区包含动态链接的信息。目前一个目标文件中只能包含一个动态节区,将来可能会取消这一限制。 |
SHT_NOTE |
7 |
此节区包含以某种方式来标记文件的信息。 |
SHT_NOBITS |
8 |
这种类型的节区不占用文件中的空间,其他方面和 SHT_PROGBITS 相似。尽管此节区不包含任何字节,成员sh_offset 中还是会包含概念性的文件偏移 |
SHT_REL |
9 |
此节区包含重定位表项,其中没有补齐(addends),例如 32 位目标文件中的 Elf32_rel 类型。目标文件中可以拥有多个重定位节区。 |
SHT_SHLIB |
10 |
此节区被保留,不过其语义是未规定的。包含此类型节区的程序与 ABI 不兼容。 |
SHT_DYNSYM |
11 |
作为一个完整的符号表,它可能包含很多对动态链接而言不必要的符号。因此,目标文件也可以包含一个 SHT_DYNSYM 节区,其中保存动态链接符号的一个最小集合,以节省空间。 |
SHT_LOPROC |
0X70000000 |
这一段(包括两个边界),是保留给处理器专用语义的。 |
SHT_HIPROC |
0X7FFFFFFF |
这一段(包括两个边界),是保留给处理器专用语义的。 |
SHT_LOUSER |
0X80000000 |
此值给出保留给应用程序的索引下界。 |
SHT_HIUSER |
0X8FFFFFFF |
此值给出保留给应用程序的索引上界。 |
sh_name
sh_name |
sh_type |
说明 |
.text |
SHT_PROGBITS |
代码段,包含程序的可执行指令 |
.data |
SHT_PROGBITS |
包含初始化了的数据,将出现在程序的内存映像中 |
.bss |
SHT_NOBITS |
未初始化数据 |
.rodata |
SHT_PROGBITS |
包含只读数据 |
.comment |
SHT_PROGBITS |
包含版本控制信息 |
.dynsym |
SHT_DYNSYM |
此节区包含了动态链接符号表 |
.shstrtab |
SHT_STRTAB |
存放section名,字符串表。Section |
Header String Table |
|
|
.strtab |
SHT_STRTAB |
字符串表 |
.symtab |
SHT_SYMTAB |
符号表 |
.rel.text |
SHT_REL |
告诉链接器,哪些地方需要重定向。 |
|
|
|
|
|
|
符号表
1 2 3 4 5 6 7 8
| typedef struct elf64_sym { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym;
|
- st_name 符号名称,给出的是一个在符号名称表(.dynstr)中的索引
- st_info 用于标示此符号的属性,占一个字节(2个字),两个标示位,第一个标示位(低四位)标志作用域,第二个标示位(高四位)标示符号类型
- st_other 固定值为0。
- **st_shndx **每个符号表项都以和其他节区间的关系的方式给出定义。此成员给出相关的节区头部表索引。某些索引具有特殊含义。
- st_value 一般都是函数地址,或者是一个常量值
- st_size 从 st_value 地址开始,共占的长度大小
c++filt 函数解析
其他
dynsym表中的符号是动态链接的符号
- 如果有地址,则可以被外部调用
- 如果没有地址,则需要依赖外部
libart.so 中带 symtab符号表,如果想调用没有导出的符号,可以查询symtab找到符号的逻辑地址,再加上maps中libart.so的基地址的地址,就是程序中符号的虚拟地址了。
dynstr,strtab,shstrtab的区别
- dynstr 动态字符串表,主要给dynsym表中使用
- strtab 字符串表,主要给symtab表使用
- shstrtab 给 section header table中使用