符号搬迁

The Symbol Relocation

以下是函数调用(第一次)在 PIC

中的解析方式
  1. 跳转到我们交易品种的 PLT 条目。
  2. 跳转到我们交易品种的 GOT 条目。
  3. 跳回 PLT 条目并将偏移量压入堆栈。那 offset 实际上是一个 Elf_Rel 结构,描述了如何修补符号。
  4. 跳转到 PLT 存根条目。
  5. 将指针推送到 link_map 结构以便链接器能够 查找符号属于哪个库。
  6. 调用解析器例程。
  7. 修补 GOT 条目。

这与仅使用 GOT table

的数据引用方式不同

那么,为什么会有这种差异呢?为什么有 2 种不同的方法?


why is there this difference? Why 2 different approaches?

你描述的是惰性搬迁。

不必 使用它,并且不会使用它,例如LD_BIND_NOW=1在环境中设置。

这是一种优化:当特定的程序调用不执行许多可能的程序执行路径时,它允许您减少动态链接器必须执行的工作量。

想象一个程序可以根据参数调用 foo()bar()baz(),并且 恰好 调用其中一个任何给定执行中的例程。

如果您不使用惰性重定位,动态加载程序将不得不在程序启动时解析所有 3 个例程。惰性重定位允许动态加载器仅执行任何给定执行中实际需要的一次重定位(被调用的 one 函数),并且在正确的时间(函数被调用时)。

现在,为什么 变量 也不能这样解决?

因为没有方便的方法让动态加载程序知道何时执行该重定位。

假设全局变量是 abc,并且 foo() 引用 abbar() 引用 bcbaz() 引用 ac。从理论上讲,动态加载器可以扫描 foobarbaz 的主体,并构建 "if calling foo, then also resolve globals a and b" 的映射等。但是只解析所有内容要简单和快速得多启动时对全局变量的引用。