ELF文件解析
参考文献:
0x00 ELF简介
ELF (Executable and Linkable Format)文件,也就是在 Linux 中的目标文件,主要有以下三种类型
- 可重定位文件(Relocatable File),包含由编译器生成的代码以及数据。链接器会将它与其它目标文件链接起来从而创建可执行文件或者共享目标文件。在 Linux 系统中,这种文件的后缀一般为
.o
。 - 可执行文件(Executable File),就是我们通常在 Linux 中执行的程序。
- 共享目标文件(Shared Object File),包含代码和数据,这种文件是我们所称的库文件,一般以
.so
结尾。一般情况下,它有以下两种使用情景:- 链接器(Link eDitor, ld)可能会处理它和其它可重定位文件以及共享目标文件,生成另外一个目标文件。
- 动态链接器(Dynamic Linker)将它与可执行文件以及其它共享目标组合在一起生成进程镜像。
0x01 ELF文件组成
文件组成参考:Object Files
ELF文件由ELF头(ELF Header)、程序头部表(Program Header Table)、节区头部表(Section Header Table)和节区(Sections)组成
除了ELF头以外,其他部分没有严格的顺序,即可以任意更换他们的位置
经典例子如下
0x02 ELF的数据格式
ELF 文件格式支持 8 位 / 32 位体系结构。当然,这种格式是可以扩展的,也可以支持更小的或者更大位数的处理器架构。因此,目标文件会包含一些控制数据,这部分数据表明了目标文件所使用的架构,这也使得它可以被通用的方式来识别和解释。目标文件中的其它数据采用目的处理器的格式进行编码,与在何种机器上创建没有关系。这里其实想表明的意思目标文件可以进行交叉编译,我们可以在 x86 平台生成 arm 平台的可执行代码。
名称 | 长度 | 对齐方式 | 用途 |
---|---|---|---|
Elf64_Addr | 8 | 8 | 无符号程序地址 |
Elf64_Off | 8 | 8 | 无符号文件偏移 |
Elf64_Half | 2 | 2 | 无符号半整型 |
Elf64_Word | 4 | 4 | 无符号整型 |
Elf64_Sword | 4 | 4 | 有符号整型 |
Elf64_Xword | 8 | 8 | 无符号长整形 |
Elf64_Sxword | 8 | 8 | 有符号长整型 |
unsigned char | 1 | 1 | 无符号小整形 |
后面将以64位为主进行介绍
0x03 文件头(ELF Header)
参考:ELF Header
类似于PE文件,ELF文件也有一个文件头(ELF Header),头内给出了整个文件的组织情况,以64位文件为例,文件头内容如下
1 | typedef struct { |
各参数含义如下
e_ident
该变量给出了用于解码和解释文件中与机器无关的数据的方式,不同的下标对应不同的内容
宏名称 | 下标 | 目的 |
---|---|---|
EI_MAG0 |
0 | 文件标识 |
EI_MAG1 |
1 | 文件标识 |
EI_MAG2 |
2 | 文件标识 |
EI_MAG3 |
3 | 文件标识 |
EI_CLASS |
4 | 文件类 |
EI_DATA |
5 | 数据编码 |
EI_VERSION |
6 | 文件版本 |
EI_OSABI |
7 | 操作系统/ABI标识 |
EI_ABIVERSION |
8 | ABI版本 |
EI_PAD |
9 | 补齐字节开始处 |
EI_NIDENT |
16 | e_ident 的大小 |
EI_MAG0到EI_MAG3
共四字节为魔数,标识该文件为一个ELF目标文件
名称 | 值 | 位置 |
---|---|---|
ELFMAG0 | 0x7f | e_ident[EI_MAG0] |
ELFMAG1 | ‘E’ | e_ident[EI_MAG1] |
ELFMAG2 | ‘L’ | e_ident[EI_MAG2] |
ELFMAG3 | ‘F’ | e_ident[EI_MAG3] |
EI_CLASS
e_ident[EI_CLASS]
为e_ident[EI_MAG3]`的下一个字节,标识文件的类型或容量。
名称 | 值 | 意义 |
---|---|---|
ELFCLASSNONE | 0 | 无效类型 |
ELFCLASS32 | 1 | 32 位文件 |
ELFCLASS64 | 2 | 64 位文件 |
ELF 文件的设计使得它可以在多种字节长度的机器之间移植,而不需要强制规定机器的最长字节长度和最短字节长度。
文件的类定义了对象文件容器本身的数据结构所使用的基本类型。对象文件部分包含的数据可能遵循不同的编程模型。如果是这样,则处理器补充描述了所使用的模型。
EI_DATA
此字节指定了对象文件容器使用的数据结构和对象文件节中包含的数据的编码。目前定义了以下编码。
名称 | 值 | 意义 |
---|---|---|
ELFDATANONE | 0 | 无效数据编码 |
ELFDATA2LSB | 1 | 小端 |
ELFDATA2MSB | 2 | 大端 |
其它值被保留,在未来必要时将被赋予新的编码。
EI_VERSION
给出了ELF头的版本号。目前这个值必须是EV_CURRENT
,即之前已经给出的e_version
。
EI_OSABI
字节e_ident[EI_OSABI]
确定该文件所使用的特定于操作系统或应用二进制接口(ABI)的ELF扩展。在其他ELF结构中的某些字段中,有标志和值具有特定于操作系统和/或ABI的含义;这些字段的解释由该字节的值决定。如果对象文件不使用任何扩展,建议将该字节设置为 0。如果该字节的值为64到255,则其含义取决于e_machine
头部成员的值。对于某一架构,ABI处理器补充可以在此范围内定义其自己相关的一组值。如果处理器补充未指定一组值,则应使用以下值之一,其中0也可以表示未指定。
名称 | 值 | 含义 |
---|---|---|
ELFOSABI_NONE |
0 |
无扩展或未指定 |
ELFOSABI_HPUX |
1 |
Hewlett-Packard HP-UX |
ELFOSABI_NETBSD |
2 |
NetBSD |
ELFOSABI_LINUX |
3 |
Linux |
ELFOSABI_SOLARIS |
6 |
Sun Solaris |
ELFOSABI_AIX |
7 |
AIX |
ELFOSABI_IRIX |
8 |
IRIX |
ELFOSABI_FREEBSD |
9 |
FreeBSD |
ELFOSABI_TRU64 |
10 |
Compaq TRU64 UNIX |
ELFOSABI_MODESTO |
11 |
Novell Modesto |
ELFOSABI_OPENBSD |
12 |
Open BSD |
ELFOSABI_OPENVMS |
13 |
Open VMS |
ELFOSABI_NSK |
14 |
Hewlett-Packard Non-Stop Kernel |
64-255 |
特定于架构的值范围 |
EI_ABIVERSION
字节e_ident[EI_ABIVERSION]
用于标识目标对象所面向的ABI版本。此字段用于区分不兼容版本的ABI。此版本号的解释取决于EI_OSABI
字段所标识的 ABI。如果处理器补充文件未指定EI_OSABI
字段的值,或者对于由EI_OSABI
字节的特定值决定的ABI未指定版本值,则EI_ABIVERSION
字节的值应使用0;这表示未指定。
EI_PAD
给出了e_ident
中未使用字节的开始地址。这些字节被保留并置为0;处理目标文件的程序应该忽略它们。如果之后这些字节被使用,EI_PAD
的值就会改变。
e_type
该成员标识目标文件类型
名称 | 值 | 含义 |
---|---|---|
ET_NONE | 0 | 无文件类型 |
ET_REL | 1 | 可重定位文件 |
ET_EXEC | 2 | 可执行文件 |
ET_DYN | 3 | 共享目标文件 |
ET_CORE | 4 | 核心转储文件 |
ET_LOPROC | 0xff00 | 处理器指定下限 |
ET_HIPROC | 0xffff | 处理器指定上限 |
虽然核心转储文件的内容没有被详细说明,但ET_CORE
还是被保留用于标志此类文件。从ET_LOPROC
到ET_HIPROC
(包括边界)被保留用于处理器指定的场景。其它值在未来必要时可被赋予新的目标文件类型。
e_machine
指定了当前文件可以运行的机器架构
名称 | 值 | 含义 |
---|---|---|
EM_NONE |
0 |
无机器类型 |
EM_M32 |
1 |
AT&T WE 32100 |
EM_SPARC |
2 |
SPARC |
EM_386 |
3 |
Intel 80386 |
EM_68K |
4 |
Motorola 68000 |
EM_88K |
5 |
Motorola 88000 |
reserved | 6 |
Reserved for future use (was EM_486 ) |
EM_860 |
7 |
Intel 80860 |
EM_MIPS |
8 |
MIPS I Architecture |
EM_S370 |
9 |
IBM System/370 Processor |
EM_MIPS_RS3_LE |
10 |
MIPS RS3000 Little-endian |
reserved | 11-14 |
Reserved for future use |
EM_PARISC |
15 |
Hewlett-Packard PA-RISC |
reserved | 16 |
Reserved for future use |
EM_VPP500 |
17 |
Fujitsu VPP500 |
EM_SPARC32PLUS |
18 |
Enhanced instruction set SPARC |
EM_960 |
19 |
Intel 80960 |
EM_PPC |
20 |
PowerPC |
EM_PPC64 |
21 |
64-bit PowerPC |
EM_S390 |
22 |
IBM System/390 Processor |
reserved | 23-35 |
Reserved for future use |
EM_V800 |
36 |
NEC V800 |
EM_FR20 |
37 |
Fujitsu FR20 |
EM_RH32 |
38 |
TRW RH-32 |
EM_RCE |
39 |
Motorola RCE |
EM_ARM |
40 |
Advanced RISC Machines ARM |
EM_ALPHA |
41 |
Digital Alpha |
EM_SH |
42 |
Hitachi SH |
EM_SPARCV9 |
43 |
SPARC Version 9 |
EM_TRICORE |
44 |
Siemens TriCore embedded processor |
EM_ARC |
45 |
Argonaut RISC Core, Argonaut Technologies Inc. |
EM_H8_300 |
46 |
Hitachi H8/300 |
EM_H8_300H |
47 |
Hitachi H8/300H |
EM_H8S |
48 |
Hitachi H8S |
EM_H8_500 |
49 |
Hitachi H8/500 |
EM_IA_64 |
50 |
Intel IA-64 processor architecture |
EM_MIPS_X |
51 |
Stanford MIPS-X |
EM_COLDFIRE |
52 |
Motorola ColdFire |
EM_68HC12 |
53 |
Motorola M68HC12 |
EM_MMA |
54 |
Fujitsu MMA Multimedia Accelerator |
EM_PCP |
55 |
Siemens PCP |
EM_NCPU |
56 |
Sony nCPU embedded RISC processor |
EM_NDR1 |
57 |
Denso NDR1 microprocessor |
EM_STARCORE |
58 |
Motorola Star*Core processor |
EM_ME16 |
59 |
Toyota ME16 processor |
EM_ST100 |
60 |
STMicroelectronics ST100 processor |
EM_TINYJ |
61 |
Advanced Logic Corp. TinyJ embedded processor family |
EM_X86_64 |
62 |
AMD x86-64 architecture |
EM_PDSP |
63 |
Sony DSP Processor |
EM_PDP10 |
64 |
Digital Equipment Corp. PDP-10 |
EM_PDP11 |
65 |
Digital Equipment Corp. PDP-11 |
EM_FX66 |
66 |
Siemens FX66 microcontroller |
EM_ST9PLUS |
67 |
STMicroelectronics ST9+ 8/16 bit microcontroller |
EM_ST7 |
68 |
STMicroelectronics ST7 8-bit microcontroller |
EM_68HC16 |
69 |
Motorola MC68HC16 Microcontroller |
EM_68HC11 |
70 |
Motorola MC68HC11 Microcontroller |
EM_68HC08 |
71 |
Motorola MC68HC08 Microcontroller |
EM_68HC05 |
72 |
Motorola MC68HC05 Microcontroller |
EM_SVX |
73 |
Silicon Graphics SVx |
EM_ST19 |
74 |
STMicroelectronics ST19 8-bit microcontroller |
EM_VAX |
75 |
Digital VAX |
EM_CRIS |
76 |
Axis Communications 32-bit embedded processor |
EM_JAVELIN |
77 |
Infineon Technologies 32-bit embedded processor |
EM_FIREPATH |
78 |
Element 14 64-bit DSP Processor |
EM_ZSP |
79 |
LSI Logic 16-bit DSP Processor |
EM_MMIX |
80 |
Donald Knuth’s educational 64-bit processor |
EM_HUANY |
81 |
Harvard University machine-independent object files |
EM_PRISM |
82 |
SiTera Prism |
EM_AVR |
83 |
Atmel AVR 8-bit microcontroller |
EM_FR30 |
84 |
Fujitsu FR30 |
EM_D10V |
85 |
Mitsubishi D10V |
EM_D30V |
86 |
Mitsubishi D30V |
EM_V850 |
87 |
NEC v850 |
EM_M32R |
88 |
Mitsubishi M32R |
EM_MN10300 |
89 |
Matsushita MN10300 |
EM_MN10200 |
90 |
Matsushita MN10200 |
EM_PJ |
91 |
picoJava |
EM_OPENRISC |
92 |
OpenRISC 32-bit embedded processor |
EM_ARC_A5 |
93 |
ARC Cores Tangent-A5 |
EM_XTENSA |
94 |
Tensilica Xtensa Architecture |
EM_VIDEOCORE |
95 |
Alphamosaic VideoCore processor |
EM_TMM_GPP |
96 |
Thompson Multimedia General Purpose Processor |
EM_NS32K |
97 |
National Semiconductor 32000 series |
EM_TPC |
98 |
Tenor Network TPC processor |
EM_SNP1K |
99 |
Trebia SNP 1000 processor |
EM_ST200 |
100 |
STMicroelectronics (www.st.com) ST200 microcontroller |
其中EM应该是ELF Machine`的简写。
其它值被在未来必要时用于新的机器。此外,特定处理器的ELF名称使用机器名称来进行区分,一般标志会有个前缀EF_
(ELF Flag)。例如,在EM_XYZ
机器上名叫 WIDGET
的标志将被称为 EF_XYZ_WIDGET
。
e_version
标识目标文件的版本。
名称 | 值 | 含义 |
---|---|---|
EV_NONE | 0 | 无效版本 |
EV_CURRENT | 1 | 当前版本 |
1表示初始文件格式;未来扩展新的版本的时候 (extensions) 将使用更大的数字。虽然在上面值EV_CURRENT
为1,但是为了反映当前版本号,它可能会改变。
e_entry
这一项为系统转交控制权给 ELF 中相应代码的虚拟地址。如果没有相关的入口项,则这一项为 0。
e_phoff
这一项给出程序头部表在文件中的字节偏移(Program Header table OFFset)。如果文件中没有程序头部表,则为 0。
e_shoff
这一项给出节头表在文件中的字节偏移( Section Header table OFFset )。如果文件中没有节头表,则为 0。
e_flags
这一项给出文件中与特定处理器相关的标志,这些标志命名格式为EF_machine_flag
。
e_ehsize
这一项给出 ELF 文件头部的字节长度(ELF Header Size)。
e_phentsize
这一项给出程序头部表中每个表项的字节长度(Program Header ENTry SIZE)。每个表项的大小相同。
e_phnum
这一项给出程序头部表的项数(Program Header entry NUMber)。因此,e_phnum
与e_phentsize
的乘积即为程序头部表的字节长度。如果文件中没有程序头部表,则该项值为 0。
e_shentsize
这一项给出节头的字节长度(Section Header ENTry SIZE)。一个节头是节头表中的一项;节头表中所有项占据的空间大小相同。
e_shnum
这一项给出节头表中的项数(Section Header NUMber)。因此,e_shnum
与e_shentsize
的乘积即为节头表的字节长度。如果文件中没有节头表,则该项值为0。
如果节的数量大于或等于SHN_LORESERVE (0xff00)
,则此成员的值为零,实际的节头表条目数量包含在索引 0 的节头的sh_size
字段中。(否则,初始条目的sh_size
成员包含 0。)
e_shstrndx
这一项给出节头表中与节名字符串表相关的表项的索引值(Section Header table InDeX related with section name STRing table)。如果文件中没有节名字符串表,则该项值为SHN_UNDEF
。
如果节名字符串表的节索引大于或等于SHN_LORESERVE (0xff00)
,则该成员的值为SHN_XINDEX (0xffff)
,并且节名字符串表的实际索引包含在索引 0 的段头的sh_link
字段中。(否则,初始条目的sh_link
成员的值为 0。)
0x04 程序头部表(Program Header Table)
Program Header Table
是一个结构体数组,每一个元素的类型是Elf64_Phdr
,每个结构描述了一个段(segment)或者其它系统在准备程序执行时所需要的信息,一个段(segment)包含一个或多个节(section)。其中,ELF 头中的e_phentsize
和e_phnum
指定了该数组每个元素的大小以及元素个数。一个目标文件的段包含一个或者多个节。程序的头部只有对于可执行文件和共享目标文件有意义。
可以说,Program Header Table就是专门为ELF文件运行时中的段所准备的。
Elf64_phdr
数据结构如下
1 | typedef struct { |
字段说明如下:
p_type
该字段为段的类型,或者表明了该结构的相关信息。该字段取值如下:
名称 | 值 |
---|---|
PT_NULL |
0 |
PT_LOAD |
1 |
PT_DYNAMIC |
2 |
PT_INTERP |
3 |
PT_NOTE |
4 |
PT_SHLIB |
5 |
PT_PHDR |
6 |
PT_TLS |
7 |
PT_LOOS |
0x60000000 |
PT_HIOS |
0x6fffffff |
PT_LOPROC |
0x70000000 |
PT_HIPROC |
0x7fffffff |
各值含义如下:
PT_NULL
表明段未使用,其结构中其他成员都是未定义的。
PT_LOAD
此类型段为一个可加载的段,大小由p_filesz
和p_memsz
描述。文件中的字节被映射到相应内存段开始处。如果p_memsz
大于p_filesz
,“剩余” 的字节都要被置为 0。p_filesz
不能大于p_memsz
。可加载的段在程序头部中按照p_vaddr
的升序排列。
PT_DYNAMIC
此类型段给出动态链接信息,具体参考Dynamic Section
PT_INTERP
此类型段给出了一个以 NULL 结尾的字符串的位置和长度,该字符串将被当作解释器调用。这种段类型仅对可执行文件有意义(也可能出现在共享目标文件中)。此外,这种段在一个文件中最多出现一次。而且这种类型的段存在的话,它必须在所有可加载段项的前面。更多信息参考Program Interpreter
PT_NOTE
此类型段给出附加信息的位置和大小。更多信息参考Program Header
PT_SHLIB
该段类型被保留,不过语义未指定。而且,包含这种类型的段的程序不符合 ABI 标准。
PT_PHDR
该段类型的数组元素如果存在的话,则给出了程序头部表自身的大小和位置,既包括在文件中也包括在内存中的信息。此类型的段在文件中最多出现一次。此外,只有程序头部表是程序的内存映像的一部分时,它才会出现。如果此类型段存在,则必须在所有可加载段项目的前面。更多信息参考Program Interpreter
PT_TLS
数组元素指定线程局部存储模板。实现不需要支持此程序表条目。更多信息参考Thread-Local Storage
PT_LOOS到PT_HIOS
此范围内包含的值保留用于操作系统特定的语义.
PT_LOPROC到PT_HIPROC
在此包含范围内的值保留用于处理器特定的语义。如果有具体的含义说明,处理器补充文档将对此进行解释。
p_flags
被系统加载到内存中的程序至少有一个可加载的段。当系统为可加载的段创建内存镜像时,它会按照 p_flags 将段设置为对应的权限。可能的段权限位有
名称 | 值 | 含义 |
---|---|---|
PF_X |
0x1 |
可执行 |
PF_W |
0x2 |
可写 |
PF_R |
0x4 |
可读 |
PF_MASKOS |
0x0ff00000 |
未定义 |
PF_MASKPROC |
0xf0000000 |
未定义 |
其中,PF_MASKOS掩码中包含的所有位保留用于操作系统特定语义。PF_MASKPROC掩码中包含的所有位保留用于处理器特定语义。如果指定了含义,处理器补充说明将进行解释。
如果一个权限位被设置为 0,这种类型的段是不可访问的。实际的内存权限取决于相应的内存管理单元,不同的系统可能操作方式不一样。尽管所有的权限组合都是可以的,但是系统一般会授予比请求更多的权限。在任何情况下,除非明确说明,一个段不会有写权限。下面给出了所有的可能组合。
Flags | Value | Exact | Allowable |
---|---|---|---|
none | 0 |
All access denied | All access denied |
PF_X |
1 |
Execute only | Read, execute |
PF_W |
2 |
Write only | Read, write, execute |
PF_W+PF_X |
3 |
Write, execute | Read, write, execute |
PF_R |
4 |
Read only | Read, execute |
PF_R+PF_X |
5 |
Read, execute | Read, execute |
PF_R+PF_W |
6 |
Read, write | Read, write, execute |
PF_R+PF_W+PF_X |
7 |
Read, write, execute | Read, write, execute |
例如,一般来说,代码段一般具有读和执行权限,但是不会有写权限。数据段一般具有写,读,以及执行权限。
p_offset
该字段给出了从文件开始到该段开头的第一个字节的偏移。
p_vaddr
该字段给出了该段第一个字节在内存中的虚拟地址。
p_paddr
该字段仅用于物理地址寻址相关的系统中, 由于 “System V” 忽略了应用程序的物理寻址,可执行文件和共享目标文件的该项内容并未被限定。
p_filesz
该字段给出了文件镜像中该段的大小,可能为 0。
p_memsz
该字段给出了内存镜像中该段的大小,可能为 0。
p_align
可加载的程序的段的p_vaddr
以及p_offset
的大小必须是page
的整数倍。该成员给出了段在文件以及内存中的对齐方式。如果该值为0或1的话,表示不需要对齐。除此之外,p_align
应该是2的整数指数次方,并且p_vaddr与
p_offset在模
p_align`的意义下,应该相等。
0x05 节区头部表(Section Header Table)
该结构用于定位ELF文件中的每个节区的具体位置(一般放在ELF文件末尾)。
首先,ELF头中的e_shoff
项给出了从文件开头到节头表位置的字节偏移。e_shnum
告诉了我们节头表包含的项数;e_shentsize
给出了每一项的字节大小。
其次,节头表是一个数组,每个数组的元素的类型是ELF64_Shdr
,每一个元素都描述了一个节区的概要内容。
1 | typedef struct { |
一般下标中,各成员含义如下
成员 | 说明 |
---|---|
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。 |
除了一般的下标外,节头表中还有一些特殊的下标,具体参考Special Section Indexes
名称 | 值 | 含义 |
---|---|---|
SHN_UNDEF | 0 | 标志未定义的,丢失的,不相关的或者其它没有意义的节引用。例如,与节号 SHN_UNDEF 相关的 “定义” 的符号就是一个未定义符号。注:虽然 0 号索引被保留用于未定义值,节头表仍然包含索引 0 的项。也就是说,如果 ELF 头的 e_shnum 为 6,那么索引应该为 0~5。更加详细的内容在后面会说明。 |
SHN_LORESERVE | 0xff00 | 保留索引值范围的下界。 |
SHN_LOPROC | 0xff00 | 处理器相关的下界 |
SHN_HIPROC | 0xff1f | 处理器相关的上界 |
SHN_ABS | 0xfff1 | 相关引用的绝对值。例如与节号 SHN_ABS 相关的符号拥有绝对值,它们不受重定位的影响 |
SHN_COMMON | 0xfff2 | 这一节区相定义的符号是通用符号,例如 FORTRAN COMMON,C 语言中未分配的外部变量。 |
SHN_HIRESERVE | 0xffff | 保留索引值范围的上界。 |
其中,当节区头部表的下标为0时,此索引标记的是未定义的节区引用,此项信息如下
字段名称 | 取值 | 说明 |
---|---|---|
sh_name | 0 | 无名称 |
sh_type | SHT_NULL | 限制 |
sh_flags | 0 | 无标志 |
sh_addr | 0 | 无地址 |
sh_offset | 0 | 无文件偏移 |
sh_size | 0 | 无大小 |
sh_link | SHN_UNDEF | 无链接信息 |
sh_info | 0 | 无辅助信息 |
sh_addralign | 0 | 无对齐要求 |
sh_entsize | 0 | 无表项 |
如果节数大于或等于SHN_LORESERVE (0xff00)
,则e_shnum
的值为SHN_UNDEF (0)
,实际的节头表项数包含在索引为0的节头的sh_size
字段中(否则,初始项的sh_size
成员为 0)。
在某些上下文中,节头表索引被保留,例如符号表项的st_shndx
成员和ELF头的e_shnum
和e_shstrndx
成员。在这些上下文中,保留的值并不代表目标文件中的实际节。此外,在这些上下文中,转义值表示实际节索引在其他地方找到,位于更大的字段中。
部分节头表项成员的具体含义如下:
sh_name
此成员指定对应节表的名称。其值是对字符串节表内容的索引,指示出一个不以NULL
为结尾的字符串的位置
关于字符串节表可以参考String Table
sh_type
该成员对部分的内容和语义进行分类。目前由下列可选范围(其中SHT是Section Header Table的简写)
名称 | 取值 | 说明 |
---|---|---|
SHT_NULL | 0 | 该类型节区是非活动的,这种类型的节头中的其它成员取值无意义。 |
SHT_PROGBITS | 1 | 该类型节区包含程序定义的信息,它的格式和含义都由程序来决定。 |
SHT_SYMTAB | 2 | 该类型节区包含一个符号表(SYMbol TABle)。目前目标文件对每种类型的节区都只 能包含一个,不过这个限制将来可能发生变化。 一般,SHT_SYMTAB 节区提供用于链接编辑(指 ld 而言) 的符号,尽管也可用来实现动态链接。 |
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 | OX7FFFFFFF | 此值指定保留给处理器专用语义的上界( HIgh PROCessor-specific semantics )。 |
SHT_LOUSER | 0X80000000 | 此值指定保留给应用程序的索引下界。 |
SHT_HIUSER | 0X8FFFFFFF | 此值指定保留给应用程序的索引上界。 |
sh_flags
节头中sh_flags
字段的每一个比特位都可以给出其相应的标记信息,其定义了对应的节区的内容是否可以被修改、被执行等信息。如果一个标志位被设置,则该位取值为1,未定义的位都为0。目前已定义值如下,其他值保留。
名称 | 值 | 说明 |
---|---|---|
SHF_WRITE | 0x1 | 这种节包含了进程运行过程中可以被写的数据。 |
SHF_ALLOC | 0x2 | 这种节在进程运行时占用内存。对于不占用目标文件的内存镜像空间的某些控制节,该属性处于关闭状态 (off)。 |
SHF_EXECINSTR | 0x4 | 这种节包含可执行的机器指令(EXECutable INSTRuction)。 |
SHF_MASKPROC | 0xf0000000 | 所有在这个掩码中的比特位用于特定处理器语义。 |
sh_link&sh_info
当节区类型的不同的时候,sh_link
和 sh_info
也会具有不同的含义。
sh_type | sh_link | sh_info |
---|---|---|
SHT_DYNAMIC | 节区中使用的字符串表的节头索引 | 0 |
SHT_HASH | 此哈希表所使用的符号表的节头索引 | 0 |
SHT_REL/SHT_RELA | 与符号表相关的节头索引 | 重定位应用到的节的节头索引 |
SHT_SYMTAB/SHT_DYNSYM | 操作系统特定信息,Linux 中的 ELF 文件中该项指向符号表中符号所对应的字符串节区在 Section Header Table 中的偏移。 | 操作系统特定信息 |
other | SHN_UNDEF |
0 |