宏观结构 
运行视图:分为若干个程序段(Segment),一个段表示一种加载类型,包括需要加载到内存的地址和属性(是否可读, 是否可写, 是否可执行);
链接视图:分为若干个程序节(Section),表示不同作用的程序组成部分,用于链接,例如 .data, .rodata, .text;类似标签的作用;文件中的节区不能重叠;不允许一个字节存在于两个节区中的情况发生。
一般来说一个 Segment 会包含多个 Section,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Segment 1: Text Segment * .text * .rodata * .hash * .dynsym * .dynstr * .plt * .rel.got Segment 2: Data Segment * .data * .dynamic * .got * .bss 
数据类型定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 typedef  uint16_t  Elf32_Half;typedef  uint16_t  Elf64_Half;typedef  uint32_t  Elf32_Word;typedef  int32_t   Elf32_Sword;typedef  uint32_t  Elf64_Word;typedef  int32_t   Elf64_Sword;typedef  uint64_t  Elf32_Xword;typedef  int64_t   Elf32_Sxword;typedef  uint64_t  Elf64_Xword;typedef  int64_t   Elf64_Sxword;typedef  uint32_t  Elf32_Addr;typedef  uint64_t  Elf64_Addr;typedef  uint32_t  Elf32_Off;typedef  uint64_t  Elf64_Off;typedef  uint16_t  Elf32_Section;typedef  uint16_t  Elf64_Section;typedef  Elf32_Half Elf32_Versym;typedef  Elf64_Half Elf64_Versym;
魔数:[0x7f, 'E', 'L', 'F'] Phdr 大小,Phdr 个数 Shdr 大小,Shdr 个数 入口地址 e_entry 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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; typedef  struct {   unsigned  char  e_ident[EI_NIDENT];    Elf64_Half e_type;      Elf64_Half e_machine;     Elf64_Word e_version;     Elf64_Addr e_entry;     Elf64_Off e_phoff;     Elf64_Off e_shoff;     Elf64_Word e_flags;     Elf64_Half e_ehsize;     Elf64_Half e_phentsize;     Elf64_Half e_phnum;     Elf64_Half e_shentsize;     Elf64_Half e_shnum;     Elf64_Half e_shstrndx;   } Elf64_Ehdr; 
一般在文件开头紧邻 EHdr,有多个 Phdr,起始偏移量由 e_phoff 指定,数量由 e_phnum 指定;
p_vaddr 段加载的虚拟地址 p_flags 段属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 typedef  struct {   Elf32_Word p_type;      Elf32_Off p_offset;     Elf32_Addr p_vaddr;     Elf32_Addr p_paddr;     Elf32_Word p_filesz;     Elf32_Word p_memsz;     Elf32_Word p_flags;     Elf32_Word p_align;   } Elf32_Phdr; typedef  struct {   Elf64_Word p_type;      Elf64_Word p_flags;     Elf64_Off p_offset;     Elf64_Addr p_vaddr;     Elf64_Addr p_paddr;     Elf64_Xword p_filesz;     Elf64_Xword p_memsz;     Elf64_Xword p_align;   } Elf64_Phdr; 
一般在文件末尾,起始偏移量由 e_shoff 指定,数量由 e_shnum 指定;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef  struct {   Elf32_Word sh_name;     Elf32_Word sh_type;     Elf32_Word sh_flags;     Elf32_Addr sh_addr;     Elf32_Off sh_offset;     Elf32_Word sh_size;     Elf32_Word sh_link;     Elf32_Word sh_info;     Elf32_Word sh_addralign;     Elf32_Word sh_entsize;   } Elf32_Shdr; typedef  struct {   Elf64_Word sh_name;     Elf64_Word sh_type;     Elf64_Xword sh_flags;     Elf64_Addr sh_addr;     Elf64_Off sh_offset;     Elf64_Xword sh_size;     Elf64_Word sh_link;     Elf64_Word sh_info;     Elf64_Xword sh_addralign;     Elf64_Xword sh_entsize;   } Elf64_Shdr; 
实例 EHdr PHdr 1 PHdr 2 PHdr … Segment: PT_PHDR (self) Segment: PT_INTERP---- .interp ---- "/lib64/ld-linux-x86-64.so.2" Segment: PT_NOTE r–---- .note.gnu.property ---- ---- .note.gnu.build-id ---- ---- .note.ABI-tag ----  Segment: PT_GNU_HASH Segment: Symbol Table Segment: PT_LOAD r-x---- .init ---- ---- .plt ---- ---- .plt.got ---- ---- .plt.sec ---- ---- .text ---- ---- .fini ----  Segment: PT_LOAD r–---- .rodata ---- ---- .eh_frame_hdr ---- ---- .eh_frame ----  Segment: PT_LOAD rw- Segment: PT_GNU_RELRO rw----- .init_array ---- ---- .fini_array ----  SHdr 1: SHdr …n– Segment: PT_DYNAMIC rw- stru_22A38---- .got ---- ---- .data ---- ---- .bss ----  Segment: Externs Segment: String Table 典型 Segment PT_LOAD 普通的需要加载的段
PT_INTERP 包含一个 C 字符串,指向动态链接器的路径,
当创建一个可执行文件时,如果依赖其它的动态链接库,那么链接编辑器会在可执行文件的程序头中加入一个 PT_INTERP 项,告诉系统这里需要使用动态链接器,一般链接器为 ld。
PT_NOTE 附加信息,例如 ABI 版本,构建 ID 等
PT_PHDR 包含一个程序头表的副本,用于动态链接器的加载
典型 Section Section 类型表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #define  SHT_NULL   0   #define  SHT_PROGBITS   1   #define  SHT_SYMTAB   2   #define  SHT_STRTAB   3   #define  SHT_RELA   4   #define  SHT_HASH   5   #define  SHT_DYNAMIC   6   #define  SHT_NOTE   7   #define  SHT_NOBITS   8   #define  SHT_REL    9   #define  SHT_SHLIB   10   #define  SHT_DYNSYM   11   #define  SHT_INIT_ARRAY   14   #define  SHT_FINI_ARRAY   15   #define  SHT_PREINIT_ARRAY 16   #define  SHT_GROUP   17   #define  SHT_SYMTAB_SHNDX  18   #define  SHT_RELR   19             #define  SHT_NUM    20   #define  SHT_LOOS   0x60000000  #define  SHT_GNU_ATTRIBUTES 0x6ffffff5  #define  SHT_GNU_HASH   0x6ffffff6  #define  SHT_GNU_LIBLIST   0x6ffffff7  #define  SHT_CHECKSUM   0x6ffffff8  #define  SHT_LOSUNW   0x6ffffffa  #define  SHT_SUNW_move   0x6ffffffa #define  SHT_SUNW_COMDAT   0x6ffffffb #define  SHT_SUNW_syminfo  0x6ffffffc #define  SHT_GNU_verdef   0x6ffffffd  #define  SHT_GNU_verneed   0x6ffffffe  #define  SHT_GNU_versym   0x6fffffff  #define  SHT_HISUNW   0x6fffffff  #define  SHT_HIOS   0x6fffffff  #define  SHT_LOPROC   0x70000000  #define  SHT_HIPROC   0x7fffffff  #define  SHT_LOUSER   0x80000000  #define  SHT_HIUSER   0x8fffffff  
.shstrtab 节名字符串表字符串表,存储 ELF 结构中所有的 Section 的名字。类型是 SHT_STRTAB;由 EHdr 中的 e_shstrndx 确定本节的位置;
.dyntab 符号名字符串表类型 SHT_STRTAB; 存储程序中的符号名,包含变量名、函数名等;
SHT_SYMTAB 符号表 包含
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 typedef  struct {   Elf32_Word st_name;     Elf32_Addr st_value;     Elf32_Word st_size;     unsigned  char  st_info;     unsigned  char  st_other;     Elf32_Section st_shndx;   } Elf32_Sym; typedef  struct {   Elf64_Word st_name;     unsigned  char  st_info;     unsigned  char  st_other;     Elf64_Section st_shndx;     Elf64_Addr st_value;     Elf64_Xword st_size;   } Elf64_Sym; 
.dynamic 动态链接节