链接器的作用
最初的程序是直接编写二进制代码,其中是包含跳转指令的,而这些跳转指令的地址都是绝对值。当程序需要插入或删除新的指令(比如修bug),每条指令的地址都要相应改变,因此这些跳转指令的目标地址也需要改变,这个过程会相当繁琐且容易出错,被称为重定位。当一个程序包含多条纸带,且需要在纸带间跳转时,重定位的难度会进一步增加。
在汇编语言出现之后,通过jmp这种指令和符号的组合,可以机器自动计算程序跳转地址的功能,这解决了需要人工计算并重定位的难题。
随着软件规模的增长,软件代码数量越来越多,全部放在一个文件里不现实,因此出现了模块,将同一个功能相关的代码放在一个文件中。随之而来的就是需要将不同的模块”组装"起来,这就是链接器的作用。
静态链接
链接的过程主要包含地址和空间分配(Address and Storage Allocation),符号决议(Symbol Resolution),重定位(Relocation)。
假设我们有个全局变量叫做var,它在⽬标⽂件A⾥⾯。我们在⽬标⽂件B⾥⾯要访问这个全局变量,⽐如我们在⽬标⽂件B⾥⾯有这么⼀条指令:movl SOx2a, var这条指令就是给这个var变量赋值0x2a,相当于C语⾔⾥⾯的语句var=42。然后我们编译目标⽂件B,得到这条指令机器码。在编译B时,我们并不知道最终的var地址,因此先将目标地址置为0,然后在链接A和B时修正。假设A和B链接后var的地址为0x1000,那么链接器就会将这条指令的地址置为0x1000。这个过程就叫做重定位。