【发布时间】:2020-06-20 11:52:01
【问题描述】:
我正在阅读 Ian Lance Taylor 关于链接器的文章:http://inai.de/documents/Linkers.pdf
在第 9 页讨论共享对象时,他提到由于共享库可以加载到无法预测的虚拟地址的进程中,因此一旦知道地址,动态链接器将需要处理大量重定位。这会减慢加载速度。为了避免动态链接器完成大量重定位,程序链接器将函数引用更改为对 PLT 表的 PC 相关调用,并将全局/静态变量引用转换为对 GOT 表的引用。那么动态链接器只需要在加载时重定位PLT/GOT中的条目,而不需要处理整个二进制文件中的重定位。
但是,对加载时间优化的关注让我感到困惑,因为这里似乎有一个更明显的问题,而加快加载速度是无关紧要的。共享对象的全部意义在于,加载到物理内存中的单个共享对象现在可以映射到每个需要它的进程的虚拟地址空间。这可以通过更改一些页表来快速完成,并且避免从磁盘加载库的新副本。
因此,如果动态链接器在共享库的主体中进行了任何重定位,这些更改将出现在也映射了该共享库的所有其他进程中,并且如果库出现在不同的虚拟地址,它们将破坏该库.
正是出于这个原因,我们才有了 GOT 和 PLT。程序链接器将所有引用修改为对 GOT 和 PLT 的与位置无关的引用。然后动态链接器为每个进程唯一地重新定位 GOT 和 PLT 中的条目。共享库的主要内容是跨进程共享的,但GOT和PLT对每个进程都是唯一的,不共享。
这种对 PLT 和 GOT 的理解是否正确?我根据自己的理解推断了这里的一些机制,但我没有看到它可以工作的任何其他方式。
【问题讨论】:
标签: compilation linker shared-libraries