空间与地址分配

对于链接器来说,整个链接过程,就是将几个输入目标文件加工后合并成一个输出文件(如下图),通过前面对ELF文件格式的介绍,使我们对其整体轮廓有了一定的了解,我们知道,可执行文件中的代码段和数据段都是有输入的目标文件合并而来的,接下来介绍一下如何合并

  1. 按序叠加
    简单的将输入的目标文件按照次序叠加起来,这种方式基本不采用

  2. 相似段合并
    将相似性质的段合并,如下图所示

地址和空间有两个含义:一是输出在可执行文件中的空间;二是装载后的虚拟地址空间
例如对于.text.data段,它们在文件和虚拟地址中都要分配空间,而对于.bss段来说,分配空间的意义只在于虚拟地址空间,因为他在文件中并没有内容。
事实上,我们只专注于虚拟地址空间分配,因为这个关系到链接器后面的关于地址计算的步骤,可执行文件本身的空间分配与链接过程关系并不是很大。

现在的链接器空间分配策略基本都采用第二种方式,且采用两步链接的方法:

  • 第一步 空间与地址分配
    扫描所有的输入目标文件,将输入目标文件中的符号表中所有的符号定义和符号引用汇总放在一个全局符号表,在这一部中,链接器能够获取所有输入目标文件的段长度,并将它们合并,计算输出文件中各个段合并后的长度与位置,并建立映射关系。
  • 第二步 符号解析与重定位
    接下来介绍。

符号解析与重定位

使用上面收集到的所有信息,读取输入文件中段的数据、重定位信息,并进行符号解析与重定位、调整代码中的地址等,第二步是链接过程的核心,特别是重定位过程。

简单来说,若在a文件中调用了b文件中的函数或者使用了其中定义的变量,那么在链接前,其实a文件是不知道调用的函数和变量的位置的,即编译器暂时将相关指令的地址部分,用地址0x00000000和0xFFFFFFFC代替,将真正的地址计算工作留给了连接器。完成地址空间分配后,已经能够确定所有符号的虚拟地址了,那么连接器就可以对每个需要重定位的指令进行地址修正。

  • 重定位表

    那么连接器是怎么知道那些指令是要被调整的呢?事实上在ELF文件中有一个叫重定位表(Relocation Table)的结构专门保存与重定位相关的信息。

    对于可重定位的ELF文件,他必须包含重定位表,对于每个要被重定位的ELF段都有一个对应的重定位表,而这个表其实就是ELF文件中的一个段,例如.text需要被重定位的地方,有一个对应的.rel.text的段保存了代表段的重定位表,还有.data对应的.rel.data段,可使用objdumo -r来查看重定位表

    这个命令可以查看文件中所有需要重定位的地方,即所有引用到外部符号的地址。每个要被重定位的地方叫重定位入口,可以看到上图中有两个入口,重定位入口的偏移表示该入口在要被重定位的段中的位置,RELOCATION RECORDS FOR [.text]即表示这个重定位表是代码段的重定位表,所以偏移表示代码段中需要被调整的位置。

  • 符号解析

    其实重定位过程也伴随这符号的解析过程,每个目标文件都可能定义一些符号,也可能引用到定义在其他目标文件的符号。重定位的过程中,每个重定位的入口都是对一个符号的引用,那么当链接器需要对某个符号的引用进行重定位时,他就要确定这个符号的目标地址。这时候链接器就会去查找所有输入目标文件的符号表组成的全局符号表,找到相应的符号后进行重定位。
    例如

    GLOBAL类型的符号,除了main函数是定义在代码段之外,其余两个都是UND,即未定义,这种未定义的符号都是因为该目标文件中有关于它们的重定位项,所以链接器在扫描完所有的输入目标文件之后,所有这些未定义的符号都应该能够在全局符号表中找到,否则连接器就报符号未定义错误。

可执行文件的装载

每个程序运行起来后,拥有自己独立的虚拟地址空间,这个空间大小由硬件平台决定,大概效果如下

上图是一个32位系统下,进程的虚拟地址空间分配情况,其中关于虚拟内存的知识可参考《Linux系统编程中内存管理》笔记中的内容,其中介绍了非连续内存分配(分段和分页),程序局部性原理,早期的覆盖技术、交换技术和现在使用的虚拟内存管理,了解上述知识后基本也就了解了可执行文件的装载。

这里需要注意,可执行文件的装载并不是按照单个段进行映射的,因为会由于段映射时的页对其产生浪费。站在装载的角度看,操作系统并不关心段的具体内容,只关心一些和装载相关的问题,主要是权限,分为以下几种

  • 以代码段为代表的可读可执行的段
  • 以.data和.bss为代表的可读可写的段
  • 以.rodata为代表的只读的段

所以处理方案就是对于相同权限的段,合并到一起当作一个段进行映射,如下图所示

到这里基本就可以搞清程序编译和链接以及装载做了那些主要工作,对我们的程序有了更进一步的认识,而其中一些更加细节的结构体和步骤暂时不再深究。