1. 空间与地址分配
对与链接器来说,整个链接过程中,它就是将几个输入目标文件加工后合并成一个输出文件。
1.1 按序叠加
很容易想到的是把所有目标文件的各个段像叠罗汉一样,叠加在一起形成最终的可执行文件。这么做会导致可执行文件非常非常大,因为每个段都需要有一定的地址和空间对齐要求,比如对于x86的硬件来说,段的装载地址和空间的对齐单位是页,也就是4096字节。那就是说如果一个段的长度只有一个字节,它在内存中也要占用4096字节。这样会找出内存空间大量的内部碎片,所以这不是一个好方案。
1.2 相似段合并
一个更实际的方法是将相同性质的段合并到一起,比如将所有输入文件的".text" 合并到输出文件的".text"段,接着是".data"段,".bss"段等
- 1.空间与地址分配 扫描所有的输入目标文件,并且获得它们的各个段的长度,属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个全局符号表。这一步中,链接器将能够获得所有输入目标文件的段长度,并且将他们合并,计算出输出文件中各个段合并后的长度和位置,并建立映射关系。
- 2.符号解析与重定位 使用上面第一步中搜集到的所有信息,读取输入文件中段的数据,重定位信息,并且进行富豪解析与重定位,调整代码中的地址等。事实上这一步是链接过程的核心,特别是重定位过程。
2. 静态库链接
程序如何使用操作系统提供的api。在一般情况下,一种语言的开发坏境往往会附带有语言库。这些库就是对操作系统的API的包装,比如我们经典的C语言版“Hello world"程序,他使用C语言标准库的 “printf” 函数来输出一个字符串,最终这个 “printf” 函数会调用操作系统提供的API。
其实一个静态库可以简单的看成一组目标文件的集合,即很多目标文件经过压缩打包后形成的一个文件。比如Linux 中常用的C语言静态库libc位于/usr/lib/libc.a,它属于glibc项目的一部分;像Windows这样的平台上,最常使用的C语言库是有集成开发环境附带的运行库,这些库一般都有编译器厂商提供。
一个.a结尾的静态库文件,其实使用 “ar” 压缩程序将一些目标文件压缩在一起,并且对齐进行编号和索引,以便于查找和检索,就形成了libc.a这个静态库。可以用以下命令查看静态库里面包含了哪些目标文件:
ar -t libc.a