GOT表和PLT表浅解
动态链接
这里引用一下大佬的比喻。如果我的文章引用了别人的一部分文字,在我发布文章的时候把别人的段落复制到我的文章里面就属于静态连接,而做一个超链接让你们自己去看就属于动态链接了
1.PLT表和GOT表
GOT表:
每一个外部定义的符号在全局偏移表(Global offset Table)中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。也可以叫做全局函数表。
PLT表:
过程链接表(precedure Linkage Table)也叫内部函数表。
为了程序的轻量化,出现了动态链接,动态链接是在运行时进行重定位。在编译的时候在对应需要进行引用函数的时候用plt表来代替。
由于运行时的重定位不能修改代码段,只能去修改数据段。
可执行文件里面保存的是对应plt表的地址,plt表指向对应的got表。got表保存对应的glibc的地址。
2. 延迟绑定
由于动态链接是由动态链接器在程序加载时进行的,当需要重定位的符号(库函数)多了之后,势必会影响性能。延迟绑定(lazy bingding)就是为了解决这个问题的。 ——-ctf权威指南
由于对函数的动态链接需要对应的got表本来就保存着该函数glibc的地址。在一开始就进行所有函数的重定位是比较麻烦的,为此,linux 引入了延迟绑定机制。
1 | Disassembly of section .plt: |
ps.这里 plt 表的第一项使用 objdump 的时候给没有符号名的一项自动改成了离他最近的一项,为了避免引起误会,改成了 common,而且随着不断深入,会发现,确实可以叫 common。
其中除第一个表项以外,plt 表的第一条都是跳转到对应的 got 表项,而 got 表项的内容我们可以通过 gdb 来看一下,如果函数还没有执行的时候,这里的地址是对应 plt 表项的下一条命令,即 push 0x0(push 0x0的作用是为了延迟绑定时的glibc函数地址回写到对应的got表数据段
- 在函数没有绑定时需要的步骤是
xxx@plt -> xxx@got -> xxx@plt -> 公共@plt -> _dl_runtime_resolve
_dl_runtime_resolve函数是寻找函数的glibc地址并保存在got数据段
- 这里引用一下大佬的流程图:
初次调用函数时,got数据段内没有保存对应函数glibc地址。需要延迟绑定。
第二次调用,就不需要绑定了。