空间与地址分配
链接器如何将多个目标文件的各个段合并到输出文件。地址和空间指的是程序装载后的虚拟地址中的虚拟地址空间分配。
按序叠加
相似段合并
两步链接方法
链接前后的程序中所使用的的地址是程序在进程中的虚拟地址
第一步 空间域地址分配
扫描所有目标文件,获取它们的信息,将所有目标文件的符号表中的定义和引用放到全局符号表中,计算输出文件中各个段合并后的长度与位置,建立映射关系
第二步 符号解析域重定位(核心)
用第一步中收集的信息,读取输入文件中段的数据,重定位信息,进行符号解析域重定位,调整代码中的地址
ABI & API
- API(Application Programming Interface)
源代码级别的接口 - ABI(Application Binary Interface)
二进制层面的接口,兼容程度比 API 更严格
链接过程控制
通常我们使用链接器提供的默认链接规则对目标文件进行链接。但对于一些特殊要求的程序,比如操作系统内核、BIOS或一些在没有操作系统的情况下运行的程序(如引导程序 Boot Loader或者嵌入式系统的程序),以及另外的些须要特殊的链接过程的程序,如一些内核驱动程序等,它们往往受限于一些特殊的条件,如须要指定输出文件的各个段虚拟地址、段的名称、段存放的顺序等,因为这些特殊的环境,特别是某些硬件条件的限制,往往对程序的各个段的地址有着特殊的要求。
链接器一般提供多种控制整个链接过程的方法,产生用户需要的文件
- 使用命令行指定参数
- 将链接指令存放在目标文件里(编译器使用此方式)
- 使用链接控制脚本(灵活、强大)
BFD 库
通过一种统一的接口来处理不同的目标文件格式。
- 是 binutils 项目的一个子项目
- 把目标文件抽象成一个统一的模型
- GCC、链接器 ld、调试器 GBD、binutils 的其他工具都通过 BFD 库处理目标文件
- 支持 25 中处理器平台,50 种目标文件格式
其他
符号未定义
常见的是链接时缺少某个库,或输入目标文件路径不正确或符号的声明与定义不一样。重定位的过程中,每个重定位的入口都是对符号的引用,那么当链接器须要对某个符号的引用进行重定位时,它就要确定这个符号的目标地址。这时候链接器就会去查找由所有输入目标文件的符号表组成的全局符号表,找到相应的符号后进行重定位。
为什么静态运行库里一个目标文件只包含一个函数
链接器在链接静态库的时候是以目标文件为单位的。如果很多函数都放在一个目标文件中,多没用的函数会被一起链接进了输出结果中。由于运行库有成百上千个函数,数量非常庞大,每个函数独立地放在一个目标文件中可以尽量减少空间的浪费。