You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ELF的PLT/GOT机制下,共享库导入函数地址获取及一致性的疑问

关于ELF中导入函数地址一致性的解析

你的核心困惑在于混淆了PLT的延迟绑定逻辑和直接获取函数地址时的立即解析行为,下面拆解背后的原理:

核心真相:你拿到的是GOT条目中的最终解析地址

当你通过函数指针获取导入函数地址时,返回的既不是PLT槽的地址,也不是未解析的占位地址——而是动态链接器已经解析完成的导出库中函数的真实内存地址,所有共享库的对应GOT条目最终都会被更新为这个地址,所以不同库中取到的地址自然相等。

为什么之前的理解有偏差?

  • 你提到的“默认情况下导出地址只有调用后才解析”,指的是PLT触发的延迟绑定:当通过PLT调用函数时,第一次调用才会触发动态链接器去解析真实地址并写入GOT,后续调用直接跳转到GOT中的地址。
  • 但直接获取函数地址的操作会绕过延迟绑定:动态链接器会立即执行重定位操作,直接将导出函数的真实地址写入当前模块的GOT条目,不需要等到第一次调用。

具体流程拆解

  1. 当程序加载时,每个共享库的GOT中对应导入函数的条目初始值是PLT槽的地址(用于延迟绑定的跳转入口)。
  2. 当你执行类似void (*fp)() = &printf;这样的代码时,编译器会生成访问GOT条目的指令,动态链接器检测到这个访问(或在重定位阶段直接完成解析,取决于链接选项),立即去查找printf在libc.so中的真实地址。
  3. 动态链接器将找到的真实地址写入当前模块的GOT条目,同时其他共享库中对应的GOT条目也会被更新为同一个地址——因为全局符号解析的规则是:同一个符号在整个进程中只有一个唯一的定义。
  4. 所以无论从哪个共享库中获取该函数的地址,最终拿到的都是GOT条目中存储的真实地址,自然完全相等。

对应Windows IAT的情况

Windows的机制类似:

  • 模块的IAT(导入地址表)初始存储的是导入函数的“桩函数”地址(类似ELF的PLT槽)。
  • 当你直接获取导入函数地址时,系统会触发IAT的立即解析,将桩函数替换为DLL中导出函数的真实地址,所有模块的IAT条目最终指向同一个地址,因此不同模块中取到的函数地址一致。

内容的提问来源于stack exchange,提问作者Ofek Shilon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:38:24