Linux下库函数动态链接过程分析-结合glibc-2.11源码

Linux下程序库函数调用的动态链接过程是很常见的,其实刚学编程时写的helloworld程序调用的printf就牵涉到动态链接,只是我们那时没有去注意罢了。

请看下面的helloworld程序反汇编代码

 

图1

可以看到图1第9行输出时的指令为call 80482fc <puts@plt>

再看看80482fc处是什么东东,如下

 

图2

可见这是.plt段的一段代码。细心的我们或许会发现.plt有一个特点,除了第一项外,其他的项都是三条指令,jmp *, push, jmp,并且第三条指令跳到了.plt的第一项。我们来分析<puts@plt>这一项:

图2第16行的间接跳转,以GOT表的某一项间接寻址(如果不知道GOT表是什么,看看elf手册就清楚了),GOT表是一个如下的数组

extern Elf32_Addr _GLOBAL_OFFSET_TABLE_[];

我们用readelf -s helloworld命令可以看出这个数组的起始地址为08049ff4,如下

 

35: 08049ff4     0 OBJECT  LOCAL  HIDDEN   22 _GLOBAL_OFFSET_TABLE_

可以计算一下,上面的间接跳转以GOT[(0x804a008 - 0x8049ff4) / 4] = GOT[5]的值间接跳转,那么这个值是什么呢,当然静态是看不到的,我们gdb启动程序并查看0x804a008地址的值

 

 

(gdb) b main

Breakpoint 1 at 0x80483ed: file helloworld.c, line 6.

(gdb) r

Starting program: /home/lzs/programming/test/helloworld 

 

Breakpoint 1, main (argc=1, argv=0xbfffefe4) at helloworld.c:6

6 printf("helloworld/n");

 

(gdb) x/x 0x804a008

0x804a008 <_GLOBAL_OFFSET_TABLE_+20>: 0x08048302

(gdb) 

可见该值为0x08048302,大家发现了没有,这个值就是图2第17行指令的地址,也就是执行了第16行的指令后就跑到了第17行,然后到了.plt的第一项,再然后又间接跳转到了某个地方,大家觉得这很没有必要,其实是有其原因的,这就是动态链接的过程。试想如果有人把GOT[5]的值改成了puts的绝对地址后,那么第16行的间接跳转不就直接到了puts的函数体了吗。
到了这里,大家可能有很多疑问,试列举如下:
1。第18行跳到.plt的第一项,然后第4行间接跳转到哪儿去了,干了些什么事情?
  答:这是动态链接的过程,本文后面要结合源码分析的,现在可以简单的说下,第4行的间接跳转到了ld-linux.so.2的_dl_runtime_resolve函数,这个函数解析出puts的绝对地址,回填到GOT[5],以达到前面所叙的效果。
2。为什么不一上来就把所有的库函数对应的GOT[]项全部填上函数的绝对地址?
  答:这是Linux系统设计的哲学之一,称之为LAZY的策略,即真正要用到某个东西时,我才为它构建好必要的环境,如这里的地址回填,又如COW机制。这是有性能考虑的,程序中可能会引用很多的库函数,但有很多库函数并不会真正执行到,如if (error){perror("err"); exit(errno);}的perror函数几乎不会执行,这样为这些不会执行的函数解析出绝对地址是没有必要的,也会增加时间的开销。
在puts函数执行了一次后,由于有动态链接的过程,GOT[5]就回填上了puts的绝对地址,请看下面
(gdb) n
helloworld
8 return 0;
(gdb) x/x 0x804a008
0x804a008 <_GLOBAL_OFFSET_TABLE_+20>: 0xb7edda60
(gdb) x/10i 0xb7edda60
0xb7edda60 <puts>: push   %ebp
0xb7edda61 <puts+
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值