【DeepSeek】ELF 中的plt
fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;第二次调用第一次调用GOT指向下一条指令查找libc中printf地址GOT已存真实地址用户代码: call printfPLT条目: jmp *GOT执行解析器 Resolver更新GOT表跳
1. .plt 是什么?
.plt (Procedure Linkage Table,过程链接表) 是 ELF 文件代码段中的一个特殊区域,用于实现动态链接中的延迟绑定。
简单来说,它是一个**“跳板”或“中转站”**。当你的代码调用一个共享库(如 libc.so)中的函数时,程序并不直接跳转到该函数的真实地址,而是先跳转到 .plt 中的对应条目。
2. 为什么需要 .plt?
问题背景:
当你在程序中调用 printf("Hello") 时,编译器生成代码时并不知道 printf 在内存中的确切位置。因为 printf 位于外部的动态库中,只有程序运行时,动态链接器才能知道它被加载到了哪里。
解决方案:
如果不使用 .plt,动态链接器需要在程序启动时,找出所有用到的外部函数地址并填入代码中。这会导致程序启动非常慢。
.plt 的作用(延迟绑定):
利用 .plt,程序可以推迟查找外部函数地址的时机。
- 第一次调用时:通过
.plt触发动态链接器去查找printf的真实地址,填入记录表,然后执行。 - 后续调用时:直接通过
.plt跳转到已记录好的真实地址,不再查找。
3. 具体例子说明
假设我们有一个简单的 C 程序 main.c,它调用了标准库函数 printf。
#include <stdio.h>
void say_hello() {
printf("Hello World!\n"); // 调用外部函数
}
int main() {
say_hello();
say_hello(); // 调用第二次
return 0;
}
场景推演:从汇编指令到内存跳转
当编译器生成汇编代码时,call printf 指令实际上被改写成了调用 .plt 中的条目。
第一步:程序执行 call printf
汇编代码实际上长这样:
call printf@plt
这行指令的意思是:跳转到 .plt 段中专门处理 printf 的那个代码块。
第二步:进入 .plt 段 (第一次调用)
程序跳转到了 .plt 中的 printf 条目。该条目通常包含三条指令(简化逻辑):
printf@plt:
; 1. 跳转到 GOT 表中记录的地址
jmp *GOT[n]
; 2. (如果上面跳转失败,说明是第一次调用,会执行下面)
push n ; 压入参数 n (代表 printf 的 ID)
jmp resolver ; 跳转到动态链接器的解析函数
- 关键点:
GOT[n]是全局偏移表中的一个槽位。- 初始状态:
GOT[n]里存的并不是printf的真实地址,而是上面push n这条指令的地址。 - 结果:因为
GOT[n]指向了下一条指令,所以第一次执行jmp *GOT[n]时,实际上没跳走,而是继续往下执行了push n和jmp resolver。
- 初始状态:
第三步:动态链接器介入resolver 是动态链接器提供的代码。它做以下事情:
- 根据参数
n,知道程序想找printf。 - 在内存中找到 libc.so 中
printf的真实加载地址(假设是0x7fff1234)。 - 将这个真实地址
0x7fff1234回写到GOT[n]中。 - 跳转到
0x7fff1234执行printf函数体。
第四步:进入 .plt 段 (第二次调用)
当 main 函数第二次调用 say_hello 时,流程再次来到 printf@plt:
printf@plt:
jmp *GOT[n] ; 此时 GOT[n] 已经被修改为 0x7fff1234
- 现状:此时
GOT[n]里存的是刚才解析好的真实地址0x7fff1234。 - 结果:
jmp指令直接跳转到了printf的真实代码,不再执行后面的push和resolver。
4. 总结流程图
5. 核心价值总结
- 性能优化:如果不使用 PLT/GOT 机制,程序启动时必须解析所有可能用到的几百个库函数,导致启动极慢。使用 PLT 后,只有真正用到的函数才会被解析(按需解析)。
- 代码独立性:用户代码不需要在编译时硬编码函数地址,所有的外部调用都通过
.plt这个统一的中转站进行。
一句话概括:.plt 就是一个带有“自动寻址功能”的跳板,第一次跳过去时它会负责找到目标并记下来,之后再跳过去时它就直接把你送到目标地址。
更多推荐



所有评论(0)