ELF文件包含文件頭(ELF Header)、程序頭表(Program Head Table)、節(Sections)或段(Segments)、節頭表(Section Header Table)四個部分。ELF文件提供了兩種視圖,分別是鏈接視圖和執行視圖。其中,節是鏈接視圖的基本單位,在文件進行鏈接操作時使用;段是執行視圖的基本單位,在文件運行時使用。一個段可包含一個或多個節,段和節在文件中沒有固定的順序。以下是elf.h中相關結構體的定義。
1. 文件頭結構體(ELF Header)
文件頭描述整個文件的組織結構。使用Elf32_Ehdr和Elf64_Ehdr描述。
#define EI_NIDENT (16) typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr;
typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Architecture */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size in bytes */ Elf64_Half e_phentsize; /* Program header table entry size */ Elf64_Half e_phnum; /* Program header table entry count */ Elf64_Half e_shentsize; /* Section header table entry size */ Elf64_Half e_shnum; /* Section header table entry count */ Elf64_Half e_shstrndx; /* Section header string table index */ } Elf64_Ehdr;
以上,
e_ident 字段前四位為文件標識,一般為“\x7fELF”,通過這四位,可以查看該文件是否為ELF文件。
e_type 字段表示ELF文件的類型,如ET_REL表示可重定位文件,ET_EXEC表示可執行文件,ET_DYN表示共享目標文件。
e_phoff 字段表示程序頭表在文件中的偏移,可根據該字段找到程序頭表的起始地址。
e_shoff 字段表示節頭表在文件中的偏移,可根據該字段找到節頭表的起始地址。
e_shstrndx 字段表示字符串表在節頭表中的索引,一般為節頭表中的最后一個,即e_shstrndx=e_shnum-1。
2. 程序頭結構體(Program Header)
程序頭表描述文件中各種段的信息。每個程序頭的結構體定義如下,使用Elf32_Phdr和Elf64_Phdr描述。
typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Word p_align; /* Segment alignment */ }Elf32_Phdr;
typedef struct { Elf64_Word p_type; /* Segment type */ Elf64_Word p_flags; /* Segment flags */ Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ Elf64_Xword p_filesz; /* Segment size in file */ Elf64_Xword p_memsz; /* Segment size in memory */ Elf64_Xword p_align; /* Segment alignment */ }Elf64_Phdr;
以上,
p_type 字段表示該段的類型,如果值為PT_LOAD,則表示該段是一個可加載到內存中的段,且必須滿足 p_memsz ≥ p_filesz ,多出的字節清零,否則該段的內容不能完全加載。在程序頭表中,所有PT_LOAD類型的程序頭都按照p_vaddr的值升序排列。
3. 節頭結構體(Section Header)
節頭表描述文件中各種節的信息。每個節頭的結構體定義如下,使用Elf32_Shdr和Elf64_Shdr描述。
typedef struct { Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */ }Elf32_Shdr;
typedef struct { Elf64_Word sh_name; /* Section name (string tbl index) */ Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section flags */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ Elf64_Xword sh_size; /* Section size in bytes */ Elf64_Word sh_link; /* Link to another section */ Elf64_Word sh_info; /* Additional section information */ Elf64_Xword sh_addralign; /* Section alignment */ Elf64_Xword sh_entsize; /* Entry size if section holds table */ }Elf64_Shdr;
以上,
sh_name 字段指出節的名字索引,節名字符串以'\0'結尾,統一存儲在字符串表中,然后該字段的值就表示對應節名字符串在字符串表中的索引。
4. 字符串表
字符串表存儲ELF文件中的節名、符號名等字符串,下面是一個示例,來說明字符串表的存儲方式。
假設字符串表如下所示:

則可以理解為:

如示例所示,字符串表索引可以引用節中的任何字節。字符串可以出現多次(11,16);可能存在對子字符串的引用(7,11);一個字符串可能被引用多次;也允許未引用的字符串(索引為22的"xx"字符串)。
下面是從字符串表中獲取節名字符串的偽代碼示例:
//The target is to get a section's name //1. get sh_name index = section_head_table[i]->sh_name; //2. find string_table string_table = section_head_table[e_shstrndx]->sh_offset; //3. get name name = string_table + index;
補充一個PDF文件鏈接:Tool Interface Standard (TIS)Executable and Linking Format (ELF) Specification [Version 1.2](全方位帶你了解ELF文件結構)
參考資料
1. ELF文件格式解析
2. ELF文件格式分析(ELF文件頭)
3. ELF文件-段和程序頭
4. ELF文件-節和節頭
5. 字符串表
