ELF 是Executable and Linking Format的缩写,即可执行和可链接的格式,是Unix/Linux系统ABI (Application Binary Interface)规范的一部分。Unix/Linux下的可执行二进制文件、目标代码文件、共享库文件和core dump文件都属于ELF文件。
ELF格式视图
ELF文件有链接视图和执行视图,两种视图形式:
链接视图:
静态链接器(即编译后参与生成最终ELF过程的链接器,如ld )会以链接视图解析ELF。编译时生成的 .o(目标文件)以及链接后的 .so (共享库)均可通过链接视图解析,链接视图可以没有段表(如目标文件不会有段表)。
执行视图:
动态链接器(即加载器,如x86架构 linux下的 /lib/ld-linux.so.2或者安卓系统下的 /system/linker均为动态链接器)会以执行视图解析ELF并动态链接,执行视图可以没有节表。

左边是ELF的链接视图,可以理解为是目标代码文件的内容布局。右边是ELF的执行视图,可以理解为可执行文件的内容布局。
对于两种视图来说,ELF Header是两种说共有的。
同时,在两个视图的区别上,对于链接视图来说section是主要特征,同时对于Section Header Table 在链接视图中也是必要的,但Program Header Table来说是非必要的。但对于执行视图来说Segment是主要特征,同时对于Program Header Table 在链接视图中也是必要的,但Section Header Table是非必要的。
segments与sections区分与联系
segments与sections区别在于:
- 节(section)
- 在汇编中经常提到的
.text,.bss,.data这些都属于section层面上的。 .text:保存程序代码。.data:保存已经初始化的全局变量和局部静态变量.bss: 保存未初始化的全局变量和局部静态变量- 目标代码文件中的
section和section header table中的条目是一一对应的。section的信息用于链接器对代码重定位。
- 在汇编中经常提到的
- 段(segment)
- 我们平常说的代码段与数据段这些都是是
segment层面上的。 - 目标代码中的
section会被链接器组织到可执行文件的各个segment中。.text section的内容会组装到代码段中,.data,.bss等节的内容会包含在数据段中。 - 而文件载入内存执行时,是以
segment组织的,每个segment对应ELF文件中program header table中的一个条目,用来建立可执行文件的进程映像。
- 我们平常说的代码段与数据段这些都是是
段(segments)与节(sections)同时又是是包含的关系,一个segment包含若干个section。当ELF文件被操作系统加载到内存中后(加载到内存中也就是说这个elf要运行),系统会将多个具有相同权限(flg值)section合并成一个segment(优化空间利用),减少内存碎片。
ELF Header 分析
之前说,在ELF文件中无论说基于执行视图还是链接视图,ELF Header是都有的结构。在elf文件中
ELF header的定义可以在Linux系统的 /usr/include目录下elf.h 文件中找到。(用vs 装上c/c++相关插件后,可以直接定位到)
在32位与64位系统下,ELF header的定义是不同的:
Elf32_Ehdr是32位 ELF header的结构体。定义如下:
1 | typedef struct |
Elf64_Ehdr是64位ELF header的结构体。定义如下:
1 | typedef struct |
Elf64_Addr 和 Elf64_Off 都是64位无符号整数。而Elf32_Addr 和 Elf32_Off是32位无符号整数。这导致ELF header的所占的字节数不同。32位的ELF header占52个字节,64位的ELF header占64个字节。

e_ident
e_ident占16个字节。前四个字节被称作ELF的Magic Number。
1 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ |

如上图,前4个字节是ELF的Magic Number,固定为7f 45 4c 46,也对应着字符串\177ELF
第5个字节为EI_CLASS代表当前ELF文件是32位还是64位的。值为 ELFCLASS32(0x1)表32位,数值为 ELFCLASS64 (0x2)表64位。
第6个字节为EI_DATA了数据的编码方式,即我们通常说的little endian或是big endian。值 ELFDATA2LSB 表little endian,即为 小端排序,低位字节在前,或者直接说低位字节在低位地址,比如0x7f454c46,存储顺序就是46 4c 45 7f 。 值 ELFDATA2MSB表big endian就是大端排序,高位字节在前,直接说就是高位字节在低位地址,比如0x7f454c46,在文件中的存储顺序是7f 45 4c 46。
第7个字节为EI_VERSION指明了ELF header的版本号,目前值都是EV_CURRENT(1)。
第8个字节为EI_OSABI表操作系统ABI标识,现在默认为0,
第9-16个字节,都填充为0。
e_type
e_type 代表文件类。
1 | Elf32_Half e_type; /* Object file type */ |
当其值为ET_REL(1)表可重定位文 件(如目标文件)
当其值为ET_EXEC(2)表可执行文件(可直接执行的文件)
当其值为ET_DYN(3)表共享目标文件(如SO库)
当其值为ET_CORE(4)表Core文件(吐核文件)
e_machine
e_machine为架构信息。
1 | Elf32_Half e_machine; /* Architecture */ |
当值为EM_X86_64(62)表x86-64架构,
e_verison
e_version为文件版本,目前常见的ELF 文件版本均为EV_CURRENT(1)。
1 | Elf32_Word e_version; /* Object file version */ |
e_entry
e_entry表入口虚拟地址(RVA)。即_start函数所在的地方(地址)。
1 | Elf32_Addr e_entry; /* Entry point virtual address */ |
e_phoff
e_phoff为程序头表(段表)的偏移,程序头表离启始位置的值。
1 | Elf32_Off e_phoff; /* Program header table file offset */ |
e_shoff
e_shoff为节头表的偏移,节头表离启始位置的值。
1 | Elf32_Off e_shoff; /* Section header table file offset */ |
e_flags
处理器特定的标志,一般为0。
1 | Elf32_Word e_flags; /* Processor-specific flags */ |
e_ehsize
Elf_Header的大小(字节),64位则为64,如果是32位则为52。
1 | Elf32_Half e_ehsize; /* ELF header size in bytes */ |
e_phentsize
·e_phentsize表程序头表/段表(Program Header)的大小(字节)
1 | Elf32_Half e_phentsize; /* Program header table entry size */ |
e_phnum
e_phnum表段的数量。
1 | Elf32_Half e_phnum; /* Program header table entry count */ |
e_shentsize
e_shentsize表节头(Section Header)的大小(字节)。当ELF文件被操作系统加载到内存中后(加载到内存中也就是说这个elf要运行),系统会将多个具有相同权限(flg值)section合并成一个segment(优化空间利用),在这个过程中section的数量可能会发生改变。
1 | Elf32_Half e_shentsize; /* Section header table entry size */ |
e_shnum
e_shnum表节头数量
1 | Elf32_Half e_shnum; /* Section header table entry count */ |
e_shstrndx
e_shstrndx表节字符串表的节索引。
1 | Elf32_Half e_shstrndx; /* Section header string table index */ |
代码解析Elf头
结合上面知识,我们可以用c语言,来解析Elf 头解析。效果如下:

原代码如下
1 |
|
参考链接
https://ch3nye.top/Linux%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%88%86%E6%9E%90%E7%AC%94%E8%AE%B0(ELF)/
https://copyright1999.github.io/2021/10/10/%E8%A7%A3%E6%9E%90ELF%E6%96%87%E4%BB%B6-%E4%B8%80/