空间与地址分配
1.按序叠加
将输入的目标文件按照次序叠加起来,但浪费空间。
2.相似段合并(采用)
相同性质的段合并在一起。“.bss”段在目标文件和可执行文件中并不占用文件的空间,但是它在装载时占用地址空间。
所以链接器在合并各个段的同时也将“.bss”合并,并且分配虚拟空间。
“链接器为目标文件分配地址和空间”,此处的“地址和空间”有两个含义:
在输出的可执行文件中的空间。
在装载后的虚拟地址中的虚拟地址空间。
对于“.bss”来说,分配空间的意义只局限于虚拟地址空间,因为它在文件中并没有内容。
----------------------------------------------------------------------------------------------------------------------------------
两步链接
1.空间与地址分配
链接器获得所有输入目标文件的段长度,将它们合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系。
2.符号解析与重定位
使用步骤一收集到的信息,读取输入文件中段的数据、重定位信息,并且进行符号解析与重定位、调整代码中的地址等。
-e main 表示将main函数作为程序的入口,ld链接器默认的程序入口为_start
VMA virtual memory address 虚拟地址
LMA load memory address 加载地址
正常情况下两者值应该一样。
在链接前,目标文件所有段的VMA都是0,因为虚拟空间还没有被分配。
链接后,可执行文件“ab”中的各个段都被分配了相应的虚拟地址。
在Linux下,ELF可执行文件默认从地址0x08048000开始分配。
---------------------------------------------------------------------------------------------------------------------------
符号地址的确定
因为各个符号在段内的相对位置是固定的,所以给每个符号加上一个偏移量,便能使它们调整到正确的虚拟地址。
-------------------------------------------------------------------------------------------------------------------------------------
符号解析与重定位
重定位
如图,第一个引用是"shared",第二个引用是"swap"。
“shared”:暂时把地址0看作是“shared”的地址。
“swap”:近址相对位移调用指令。0XE8是操作码,后面4个字节就是被调用函数的 相对于调用指令的下一条指令 的偏移量。暂时作“-4”。
链接器在完成地址和空间分配之后就已经可以确定所有符号的虚拟地址了,链接器可以根据符号的地址对每个需要重定位的指令进行地址修正。
“shared”地址修正为0x08049154
"swap":call指令的下一条指令地址是0x080480b9,"swap"函数起始地址为0x080480bb,偏移量为2.
------------------------------------------------------------------------------------------------------------------------------------
重定位表
专门用来保存这些与重定位相关的信息。
每个要被重定位的地方叫做一个重定位入口。重定位入口的偏移表示该入口在要被重定位的段中的位置,即需要被调整的位置。
如“shared”偏移量为0x15,0x080480a9-0x08048094=0x15.
每个重定位入口都是一个Elf32_Rel结构的数组。
-------------------------------------------------------------------------------------------------------------------------------------------
符号解析
重定位的过程中,每个重定位的入口都是对一个符号的引用,那么当链接器需要对某个符号的引用进行重定位时,它就要确定这个
符号的目标地址。这时链接器就会去查找由所有输入目标文件的符号组成的全局符号表,找到相应的符号后进行重定位。
如图,其中Ndx为UND的都为需要重定位的。
---------------------------------------------------------------------------------------------------------------------
指令修正方式
缺省
------------------------------------
COMMON块
缺省
------------------------------
C++相关问题
缺省
------------------------------
静态库链接
在一般情况下,一种语言的开发环境往往会附带有语言库。这些库就是对操作系统的API的包装。很大部分库函数都是要调用OS的API的。
一个静态库可以简单地看成一组目标文件的集合。通常使用“ar”压缩程序将目标文件压缩在一起,并对其进行编号和索引,形成了libc.a这个静态库文件。
$ ar -t libc.a 查看这个文件包含了哪些目标文件
$objdump -t libc.a 查看libc.a的符号
链接器会自动寻找所有须要的符号及它们所在的目标文件,将这些目标文件从libc.a中“解压”出来,最终将它们链接在一起成为一个可执行文件。
--------------------------------------------------------------------------------------------------------------------------------------------------------
“-verbose”表示将整个编译链接过程的中间步骤打印出来;
“-fno-builtin” 关闭内置函数优化选项
调用ccl程序,将.c编译成一个临时的汇编文件.s
调用GNU的汇编器as将.s汇编成临时目标文件.o
调用collect2(ld链接器的一个包装)完成链接
------------------------------------------------------------------------------------------------------------------------------------------
链接过程控制
查看ld默认链接脚本
为了更精确地控制链接过程,可以自己写一个脚本,然后指定该脚本为链接控制脚本
$ ld -T link.script
缺省
------------------------------------------------------------------------------------------------------------------------
BFD库
BFD库(Binary File Descriptor library)是一个GNU项目,把目标文件抽象成一个统一的模型.
一旦我们需要支持一种新的目标文件格式,只需在BFD库里面添加一种格式即可。