免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6555 | 回复: 7
打印 上一主题 下一主题

动态链接库函数是怎样调用到的? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-07-15 13:03 |只看该作者 |倒序浏览
本帖最后由 wwxbei 于 2011-07-16 14:00 编辑

最近在看动态链接的实现,主要是GOT, PLT段的汇编。 理论上是加载器会修改GOT内容,填写动态库函数的真正地址。 但是从反汇编上却总是看不出来这一点。
就以最简单的printf为例:

main.c
  1. #include <stdio.h>
  2. int main(int argc, char* argv[])
  3. {
  4.     printf("Hello world %d.\n", argc);
  5.     return 0;
  6. }
复制代码


看main函数的反汇编,其实是直接跳转到
printf@plt 标号处。
  1. 00400470 <printf@plt>:
  2. 400470:   3c0f0041    lui t7,0x41
  3. 400474:   8df907c0    lw  t9,1984(t7)
  4. 400478:   25f807c0    addiu   t8,t7,1984
  5. 40047c:   03200008    jr  t9
  6. 400480:   00000000    nop
复制代码


流程是:
t7=0x410000, t9=*(0x4107c0),t8=0x4107c0, jr t9
也就是寄存器
t8的值是0x4107c0, t9的值是内存地址0x4107c0处存放的值。然后跳转到t9指示的地址处。所以,这里的关键就是内存地址0x4107c0处存放的值到底是什么。

  1. Disassembly of section .got.plt:
  2. 004107b4 <.got.plt>:
  3.     ...
  4. 4107bc:   00400440    0x400440
  5. 4107c0:   00400440    0x400440
复制代码

可见,地址0x4107c0位于.got.plt段,存放的值为0x400440. 也就是说刚才程序的执行流程会跳转到0x400440地址处,这正是.plt段的位置。

  1. Disassembly of section .plt:
  2. 00400440 <_PROCEDURE_LINKAGE_TABLE_>:
  3. 400440:   3c1c0041    lui gp,0x41
  4. 400444:   8f9907b4    lw  t9,1972(gp)
  5. 400448:   279c07b4   addiu   gp,gp,1972
  6. 40044c:   031cc023    subu    t8,t8,gp
  7. 400450:   03e07821   move    t7,ra
  8. 400454:   0018c082   srl t8,t8,0x2
  9. 400458:   0320f809   jalr    t9
  10. 40045c:   2718fffe    addiu   t8,t8,-2
复制代码


t9=*(0x4107b4),其实就是以0x4107b4处存放的值做目的地址去跳转。而从上面.got.plt段的汇编看,0x4107b4处存放的值应该是零。
Jalr跳到零地址?????   到这里就分析不下去了, 请高手指点一下迷津。


附上.rel.plt和.got段:
  1. Disassembly of section .rel.plt:
  2. 004003c8 <.rel.plt>:
  3. 4003c8:   0041077c    0x41077c
  4. 4003cc:   0000027f    0x27f
  5. 4003d0:   00410780    0x410780
  6. 4003d4:   0000047f    0x47f
复制代码
  1. Disassembly of section .got:
  2. 004107d0 <_GLOBAL_OFFSET_TABLE_>:
  3. 4107d0:   00000000    nop
  4. 4107d4:   80000000    lb  zero,0(zero)
  5. 4107d8:   00410784    0x410784
  6. 4107dc:   00000000    nop
  7. 4107e0:   004003d8    0x4003d8
  8. 4107e4:   00000000    nop
复制代码

论坛徽章:
0
2 [报告]
发表于 2011-07-16 21:28 |只看该作者
你看一本专著叫《连接器和加载器》,讲解的很详细,动态加载的时候实际启动了一个加载器,帮助程序去调用动态库,并修改程序里的符号表,然后去执行;当第二次运行的时候就不需要再去加载,直接跳到修改过的符号地址

论坛徽章:
0
3 [报告]
发表于 2011-07-17 13:37 |只看该作者
回复 2# 吾爱夏日长

我就是看了书上的理论,才打算找个实际的代码来验证一下的。 但是分析下来实际跟理论结合不上,所以才来请求帮助。

论坛徽章:
0
4 [报告]
发表于 2011-07-18 16:48 |只看该作者
使用GDB单步调试发现, 加载器会修改.got.plt段的内容,加载后(运行前).got.plt段的内容为:
  1. 004107b4 <.got.plt>:
  2. 4107b4:  4081718c    0x4081718c
  3. 4107b8:  40830a18    0x40830a18
  4. 4107bc:  00400440    0x400440
  5. 4107c0:  00400440    0x400440
复制代码

所以不是跳到零地址,而是跳到0x4081718c处,这是ld-linux.so里面的_dl_runtime_pltresolve()函数所在处。

论坛徽章:
0
5 [报告]
发表于 2011-07-21 19:50 |只看该作者
楼主搞清楚了写个总结出来吧

论坛徽章:
0
6 [报告]
发表于 2011-07-28 16:31 |只看该作者

论坛徽章:
0
7 [报告]
发表于 2011-08-03 08:10 |只看该作者
《链接器和加载器》大家都说好,其实我个人觉得有点言过其实,对完全不懂的人来说,不适合去看那本书,还是看看《程序员的自我修养-链接、加载和库》,讲得非常详细。你所想知道的都有讲

论坛徽章:
0
8 [报告]
发表于 2011-08-14 20:04 |只看该作者
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP