Linux下动态链接实现原理(3)

注意其中地址 4fa 及 516 处的指令:此两处分别对 g_share 及 g_func 进行了访问,显然此时它们的地址仍然是假地址,这些地址在动态库加载完成后会被动态链接器进行重定位,最终修改为正确的地址,这看起来与静态链接时进行重定位是一样的过程,但实现上有几个关键的不同之处:

因为不允许对可执行文件的代码段进行加载时符号重定位,因此如果可执行文件引用了动态库中的数据符号,则在该可执行文件内对符号的重定位必须在链接阶段完成,为做到这一点,链接器在构建可执行文件的时候,会在当前可执行文件的数据段里分配出相应的空间来作为该符号真正的内存地址,等到运行时加载动态库后,再在动态库中对该符号的引用进行重定位:把对该符号的引用指向可执行文件数据段里相应的区域。

ELF 文件对动态库中的函数调用采用了所谓的"延迟绑定”(lazy binding), 动态库中的函数在其第一次调用发生时才去查找其真正的地址,因此我们不需要在调用动态库函数的地方直接填上假的地址,而是使用了一些跳转地址作为替换,这里先不细说。

至此,我们可以发现加载时重定位实际上是一个重新修改动态库代码的过程,但我们知道,不同的进程即使是对同一个动态库也很可能是加载到不同地址上,因此当以加载时重定位的方式来使用动态库时,该动态库就没法做到被各个进程所共享,而只能在每个进程中 copy 一份:因为符号重定位后,该动态库与在别的进程中就不同了,可见此时动态库节省内存的优势就不复存在了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/ff8ee0804422736d6a822e7015c50de4.html