plt 和 got
在 Linux ELF 文件和动态链接机制中,这四个段(Section)共同协作,实现了位置无关代码(PIC)和延迟绑定(Lazy Binding)。
虽然它们名字很像,但功能和权限有着本质区别。我们可以将其分为两类:PLT 类(代码/执行) 和 GOT 类(数据/读写)。
1. .plt (Procedure Linkage Table - 过程链接表)
- 属性:代码段(权限:读取+执行
R-X)。 - 作用:它包含了一系列小的可执行代码片段(Stub)。
- 功能:当程序调用一个外部函数(如
printf)时,它实际上并不是直接跳到printf的地址(因为在编译阶段不知道地址),而是跳到.plt段中对应的条目。 - 内容:
- 第一项是特殊项,负责调用动态链接器的符号解析函数。
- 后续每一项对应一个外部函数,代码逻辑通常是:
jmp *(.got.plt中的对应项)。
2. .got (Global Offset Table - 全局偏移表)
- 属性:数据段(权限:读取+写入
RW-)。 - 作用:用于存储全局变量的绝对地址。
- 功能:程序在引用全局变量时,会先到
.got中查找该变量的真实地址。 - 为什么需要:为了实现位置无关代码(PIC),代码段不包含变量的绝对地址,只包含到
.got的相对偏移。动态链接器在程序启动时会将变量的真实地址填入.got。
3. .got.plt (GOT 的 PLT 部分)
- 属性:数据段(权限:读取+写入
RW-,但在 Full RELRO 下为R--)。 - 作用:它是
.got的一个子集,专门用于存储外部函数的绝对地址。 - 与
.plt的配合:- 在延迟绑定(Lazy Binding)模式下:
.got.plt的初始内容指向.plt中的下一条指令(即“跳回 PLT”)。当函数第一次被调用时,动态链接器解析出真实地址并覆盖掉这个值。 - 在第二次调用时:
.plt里的jmp就会直接跳到.got.plt中存储的真实地址,不再进入链接器。
- 在延迟绑定(Lazy Binding)模式下:
- 特殊项:前三项通常预留给动态链接器的私有信息(如
link_map结构和_dl_runtime_resolve函数地址)。
4. .plt.got (专门的 PLT 跳转表)
- 属性:代码段(权限:读取+执行
R-X)。 - 作用:这是一个特殊的
.plt段,通常用于非延迟绑定的情况,或者用于处理某些特定的重定位类型(如通过R_X86_64_GLOB_DAT重定位的函数指针)。 - 区别:
- 标准的
.plt条目通常包含三个动作:跳转到 GOT、压栈索引、跳到解析器。 .plt.got条目通常直接跳转到.got(而不是.got.plt)中存储的地址,不包含延迟绑定的逻辑(没有压栈和解析器的跳转)。它通常出现在启用了-z now(Full RELRO)或编译器优化后的二进制文件中。
- 标准的
总结与对比
| 段名称 | 类型 | 权限 | 存储内容 | 核心目的 |
|---|---|---|---|---|
| .plt | 代码 | R-X | 跳转代码片段 (Stubs) | 函数调用的中转站,触发延迟绑定 |
| .plt.got | 代码 | R-X | 直接跳转代码 | 跳过延迟绑定逻辑,直接跳转到 GOT 地址 |
| .got | 数据 | RW- | 全局变量的绝对地址 | 变量引用的位置无关化 |
| .got.plt | 数据 | RW- | 外部函数的绝对地址 | 配合 .plt 实现函数的延迟绑定 |
协作流程演示(以延迟绑定为例):
- Call
printf@plt:程序跳转到.plt中printf对应的条目。 - Jmp to
.got.plt:.plt里的第一条指令跳转到.got.plt记录的地址。- 第一次调用:
.got.plt填的是.plt的下一行。
- 第一次调用:
- Resolve:
.plt剩下的代码调用动态链接器,找到printf的真实地址。 - Update:动态链接器将
printf的真实地址写回.got.plt。 - Subsequent Calls:下次再调
printf@plt时,第 2 步的Jmp会直接跳到printf的真实地址。
为什么现在的安全保护(RELRO)会影响这些段?
- Partial RELRO:
.got.plt是可写的。攻击者可以利用堆栈溢出覆盖.got.plt的条目,将printf改为system,从而实现 GOT Hijacking。 - Full RELRO:动态链接器在程序启动时就把所有函数解析完毕,并将
.got.plt设为只读。此时,.plt.got的作用就会变得更明显,因为不再需要延迟绑定逻辑了。
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.