ELF文件类型
ELF文件主要分为三种类型:
- 可重定位文件(Relocatable File)包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。
- 可执行文件(Executable File) 包含适合于执行的一个程序,此文件规定了exec() 如何创建一个程序的进程映像。
- 共享目标文件(Shared Object File) 包含可在两种上下文中链接的代码和数据。首先链接编辑器可以将它和其它可重定位文件和共享目标文件一起处理,生成另外一个目标文件。其次,动态链接器(Dynamic Linker)可能将它与某个可执行文件以及其它共享目标一起组合,创建进程映像。
ELF文件的数据表示
ELF文件头结构及相关常数被定义在”/usr/include/elf.h”里。ELF目标文件中的所有数据结构都遵从自然大小和对齐规则。如果必要,数据结构可以包含显式的补齐,例如为了确保4字节对象按4字节边界对齐。数据对齐同样适用于文件内部。下面为ELF中常用的数据格式:
| 名称 | 大小 | 对齐 | 描述 |
| Elf32_Addr | 4 | 4 | 无符号程序地址 |
| Elf32_Half | 2 | 2 | 无符号短整型 |
| Elf32_Off | 4 | 4 | 无符号偏移地址 |
| Elf32_Sword | 4 | 4 | 有符号整型 |
| Elf32_Word | 4 | 4 | 有符号整型 |
ELF除了32位版还有64位版本,数据类型的名称和大小也相应地变化(Elf64_Addr…)。
链接视图和执行视图
目标文件既要参与程序链接又要参与程序执行。出于方便性和效率考虑,目标文件格式提供了两种并行视图,分别反映了这些活动的不同需求。

这两个视图并不冲突,在执行视图中的”Segment”是由链接视图中的多个权限和性质相仿的”Section”组成的。
文件开始处是一个ELF头部(ELF Header),用来描述整个文件的组织。ELF的文件头定义了ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口和长度、段表的位置和长度及段的数量等信息。
程序头部表(Program Header Table),主要用来保存”Segment”的信息。可重位文件由于不需要被装载,因此没有这个表,而ELF可执行文件和共享库文件则有。
段表(Section Header Table),保存各个段的基本属性,包括每个段的段名、段的长度、在文件中的偏移、读写权限、段的链接信息等等。
ELF Header 部分
下面是使用readelf来查看一个ELF文件的文件头信息:
ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 264 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 11 Section header string table index: 8
文件头对应一个Elf32_Ehdr的结构如下(如上面的输出信息是一一对应的):
#define EI_NIDENT 16
typedef struct{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
}Elf32_Ehdr;
ELF Header中各个字段说明如下:
| 成员 | 说明 | |||||||||||||||||||||||||||
| e_ident | ELF文件标识。
|
|||||||||||||||||||||||||||
| e_type | 目标文件类型:
ET_LOPROC 和 ET_HIPROC 之间的取值用来标识与处理器相关的文件格式。 |
|||||||||||||||||||||||||||
| e_machine | ELF文件的CPU平台属性:
其它值都是保留的。特定处理器的ELF名称会使用机器名来进行区分。 |
|||||||||||||||||||||||||||
| e_version | ELF文件版本号,一般为常数1
|
|||||||||||||||||||||||||||
| e_entry | 程序入口的虚拟地址,操作系统在加载完该程序后从这个地址开始执行进程的指令。可重定位文件一般没有入口地址,则这个值为0。 | |||||||||||||||||||||||||||
| e_phofff | 程序头表(Program Header Table)在文件中的偏移量(以字节计算)。如果没有程序头表,可以为0。 | |||||||||||||||||||||||||||
| e_shoff | 段表在文件中的偏移量(以字节计算) | |||||||||||||||||||||||||||
| e_flags | ELF标志位,用来标识一些ELF文件平台相关的属性。相关常量的格式一般为EF_machine_flag,machine为平台,flag为标志。 | |||||||||||||||||||||||||||
| e_ehsize | ELF文件头本身的大小。 | |||||||||||||||||||||||||||
| e_phentsize | 程序头表的表项大小。 | |||||||||||||||||||||||||||
| e_phnum | 程序头表的表项数目,可以为0。 | |||||||||||||||||||||||||||
| e_shentsize | 段表的表项大小。 | |||||||||||||||||||||||||||
| e_shnum | 段表的表项数目,可以为0。 | |||||||||||||||||||||||||||
| e_shstrndx | 段表字符串所在的段在段表中的下标。也就是段表字符串表的位置,可以从段表中用索引获取。 |
本来很有冲动想将其它的一些段的格式说明也记录下来,但发现这样太费时间了,而且wp的编辑器有点让我抓狂。其实主要也就参考了《程序员的自我修养》这本书和《ELF文件格式分析》这份PDF文件。