【问题标题】:What is the primary reason for using PLT & GOT tables for shared libraries?将 PLT 和 GOT 表用于共享库的主要原因是什么?
【发布时间】: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


    【解决方案1】:

    您似乎缺少或不理解copy-on-write (CoW) 页面的概念。

    两个进程可以将磁盘上的同一个文件mmap 放到它们不同的虚拟地址中,并且操作系统可以为这两个映射使用单个 RAM 物理页(即进程共享一个物理内存页)。但是,一旦一个进程更改了内存,就会为该进程创建一个副本,并且更改不会出现在另一个进程中(物理内存页面不再共享)。

    因此,如果动态链接器在共享库的主体中进行了任何重定位,这些更改将出现在也映射了该共享库的所有其他进程中,

    如果内存是 CoW,则不会。

    正是因为这个原因,我们才有了 GOT 和 PLT

    不,原因是优化(需要复制的页面更少),而不是您的(错误)理解所暗示的正确性

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-03
      • 1970-01-01
      • 1970-01-01
      • 2012-11-10
      • 2012-05-29
      • 2015-12-27
      • 2017-08-20
      相关资源
      最近更新 更多