一、ELF文件类型
- ET_NONE:未知类型。
- ET_REL:重定位文件。通常是还未被链接到可执行程序中的一段位置独立的代码,例如linux中的.o格式的文件。
- ET_EXEC:可执行文件。
- ET_DYN:共享目标文件。ELF类型为dynamic,意味着该文件被标记为了一个动态的可连接的目标文件,也称为共享库,这类共享库会在程序运行时被装载并链接到程序的进程镜像中。
- ET_CORE:核心文件,在程序崩溃或进程传递了一个SIGSEGV信号(分段违规)时,会在核心文件中记录整个进程的镜像信息。
二、ELF文件结构
通过上图可以看到,ELF文件的开始是ELF文件头,接着是程序头表(program header table),以及节头表(section header table)。
1. 段和节的区别
段是程序执行的必要组成部分,在每一个段中,会有着代码或者数据被划分为不同的节。节头表是对这些节的位置和大小的描述,主要用于链接和调试。节头对于程序的执行来说不是必需的,没有节头表,程序仍可以正常执行,因为节头表没有对程序的内存布局进行描述,对程序内存布局的描述是程序头表的任务。节头是对程序头的补充。
如果二进制文件中缺少节头,并不意味着节不存在,只是没有办法通过节头来引用节,对于调试器或者反编译器程序来说,只是可以参考的信息变少了而已。
2. ELF文件头内容
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* 文件类型 */
Elf32_Half e_machine; /* CPU平台属性 */
Elf32_Word e_version; /* ELF版本号,一般为常数1 */
Elf32_Addr e_entry; /* ELF程序的入口虚拟地址,可重定位文件一般没有入口地址,为0 */
Elf32_Off e_phoff; /* 程序头表在文件中的偏移 */
Elf32_Off e_shoff; /* 节头表在文件中偏移 */
Elf32_Word e_flags; /* ELF标志位 */
Elf32_Half e_ehsize; /* ELF文件头本身的大小 */
Elf32_Half e_phentsize; /* 程序头描述符的大小 */
Elf32_Half e_phnum; /* 程序头描述符的数量,多少个段 */
Elf32_Half e_shentsize; /* 节表描述符的大小 */
Elf32_Half e_shnum; /* 节表描述符的数量,多少个节 */
Elf32_Half e_shstrndx; /* 节表字符串表所在节的下标,即存储节名字符串的字符串表所在节在节表中的下标 */
} Elf32_Ehdr;
3. 段头
typedef struct
{
Elf32_Word p_type; /* 段的类型,我们基本上只关注PT_LOAD类型的,当然还有其他类型例如DYNAMIC等 */
Elf32_Off p_offset; /* 段在文件中的偏移 */
Elf32_Addr p_vaddr; /* 段在进程虚拟地址空间的起始位置 */
Elf32_Addr p_paddr; /* 段的物理装载地址,一般情况下与p_vaddr相同 */
Elf32_Word p_filesz