一,简介
一般gcc编译生成的文件是可执行文件,一般我们称为目标文件,目标文件在linux上是一个ELF(Executable and Linkable Format)文件。一个文件是否ELF文件可以通过file命令查看,包括是否32bit/64bit,以及类型。
ELF文件由四种类型,可重定位文件(Relocatable)、可执行文件(Executable)、共享文件库(shared Object)、核心转储文件(core dump).
编译阶段生成的*.o文件是可重定位文件,链接后生成的是可执行文件或者共享库。
目标文件内容肯定是机器指令、数据、链接时需要的信息(如符号表),这些数据以section的形式存储。
二、ELF文件结构
ELF Header:开头即ELF字符,7f 45 4c,还有文件类型、大小以及加载后的程序执行的入口点信息等,readelf-h读取
Progrem Header table:程序头表,readelf -l 读取,可执行文件的数据在进程虚拟地址空间组织方式信息,以及文件包含的段数据、各段位置和用途
各种section:section一般称为节
Section header table:各个section的信息,如名称、长度、偏移、读写权限等,可通过readelf -S读取
String tables
Symbol tables
Section Header table
Code指令:存在.code或者.text;
已初始化的全局变量和局部变量:放在.data
未初始化的静态变量:放在.bss段,bss的意思是Block Started by Symbol
常量:放在.rodata,即只读数据
注释信息section: 放在.comment
堆栈提示段:放在.not.GNU-stack
动态链接信息:.dynamic
额外编译器信息:.note,如公司名称等
动态链接的跳转表和全局入口表:.plt和.got
字符串表:.strtab,用于存储ELF文件中符号表用到的字符串,以数组组织起来,第一个字节为0,字符串之间以\0分割,
符号表:.symtab,其本质是一个Elf32_Sym(32位机)的结构体,通过readelf -s读取,也可以通过nm工具读出程序定义和使用的符号列表,符号即code中定义的一些变量或者方法的信息,例如其定义位置、占用大小、其值。
自定义section:
可以通过objcopy工具自定义section
也可以在code中指定数据存储的section:__attribute__((section”name”)) int variable,即将变量variable存储在ELF文件的namesection.
可以通过objdump -h file读取部分section的摘要,
readelf -S file 读取全部section的摘要,即Section header table, 还有readelf -h file,可以读取elf文件头部信息,还有命令size file,显示code、data和bss三个段的长度及他门的和。
Code和数据分别存储在不同section,大致有三个优点:
1, 加载到内存后,方便管理段的属性,如code值read 和excute,数据是write和read;
2, 方便cache,方便分别将指令和数据分别加载到相应cache,提供cache命中率;
3, 方便管理内存中的可执行指令,方便复用,因为对于多个app来说,可能由重复的可执行文件,方便对同样的code映射到各个进程,提供复用率,而数据却是各app私有的。
PS:以上所属的命令中的file需替换为要查看的目标文件