符号搬迁
The Symbol Relocation
以下是函数调用(第一次)在 PIC
中的解析方式
- 跳转到我们交易品种的
PLT
条目。
- 跳转到我们交易品种的
GOT
条目。
- 跳回
PLT
条目并将偏移量压入堆栈。那
offset 实际上是一个 Elf_Rel
结构,描述了如何修补符号。
- 跳转到
PLT
存根条目。
- 将指针推送到
link_map
结构以便链接器能够
查找符号属于哪个库。
- 调用解析器例程。
- 修补
GOT
条目。
这与仅使用 GOT
table
的数据引用方式不同
那么,为什么会有这种差异呢?为什么有 2 种不同的方法?
why is there this difference? Why 2 different approaches?
你描述的是惰性搬迁。
您 不必 使用它,并且不会使用它,例如LD_BIND_NOW=1
在环境中设置。
这是一种优化:当特定的程序调用不执行许多可能的程序执行路径时,它允许您减少动态链接器必须执行的工作量。
想象一个程序可以根据参数调用 foo()
、bar()
或 baz()
,并且 恰好 调用其中一个任何给定执行中的例程。
如果您不使用惰性重定位,动态加载程序将不得不在程序启动时解析所有 3 个例程。惰性重定位允许动态加载器仅执行任何给定执行中实际需要的一次重定位(被调用的 one 函数),并且在正确的时间(当函数被调用时)。
现在,为什么 变量 也不能这样解决?
因为没有方便的方法让动态加载程序知道何时执行该重定位。
假设全局变量是 a
、b
和 c
,并且 foo()
引用 a
和 b
、bar()
引用 b
和 c
,baz()
引用 a
和 c
。从理论上讲,动态加载器可以扫描 foo
、bar
和 baz
的主体,并构建 "if calling foo
, then also resolve globals a
and b
" 的映射等。但是只解析所有内容要简单和快速得多启动时对全局变量的引用。
以下是函数调用(第一次)在 PIC
- 跳转到我们交易品种的
PLT
条目。 - 跳转到我们交易品种的
GOT
条目。 - 跳回
PLT
条目并将偏移量压入堆栈。那 offset 实际上是一个Elf_Rel
结构,描述了如何修补符号。 - 跳转到
PLT
存根条目。 - 将指针推送到
link_map
结构以便链接器能够 查找符号属于哪个库。 - 调用解析器例程。
- 修补
GOT
条目。
这与仅使用 GOT
table
那么,为什么会有这种差异呢?为什么有 2 种不同的方法?
why is there this difference? Why 2 different approaches?
你描述的是惰性搬迁。
您 不必 使用它,并且不会使用它,例如LD_BIND_NOW=1
在环境中设置。
这是一种优化:当特定的程序调用不执行许多可能的程序执行路径时,它允许您减少动态链接器必须执行的工作量。
想象一个程序可以根据参数调用 foo()
、bar()
或 baz()
,并且 恰好 调用其中一个任何给定执行中的例程。
如果您不使用惰性重定位,动态加载程序将不得不在程序启动时解析所有 3 个例程。惰性重定位允许动态加载器仅执行任何给定执行中实际需要的一次重定位(被调用的 one 函数),并且在正确的时间(当函数被调用时)。
现在,为什么 变量 也不能这样解决?
因为没有方便的方法让动态加载程序知道何时执行该重定位。
假设全局变量是 a
、b
和 c
,并且 foo()
引用 a
和 b
、bar()
引用 b
和 c
,baz()
引用 a
和 c
。从理论上讲,动态加载器可以扫描 foo
、bar
和 baz
的主体,并构建 "if calling foo
, then also resolve globals a
and b
" 的映射等。但是只解析所有内容要简单和快速得多启动时对全局变量的引用。