【问题标题】:Why trampoline from PLT to GOT instead of directly jumping to GOT? [duplicate]为什么要从 PLT 跳到 GOT 而不是直接跳到 GOT? [复制]
【发布时间】:2017-07-27 15:24:58
【问题描述】:

我正在研究如何在动态链接中使用 GOT 和 PLT。我很困惑为什么每个动态链接的函数调用似乎都会跳转到 PLT 中的某个位置,而该位置总是会跳转到 GOT 中的相同位置。为什么不直接跳到 GOT 中的那个位置呢?为什么需要另一层间接?


我可能从根本上对 GOT 和 PLT 有一些误解,所以这里简要描述一下我对如何使用 PLT 和 GOT 的概念理解。

我们有一个名为 FunctionX 的函数,在 PLT 中的对应位置为 PLT[X],在 GOT 中的对应位置为 GOT[X]。 PLT 和 GOT 的地址在编译时是已知的,但 FunctionX 的地址是未知的。

为了调用FunctionX:

1) 调用(在汇编意义上)PLT[X] 的地址。

2) PLT[X] 是跳转到 GOT[X] 所包含的值。

3a) 如果 FunctionX 已经解析,则 GOT[X] 包含函数地址,因此第 2 步是跳转到 FunctionX。

3b) 否则,GOT[X] 包含将在运行时解析 FunctionX 地址的代码地址,将该地址写入 GOT[X],然后跳转到 FunctionX。在这种情况下,第 2 步会导致 FunctionX 被解析然后跳转到。

第一步的目的是什么?

我对这个话题的理解是粗略的,所以请指出任何可以帮助这个问题的澄清。

【问题讨论】:

  • 这里只是猜测,但也许PLT是一个标准化的东西,但它恰好使用GOT的事实只是一个偶然的实现细节。
  • 请参阅stackoverflow.com/questions/43048932/…,了解为什么在 x86 目标上无法轻松消除 PLT。
  • @RossRidge 这回答了我的问题。谢谢。

标签: assembly linker dynamic-linking plt got


【解决方案1】:

想一想

想象一下,从某个客户端代码(例如 main)第一次调用 GOT[X] 处的任何地址。正如您在 3b) 中所说,这将调用解析 FunctionX 地址的代码。但是解析代码怎么知道你想解析 FunctionX 呢?您像普通函数一样调用它,您没有为解析器提供任何其他信息,即您要修补的 FunctionX 地址。 Stub 在跳转到 GOT[X] 之前推送堆栈额外信息。

this 文章的最后几段帮助很大。

【讨论】:

  • 我把那部分省略了。本质上,GOT[X] 最初包含的地址是专门用于解析 FunctionX 的代码地址。该代码设置参数,指定我们正在解析 FunctionX 并且地址应该写入 GOT[X] 然后分派到通用符号解析代码。我的理解是对 PLT[X] 的初始调用总是一个简单的跳转。
  • 是的,设置参数的代码是存根不是吗?据我所知,这就是它的目的。
  • PLT[X] 中的第一条指令是跳转回自身,它在第一次调用时实际上是 NOP 指令。
  • GOT[X] 最初包含 PLT[X] 中第二条指令的地址
  • 我的理解是,指定“在 GOT[X] 处解析 FunctionX”的代码在 PLT 中,但不在 PLT[X] 处。 PLT[X] 总是只是跳转到 GOT[X] 包含的值。我不明白第一次访问PLT的目的。
猜你喜欢
  • 2017-08-20
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 2021-11-26
相关资源
最近更新 更多