博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
plt和got
阅读量:5249 次
发布时间:2019-06-14

本文共 2169 字,大约阅读时间需要 7 分钟。

  最近在学习linux高级调试技术。下面就动态库连接这块做了一个实验

  首先理解下plt是procedure linkage table,got是global offset table。got表中存放的是外部符号的地址。plt表中存放的是函数地址。下面看下实验具体情况。

  源码:

#include <stdio.h>

int fun()

{
printf("hello world\n");
}

int main()

{
while(1){
fun();
}
return 1;
}

在fun函数开始处设置断点。开始运行程序

首先看下fun函数的反汇编代码:

首先看下fun函数的反汇编代码:

(gdb) disassemble fun

Dump of assembler code for function fun:
0x080483d4 <+0>: push %ebp
0x080483d5 <+1>: mov %esp,%ebp
0x080483d7 <+3>: sub $0x18,%esp
0x080483da <+6>: movl $0x80484d0,(%esp)
0x080483e1 <+13>: call 0x80482f0 <puts@plt>
0x080483e6 <+18>: leave 
0x080483e7 <+19>: ret 
End of assembler dump.

偏移量为13的那句汇编就是调用printf。这个可以通过objdump -l 和-S选项查看

查看0x80482f0处的汇编

(gdb) disassemble 0x80482f0

Dump of assembler code for function puts@plt:
0x080482f0 <+0>: jmp *0x804a000
0x080482f6 <+6>: push $0x0
0x080482fb <+11>: jmp 0x80482e0
End of assembler dump.

接着再查看0x804a000中存放的内容

gdb) x/x 0x804a000

0x804a000 <puts@got.plt>: 0x080482f6

可以看到就是之前的反汇编代码的下一句话,但这也是plt表中的一项

那么查看0x80482e0的反汇编,

(gdb) disassemble 0x80482e0

No function contains specified address.

那么在该地址处设置断点查看。发现还是不能查看,那么采用查看内存内容的方式查看该处反汇编代码

(gdb) x/10i 0x80482e0

0x80482e0: pushl 0x8049ff8
=> 0x80482e6: jmp *0x8049ffc

接着查看0x8049ffc里面的内容

(gdb) x/x 0x8049ffc

0x8049ffc <_GLOBAL_OFFSET_TABLE_+8>: 0xb7ff2690

发现这个got表中的一项,地址是0xb7ff2690。

接着查看0xb7ff2690地址处的反汇编代码

(gdb) x/10i 0xb7ff2690

0xb7ff2690: push %eax
0xb7ff2691: push %ecx
0xb7ff2692: push %edx
0xb7ff2693: mov 0x10(%esp),%edx
0xb7ff2697: mov 0xc(%esp),%eax
0xb7ff269b: call 0xb7fec1c0

接下来会调用0xb7fec1c0地址处的代码,查看map信息会发现,这两个地址全部都是0xb7fde820 - 0xb7ff6b9f is .text in /lib/ld-linux.so.2里的代码,但是这边由于条件限制,看不到里面的函数名称,在网上可以查到是_dl_runtime_resolve函数。

当第一次运行fun函数结束后,第二次运行该函数时,我们再看下反汇编代码。

(gdb) disassemble 0x80482f0

Dump of assembler code for function puts@plt:
0x080482f0 <+0>: jmp *0x804a000
0x080482f6 <+6>: push $0x0
0x080482fb <+11>: jmp 0x80482e0

这段代码没有改变,但是看下0x804a000中的地址

(gdb) x/x 0x804a000

0x804a000 <puts@got.plt>: 0xb7e866a0

这和之前的地址是不一样的,之前是跳转到了0x080482f6,而这里已经实际填写上了printf的地址。

总结一下就是,如果一个动态库函数是第一次被调用,那么plt表中是不存在该函数的地址的,通过ld库中的函数,将这个地址取出来存放到got表中,那么当第二次调用该函数时,plt表中就有了这个函数的地址,直接跳转到该地址,而不再需要去取地址,也就是动态链接。

 

转载于:https://www.cnblogs.com/leo0000/p/5548650.html

你可能感兴趣的文章
hdu 1728 逃离迷宫
查看>>
MFC连接Mysql数据库执行查询和插入
查看>>
Linux+Apache+Tomcat集群配置
查看>>
c# Task编程一个task抛出异常后怎么取消其他线程
查看>>
Linux 最常用命令小结
查看>>
django之form表单验证
查看>>
自定义的事件管理器
查看>>
防止网页被搜索引擎爬虫和网页采集器收录的方法汇总
查看>>
【整理】Python中实际上已经得到了正确的Unicode或某种编码的字符,但是看起来或打印出来却是乱码...
查看>>
silverlight浏览器自适应问题
查看>>
【18】平衡二叉树
查看>>
转: ubuntu apt-get 与 aptitude 用法与区别
查看>>
基于ACE的TAO开发---一个简单的入门实例-----VS2008(一)
查看>>
数据库 阶段总结
查看>>
算法之【仿竖式算法】
查看>>
java环境安装说明
查看>>
Jmeter通过BeanShell Sampler获取Jmeter的Bin路径,并存入变量供后面的脚本调用
查看>>
MySQL Migration Toolkit v2.1特别版
查看>>
使用using current logfile实现DG备库实时更新
查看>>
List.Jion
查看>>