前言

plt表和got表是和链接过程相关的表。我们知道,一个可执行文件的生成过程需要经过预处理,编译,汇编,链接四个过程。链接又分为静态链接和动态链接。静态链接是发生在程序执行之前,动态链接是发生在程序执行中。

链接方式不同,plt表和got的功能会有一些区别。

动态链接中的plt和got表

plt表的形式如下,下图是gdb调试过程中的图

plt表又叫过程链接表(Procedure Linkage Table)。

可以看到,plt表中存放的是代码,事实上,plt表就位于代码段。

如图可见,plt表的开头是一些指令,和下面的函数顺序对应。比方说程序第一次调用read函数,那么会先去找read的plt对应的内容,里面存的是直接跳转到got表的指令。跳到got之后,由于是第一次调用函数,got表里的内容是一条指令,jump到plt开头的对应的指令去。

注意前面的指令:

  1. push xxx :先将导入函数的标识(Elf Rel在.rel.plt的偏移)压栈
  2. 然后跳转到plt表的开头,又把linkmap的地址压栈,然后跳转到GOT[2](0x404010)保存的地址处,也就是_dl_runtime_resolve()函数

.got和.got.plt段的区别

先来张图看看got表长啥样 Global Offset Table (GOT)

__gmon_start___ptr 是编译器生成的一个符号,通常在使用 GCC 编译器时会出现。这个符号通常与程序的性能分析和优化有关。在程序中,__gmon_start___ptr 实际上是一个指向 __gmon_start__ 函数的指针,__gmon_start__ 函数是用于支持程序性能计数的库函数。

然后是got.plt表

got.plt[0],如上图所示,存的是这个值是 _DYNAMIC 符号的偏移量。 _DYNAMIC 符号通常用于动态链接过程中,在程序启动时由动态链接器使用。

got.plt[1]放的是link_map的地址。

got.plt[2]放的是_dl_runtime_resolve函数的地址,这个地址是动态装载的,因此在IDA里显示为0。

静态链接中的plt和got表 

如图,静态链接程序的plt表如下

可以看到,push的数字是0,这里push指令其实没有什么意义。然后会发现有两个jump,第一个jump跳到了下一条指令,然后跳到了got表。

got表里存的就是函数的地址了,不过这个地址并不是动态装载的,在IDA中就可以看到。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐