空间与地址分配

对于链接器来说,在连接过程中。它的工作就是把多个输入的目标文件加工成合并成一个输出文件。这一篇博客就是介绍的静态链接中空间与地址分配的,有关静态链接的其他内容以及动态链接的信息我会在之后的博客介绍。

按序叠加

按序叠加可以说是最简单的一个方案,就是将输入的目标文件按照次序叠加起来。

但是从图中我们可以看到,在有很多输入文件的情况下,输出文件将有很多零散的段。因为每个段都要遵循空间对齐,所以这样无疑会占用大量空间。

比如,一个段长度只有1字节,但是按照空间对齐,其在内存也要占用4096个字节。

相似段合并

为了解决按需叠加所带来的问题,引入了相似段合并这个概念。顾名思义,就是把相同性质的段合并到一起。

就像我在博客:目标文件详解中提到的,.bss段其实在目标文件和可执行文件中 并不占用文件的空间(即不占用磁盘空间),但是在装载时是要占用地址空间的。
很多书中提到的“链接器为目标文件分配地址和空间”,这一句话其实是有两个含义的。对于.text和.data这样有实际数据的段,链接器在文件中和虚拟地址中都要分配空间。但是对于.bss这样的段,在文件中就不必分配空间,目的是节约磁盘空间
目前的链接器都不采用按序叠加的方法,而是采用相似段合并的方法。

链接器的链接方法——两步链接

刚刚我们说,链接器采用的是相似段合并的方法,使用这种方法的链接器一般都采用两步链接的方法。
第一步 空间与地址分配:链接器获取所有目标文件的段长度,并且将他们合并,计算出输出文件中各个段合并后的长度与位置,建立映射关系。
第二步 符号解析与重定位:使用上一步所收集到的信息,读取输入文件中段的数据、重定位信息、进行符号解析和重定位、调解代码中的地址。符号详解
链接器前后的程序所用的地址其实已经是程序应该在进程中使用的虚拟地址。Linux下一般冲0x08048000开始分配。至于为什么会从这个地方开始分配,我将在接下来的博客逐步介绍。

一个程序在加载到内存中一般会有4G的虚拟地址空间,其中1G是内核空间,3G进程空间。
符号地址的确定

地址确定很简单就,基址地址(0x08048000)+偏移地址(符号在进程中的地址)。

参考文献

[1] 俞甲子 石凡 潘爱明.程序员的自我修养.电子工业出版社,2009.4.