elf文件查找函数的过程

要反编译的程序:hello.c

#include<stdio.h>
int main()
{
printf(“Hello World!/n”);
return 0;
}

1.对hello进行反汇编,并查找包含”printf”的行;
可以看到它调用了地址0x80482b0的函数;
[root@localhost src]# objdump -d hello | grep printf
080482b0 <printf@plt>:
804838c: e8 1f ff ff ff call 80482b0 <printf@plt>

2.对hello的.got.plt部分进行反汇编;
[root@localhost src]# objdump -d -j .got.plt hello

hello: file format elf32-i386

Disassembly of section .got.plt:

08049570 <_GLOBAL_OFFSET_TABLE_>:
8049570: a4 94 04 08 00 00 00 00 00 00 00 00 a6 82 04 08 …………….
8049580: b6 82 04 08

3.对hello进行反汇编,并查找包含”.rel.plt”的行;
[root@localhost src]# objdump -s hello | grep .rel.plt -A3
Contents of section .rel.plt:
8048268 7c950408 07010000 80950408 07020000 |……………
Contents of section .init:
8048278 5589e583 ec08e861 000000e8 b4000000 U……a……..

4.显示所有的Section,并查找包含.got.plt 的行;
[root@localhost src]# readelf -S hello | grep .got.plt
[21] .got.plt PROGBITS 08049570 000570 000014 04 WA 0 0 4

5.对hello的plt部分进行反汇编,可以看到地址0x80482b0 处的汇编代码,
jmp 0x8049580 语句的意思是跳转到got,从第二步可以看到,它跳到了got中;
got中的内容为b6 82 04 08 ,它的小字节序是08 04 82 b6;
地址0x080482b又是plt中的push $0x8,0x8是在重定向表中的偏移量,可以从第三步看到;
jmp 8048290 <_init+0x18> 又跳到了plt的开头;
pushl 0x8049574 0x8049574位于got中;
jmp
0x8049578 然后调用位于0x8049578 的东西,但是该位置是零。

[root@localhost src]# objdump -d -j .plt hello

hello: file format elf32-i386

Disassembly of section .plt:

08048290 <__libc_start_main@plt-0x10>:
8048290: ff 35 74 95 04 08 pushl 0x8049574
8048296: ff 25 78 95 04 08 jmp *0x8049578
804829c: 00 00 add %al,(%eax)

080482a0 <__libc_start_main@plt>:
80482a0: ff 25 7c 95 04 08 jmp *0x804957c
80482a6: 68 00 00 00 00 push $0x0
80482ab: e9 e0 ff ff ff jmp 8048290 <_init+0x18>

080482b0 <printf@plt>:
80482b0: ff 25 80 95 04 08 jmp *0x8049580
80482b6: 68 08 00 00 00 push $0x8
80482bb: e9 d0 ff ff ff jmp 8048290 <_init+0x18>
….
这个过程叫做懒惰链接,因为重定向只发生在运行并且需要时,只要链接器完成了第一次查找,
链接器将会修改got表项,使得调用plt中的函数时,直接跳到got中,再跳到真正的函数哪里,而不是像
上面那样回到plt中,将重定向表中的偏移量入栈。

参考1:http://em386.blogspot.com/2006/10/resolving-elf-relocation-name-
symbols.html