概念

动态链接比静态链接灵活,但牺牲了性能,据统计ELF程序在静态链接下比动态库快大约1%~5%。

原因

主要原因是,动态链接下对于全局和静态数据的访问都要进行复杂的GOT定位,然后间接寻址,对于模块间的调用也要先定位GOT,然后进行间接跳转。 另外,动态链接的链接过程是在运行时完成的,动态链接器会寻找并转载所需要的对象,然后进行符号查找地址重定位等工作。

步骤

建立一个 GOT.PLT 表,该表用来放全局函数的实际地址,但最开始时,该里面放的不是真实的地址而是一个跳转,接下来会讲。

对每一个全局函数,链接器生成一个与之相对应的影子函数,如 fun@plt。

所有对 fun 的调用,都换成对 fun@plt 的调用,每个fun@plt 长成如下样子:

fun@plt:
jmp *(fun@got.plt)
push index
jmp _init

其中第一条指令直接从 got.plt 中去拿真实的函数地址,如果已经之前已经发生过调用,got.plt 就已经保存了真实的地址,如果是第一次调用,则 got.plt 中放的是 fun@plt 中的第二条指令,这就使得当执行第一次调用时,fun@plt中的第一条指令其实什么事也没做,直接继续往下执行,第二条指令的作用是把当前要调用的函数在 got.plt 中的编号作为参数传给 _init(),而 _init() 这个函数则用于把 fun 进行重定位,然后把结果写入到 got.plt 相应的地方,最后直接跳过去该函数。