程序员的自我修养 | 目标文件
第三章-目标文件
编译器编译源代码后生成的文件叫做目标文件,格式上来说,它是已经编译后的可执行文件格式,只是还没有经过链接过程。
总结
在Linux中目标文件是ELF格式的,其中,除了文件头还有很多段,比如数据段、代码段
目标文件的格式
目标文件在Linux中是ELF格式(Executable Linkable Format),除此之外还有很多ELF格式的文件
可重定位文件
- Linux的 .o
- 这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件
- 静态链接库
可执行文件
- /bin/bash 下的文件,可以直接执行
共享目标文件
- Linux 的 .so
核心转储文件
目标文件的内容
有不同的段
文件头
- 描述整个文件的属性
- 是否可执行
- 是静态链接还是动态链接
- 入口地址
- 目标硬件
- 目标操作系统
- 段表:文件中各个段的位置
- 描述整个文件的属性
代码段(.code .text)
- 编译后执行语句都编译成机器代码保存在.text段
- 属于指令区域,只读
数据段 (.data)
- 已经初始化的全局变量和局部静态变量
- 属于数据区域
bss段
- 未初始化的全局变量和局部静态变量
- 属于数据区域
- 仅仅记录所需大小
但事实上上述只是简化版的ELF结构,真正的结构如下图
- 数据和指令会被映射到两个虚拟存储区域
- 数据可读可写,指令区域只读
- CPU缓存是数据缓存和指令缓存分离,有利于提高程序的局部性
- 如果同时运行多个改程序,由于指令都是一样的,内存中只需要保存一份该程序的指令副本
ELF文件的文件头
段表
保存ELF文件中各种段的基本属性的结构。描述了各个段的段名、段长度、在文件中的偏移、读写权限等
段表的结构是一个数组里面每个元素是一个结构体,数组的长度就是不同的段的个数。如图上图所示,这个目标文件中一共有11个段,其中第一个元素是无效的段描述符,因此一共有10个有效的段。每一个结构体长下图这样
重定位表 .rel.text
链接器在处理目标文件时,需要对目标文件中某些部位进行重定位,即代码段和数据段中那些对绝对地址的引用的位置。这些重定位信息都记录在ELF文件的重定位表里面。对于每个需要重定位的代码段和数据段,都会有一个相应的重定位表
比如.rel.text表示对.text段的重定位表, .rel.data就是对.data段的重定位表
字符串表
.strtab
或 .shstrtab
表示字符串表和段表字符串表
字符串表用来保存普通的字符串,比如符号的名字
段表字符串表用来保存段名字
符号表
记录了目标文件中用到的所有符号,有符号名和符号值,符号值就是地址。
- 定义在本目标文件中的全局符号
- 在本目标文件中引用的全局符号,但没有定义在本目标文件中(外部符号)
- printf
上述两个最重要,因为链接过程就是要把全局符号黏在一起,下面三个对于其他目标文件是不可见的,在链接过程中无关紧要
- 段名
- 局部符号:局部变量的变量名
- 对链接过程没有作用
- 行号信息
一个具体的符号表例子