1. ELF header结构体
主要定义了文件的类型,程序头表位置,大小和个数,节头表位置,大小和个数
typedef struct {
unsigned char e_ident[EI_NIDENT];/*ELF Majic*/
uint16_t e_type;/*文件类型(ET_REL,ET_EXEC,ET_DYN)*/
uint16_t e_machine;/*CPU体系(ARM ,X86,MIPS),表示程序在哪种cpu执行*/
uint32_t e_version;
ElfN_Addr e_entry;/* 程序的入口点*/
ElfN_Off e_phoff;/*程序头表的offset */
ElfN_Off e_shoff;/*节头表的offset */
uint32_t e_flags;/*目前未用到 */
uint16_t e_ehsize;/*文件头的大小 */
uint16_t e_phentsize;/*一个程序头的大小 */
uint16_t e_phnum;/*程序头个数*/
uint16_t e_shentsize;/*一个节表头的大小 */
uint16_t e_shnum; /*节表头的个数 */
uint16_t e_shstrndx;/*字符串节表在节表头table中的index */
} ElfN_Ehdr;
2.常见的ELF程序类型
ET_REL :可重定向文件
ET_EXEC:可执行文件
ET_DYN : 共享文件
3.程序头(Program header)
可执行文件或者共享文件的program header table描述了系统执行一个程序所需要的段(segment)或者其它信息。
目标文件的一个段(segment)包含一个或者多个section。Program header只对可执行文件和共享目标文件有意义,
对于程序的链接没有任何意义。一个program header table包含多个program header,定义如下:
typedef struct {
uint32_t p_type;/*segment类型(PT_LOAD,PT_DYNAMIC,PT_GNU_STACK) */
uint32_t p_flags;/*segment 属性PF_X,PF_R,PF_W*/
Elf64_Off p_offset;/*这个segment相对文件的偏移 */
Elf64_Addr p_vaddr;/*这个segment在运行时的虚拟地址 */
Elf64_Addr p_paddr;/* 物理地址,暂时没用*/
uint64_t p_filesz;/*这个segment的大小 */
uint64_t p_memsz;/*这个segment加载到内存后的大小 */
uint64_t p_align;/*对齐相关*/
} Elf64_Phdr;
4.segment类型和flags说明
PT_LOAD :这个段是可装载的(程序运行时,把这个segment加载到内存)
PT_DYNAMIC:动态链接相关的segment
PT_INTERP :制定动态链接库的全路径
PF_X: segment具有执行权限
PF_R: segment是只读的
PF_W: segment是可写的.
代码段具有:PF_X, PF_W
数据段具有:PF_X,PF_W,PF_R
5.readelf常用指令
readelf -h binary_file /*显示文件头信息 */
readelf -l binary_file /*显示程序头信息 */
readelf -S binary_file /*显示段表头信息 */
readelf -s binary_file /*显示.symtab内容 */
readelf -n binary_file /*显示文件的Note信息 */
readelf -x section_name /*以16进制显示段表内容 */
readelf -p section_name /*以字符串显示段表内容 */
6. objdump常用指令
objdump -d binary_file /*把代码段反汇编 */
objdump -d -Mintel binary_file /*以intel汇编格式来反汇编代码,默认是AT&T格式 */
7.段表(section header table)
目标文件的section header table可以定位所有的section,段表实际上是一个数组
typedef struct {
uint32_t sh_name;/* section name在string section 中的Index*/
uint32_t sh_type;/*section类型,常见类型SHT_PROGBITS,SHT_REL,SHT_SYMTAB,SHT_STRTAB,SHT_DYNSYM */
uint64_t sh_flags;/*section访问权限,SHF_WRITE,SHF_ALLOC,SHF_EXECINSTR */
Elf64_Addr sh_addr;/*section在内存中的地址. */
Elf64_Off sh_offset;/*section在文件中的偏移 */
uint64_t sh_size;/*section的大小 */
uint32_t sh_link;/*section依赖其他section的index,比如.symtab依赖.strtab,sh_link的值就是.strtab的index */
uint32_t sh_info;/*额外信息,.symtab会用到 */
uint64_t sh_addralign;/*对齐相关 */
uint64_t sh_entsize;/*有些section包含额外的信息 */
} Elf64_Shdr;
8. section 的sh_name解析
1.先根据file header找到section header table的位置
2.根据file header中的e_shstrndx,在段表中找到字符串section ".strtab"
3.根据sh_name的值从".strtab"找到对应的字符串.从而得出section name
9. 常见的section
可以用readelf -S binary_file查看所有的段
.bss :为初始化的全局变量
.text :代码段
.data :数据段
.rodata:只读数据段
.strtab :包含所有符号的名字
.shstrtab:包含所有section name
.symtab :包含文件所有的符号表(函数名,文件名,全局变量名等等)
.rel/.rela: 可重定向相关
.dymtab/.dymstr :动态链接相关
10. symbol/section/segment的关系
symbol被定义在各种section中。而section最终又被包含到segment中.
一个segment可以包含多个section