Linux中的静态链接

静态链接就是将多个目标文件链接成一个文件,主要有两种方法:

  1. 按序叠加:将输入的目标文件按照次序叠加起来。该方法会造成很多的段,因为每一个段都需要有一定的地址和空间对齐要求,这样会造成内存空间的大量内部碎片。
  2. 相似段合并:将相同性质的段合并到一起。

链接器为目标文件分配地址和空间,这句话中的地址和空间其实有两个含义:第一个就是在输出的可执行文件中的空间,第二个就是在装载后的虚拟地址中的虚拟地址空间。对于有实际数据的段来说,如代码段和数据段,他们在文件和虚拟地址中都需要分配空间,因为他们在这两者中都存在,而对于bss段,分配空间的意义只局限于虚拟地址空间,因为在文件中,bss段并内有实际的内容。
现在的空间链接分配策略都采用第二种方法,一般分两个步骤进行:

  1. 空间和地址分配:扫描所有的输入目标文件,获得他们各个段的长度、属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号应用收集起来,统一放到一个全局符号表。
  2. 符号解析与重定位:使用上面第一步中收集到的所有信息,读取输入文件中段的数据、重定位信息并且进行符号解析与重定位、调整代码中的地址等信息。该步骤是链接的核心,特别是符号重定位过程。链接器对于重定位中的符号,根据生成的全局符号表进行目标地址查找,然后修改代码中相应的地址。

连接后生成的可执行文件,每一个段都被分配到一个固定的虚拟地址了,转载后,该地址就是实际运行的虚拟地址。也就是说,连接后,每一个段在虚拟地址空间的布局就已经分配好了。在Linux下,ELF可执行文件默认的开始地址为0x08048000,并不是从0x0开始分配。

由于静态链接是将输入的目标文件合并在一起,所以对已一般的静态运行库来说,一个目标文件只有一个函数,这样的设计是的静态链接后的文件所合并的都是实际上需要的代码或数据段。如果一个目标文件包含多个函数的话,即使只需要该目标文件中的一个函数,由于合并是以文件为单位的,所以其他的不必要的函数也会被合并进来,造成空间浪费。