ELF文件格式
ELF文件结构
ELF全称为Executable and Linkable Format,是 Linux 中的目标文件。
其内容视图主要有两种
![Link View](/2019/08/30/ELF%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F/object_file_format.png)
以链接视图来分析ELF的文件格式
- ELF Header -> 存放ELF文件的整体信息
- Program Header Table -> 存放程序执行时所需要的信息。其实就是段信息
- Section -> 存放程序大部分信息:指令、数据、符号表等等
- Section Header Table -> 存放描述节区的信息
ELF Header
用于索引ELF全部的信息,其数据结构如下(数据结构可以在/usr/include/elf.h查看)
1 | /* The ELF file header. This appears at the start of every ELF file. */ |
只了解其中部分含义
e_ident
其下标含义如下
宏名称 | 下标 | 目的 |
---|---|---|
EI_MAG0 | 0 | 文件标识 |
EI_MAG0 | 1 | 文件标识 |
EI_MAG0 | 2 | 文件标识 |
EI_MAG0 | 3 | 文件标识 |
EI_CLASS | 4 | 文件类 |
EI_DATA | 5 | 数据编码 |
EI_VERSION | 6 | 文件版本 |
EI_PAD | 7 | 补齐字节开始处 |
下标0-3称为魔数标识ELF文件
下标4EI_CLASS定义ELF类型,有以下取值
名称 | 值 | 意义 |
---|---|---|
ELFCLASSNONE | 0 | 无效类型 |
ELFCLASS32 | 1 | 32 位文件 |
ELFCLASS64 | 2 | 64 位文件 |
下标5 EI_DATA 定义大小端模式,有以下取值
名称 | 值 | 意义 |
---|---|---|
ELFDATANONE | 0 | 无效数据编码 |
ELFDATA2LSB | 1 | 小端 |
ELFDATA2MSB | 2 | 大端 |
下标6 EI_DATA 定义ELF头的版本号,与e_version相同
下标7 EI_PAD 给出了e_ident中未使用字节的开始地址。这些字节被保留并置为 0;处理目标文件的程序应该忽略它们。如果之后这些字节被使用,EI_PAD 的值就会改变。
e_phoff
给出程序头部表在文件中的字节偏移(Program Header table OFFset)。如果文件中没有程序头部表,则为 0。
e_shoff
给出节头表在文件中的字节偏移( Section Header table OFFset )。如果文件中没有节头表,则为 0。
Program Header Table
其类型为Elf32_Phdr结构体数组,ELF Header中的 e_phentsize 和 e_phnum 指定了该数组每个元素的大小以及元素个数。数据结构如下:
1 | /* Program segment header. */ |
前面说过其实这个表就是存放段信息的,暂且先了解p_type,p_offset字段
p_type
描述段类型,具体取值如下
名字 | 取值 | 说明 |
---|---|---|
PT_NULL | 0 | 表明段未使用,其结构中其他成员都是未定义的。 |
PT_LOAD | 1 | 此类型段为一个可加载的段,大小由 p_filesz 和 p_memsz 描述。文件中的字节被映射到相应内存段开始处。如果 p_memsz 大于 p_filesz,“剩余” 的字节都要被置为 0。p_filesz 不能大于 p_memsz。可加载的段在程序头部中按照 p_vaddr 的升序排列。 |
PT_DYNAMIC | 2 | 此类型段给出动态链接信息。 |
PT_INTERP | 3 | 此类型段给出了一个以 NULL 结尾的字符串的位置和长度,该字符串将被当作解释器调用。这种段类型仅对可执行文件有意义(也可能出现在共享目标文件中)。此外,这种段在一个文件中最多出现一次。而且这种类型的段存在的话,它必须在所有可加载段项的前面。 |
PT_NOTE | 4 | 此类型段给出附加信息的位置和大小。 |
PT_SHLIB | 5 | 该段类型被保留,不过语义未指定。而且,包含这种类型的段的程序不符合 ABI 标准。 |
PT_PHDR | 6 | 该段类型的数组元素如果存在的话,则给出了程序头部表自身的大小和位置,既包括在文件中也包括在内存中的信息。此类型的段在文件中最多出现一次。此外,只有程序头部表是程序的内存映像的一部分时,它才会出现。如果此类型段存在,则必须在所有可加载段项目的前面。 |
PT_LOPROC~PT_HIPROC | 0x70000000 ~0x7fffffff | 此范围的类型保留给处理器专用语义。 |
p_offset
存放从文件开始到该段开头的第一个字节的偏移
关于段和节的关系
简单来说段就是节的集合,段主要在程序装载时起作用。
![text segment](/2019/08/30/ELF%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F/text_segment.png)
- 有执行功能的代码指令流和只读属性的数据节组合成只读代码段。
- 可修改的数据变量,和动态调用的相对地址寻址入口组合成读写数据段。
- 不同的段来说可能会有所重合,即不同的段包含相同的节
Section Header Table
其类型为ELF32_Shdr结构体数组,存放节信息。其数据结构如下
1 | /* Section header. */ |
还是先了解部分字段
sh_type
名称 | 取值 | 说明 |
---|---|---|
SHT_NULL | 0 | 该类型节区是非活动的,这种类型的节头中的其它成员取值无意义。 |
SHT_PROGBITS | 1 | 该类型节区包含程序定义的信息,它的格式和含义都由程序来决定。 |
SHT_SYMTAB | 2 | 该类型节区包含一个符号表(SYMbol TABle)。目前目标文件对每种类型的 |
SHT_STRTAB | 3 | 该类型节区包含字符串表( STRing TABle )。 |
SHT_RELA | 4 | 该类型节区包含显式指定位数的重定位项( RELocation entry with Addends ),例如,32 位目标文件中的 Elf32_Rela 类型。此外,目标文件可能拥有多个重定位节区。 |
SHT_HASH | 5 | 该类型节区包含符号哈希表( HASH table )。 |
SHT_DYNAMIC | 6 | 该类型节区包含动态链接的信息( DYNAMIC linking )。 |
SHT_NOTE | 7 | 该类型节区包含以某种方式标记文件的信息(NOTE)。 |
SHT_NOBITS | 8 | 该类型节区不占用文件的空间,其它方面和 SHT_PROGBITS 相似。尽管该类型节区不包含任何字节,其对应的节头成员 sh_offset 中还是会包含概念性的文件偏移。 |
SHT_REL | 9 | 该类型节区包含重定位表项(RELocation entry without Addends),不过并没有指定位数。例如,32 位目标文件中的 Elf32_rel 类型。目标文件中可以拥有多个重定位节区。 |
SHT_SHLIB | 10 | 该类型此节区被保留,不过其语义尚未被定义。 |
SHT_DYNSYM | 11 | 作为一个完整的符号表,它可能包含很多对动态链接而言不必 要的符号。因此,目标文件也可以包含一个 SHT_DYNSYM 节区,其中保存动态链接符号的一个最小集合,以节省空间。 |
SHT_LOPROC | 0X70000000 | 此值指定保留给处理器专用语义的下界( LOw PROCessor-specific semantics )。 |
SHT_HIPROC | 0X7FFFFFFF | 此值指定保留给处理器专用语义的上界( HIgh PROCessor-specific semantics )。 |
SHT_LOUSER | 0X80000000 | 此值指定保留给应用程序的索引下界。 |
SHT_HIUSER | 0X8FFFFFFF | 此值指定保留给应用程序的索引上界。 |
Section
节区包含目标文件中除了 ELF 头部、程序头部表、节区头部表的所有信息。节区满足以下条件:
- 每个节区都有对应的节头来描述它。但是反过来,节区头部并不一定会对应着一个节区。
- 每个节区在目标文件中是连续的,但是大小可能为 0。
- 任意两个节区不能重叠,即一个字节不能同时存在于两个节区中。
- 目标文件中可能会有闲置空间(inactive space),各种头和节不一定会覆盖到目标文件中的所有字节,闲置区域的内容未指定。
先了解一些特殊节(前边带.的节是系统保留的)
名称 | 类型 | 属性 | 含义 |
---|---|---|---|
.comment | SHT_PROGBITS | 包含版本控制信息。 | |
.debug | SHT_PROGBITS | 此节区包含用于符号调试的信息。 | |
.dynamic | SHT_DYNAMIC | SHF_ALLOC SHF_WRITE | 此节区包含动态链接信息。SHF_WRITE 位设置与否是否被设置取决于具体的处理器。 |
.dynstr | SHT_STRTAB | SHF_ALLOC | 此节区包含用于动态链接的字符串,大多数 情况下这些字符串代表了与符号表项相关的名称。 |
.dynsym | SHT_DYNSYM | SHF_ALLOC | 此节区包含动态链接符号表。 |
.got | SHT_PROGBITS | 此节区包含全局偏移表。 | |
.line | SHT_PROGBITS | 此节区包含符号调试的行号信息,描述了源程序与机器指令之间的对应关系,其内容是未定义的。 | |
.plt | SHT_PROGBITS | 此节区包含过程链接表(procedure linkage table)。 | |
.relname | SHT_REL | 这些节区中包含重定位信息。如果文件中包含可加载的段,段中有重定位内容,节区的属性将包含 SHF_ALLOC 位,否则该位置 0。传统上 name 根据重定位所适用的节区给定。例如 .text 节区的重定位节区名字将是:.rel.text 或者 .rela.text。 | |
.relaname | SHT_RELA | ||
.shstrtab | SHT_STRTAB | 此节区包含节区名称。 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 F11st's Cyber Journey!