动态链接库函数重定位与延迟绑定

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

void test() {
puts("First Puts");
printf("First Printf");
puts("Second Puts");
}

int main() {
test();
return 0;
}
1
2
3
kv@Eden:~/Code/Test$ gcc -g test.c -o test
kv@Eden:~/Code/Test$ ls
test test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
kv@Eden:~/Code/Test$ readelf -a test

...

Dynamic section at offset 0xe28 contains 24 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x400418
0x000000000000000d (FINI) 0x400644
0x0000000000000019 (INIT_ARRAY) 0x600e10
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x600e18
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x400298
0x0000000000000005 (STRTAB) 0x400330
0x0000000000000006 (SYMTAB) 0x4002b8
0x000000000000000a (STRSZ) 68 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x601000
0x0000000000000002 (PLTRELSZ) 96 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x4003b8
0x0000000000000007 (RELA) 0x4003a0
0x0000000000000008 (RELASZ) 24 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x400380
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x400374
0x0000000000000000 (NULL) 0x0

Relocation section '.rela.dyn' at offset 0x3a0 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000600ff8 000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

Relocation section '.rela.plt' at offset 0x3b8 contains 4 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0
000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf + 0
000000601028 000300000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
000000601030 000400000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0

...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
kv@Eden:~/Code/Test$ objdump -h test

Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000400238 0000000000400238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
...

9 .rela.plt 00000060 00000000004003b8 00000000004003b8 000003b8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
...

11 .plt 00000050 0000000000400440 0000000000400440 00000440 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .text 000001b2 0000000000400490 0000000000400490 00000490 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
...

20 .dynamic 000001d0 0000000000600e28 0000000000600e28 00000e28 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .got 00000008 0000000000600ff8 0000000000600ff8 00000ff8 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .got.plt 00000038 0000000000601000 0000000000601000 00001000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .data 00000010 0000000000601038 0000000000601038 00001038 2**3
CONTENTS, ALLOC, LOAD, DATA
24 .bss 00000008 0000000000601048 0000000000601048 00001048 2**0
ALLOC
...
1
2
3
4
5
6
7
8
9
kv@Eden:~/Code/Test$ objdump -R test

DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0000000000600ff8 R_X86_64_GLOB_DAT __gmon_start__
0000000000601018 R_X86_64_JUMP_SLOT puts
0000000000601020 R_X86_64_JUMP_SLOT printf
0000000000601028 R_X86_64_JUMP_SLOT __libc_start_main
0000000000601030 R_X86_64_JUMP_SLOT __gmon_start__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
kv@Eden:~/Code/Test$ objdump -d -j .plt test

Disassembly of section .plt:

0000000000400440 <puts@plt-0x10>:
400440: ff 35 c2 0b 20 00 pushq 0x200bc2(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
400446: ff 25 c4 0b 20 00 jmpq *0x200bc4(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
40044c: 0f 1f 40 00 nopl 0x0(%rax)

0000000000400450 <puts@plt>:
400450: ff 25 c2 0b 20 00 jmpq *0x200bc2(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
400456: 68 00 00 00 00 pushq $0x0
40045b: e9 e0 ff ff ff jmpq 400440 <_init+0x28>

0000000000400460 <printf@plt>:
400460: ff 25 ba 0b 20 00 jmpq *0x200bba(%rip) # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
400466: 68 01 00 00 00 pushq $0x1
40046b: e9 d0 ff ff ff jmpq 400440 <_init+0x28>

0000000000400470 <__libc_start_main@plt>:
400470: ff 25 b2 0b 20 00 jmpq *0x200bb2(%rip) # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
400476: 68 02 00 00 00 pushq $0x2
40047b: e9 c0 ff ff ff jmpq 400440 <_init+0x28>

0000000000400480 <__gmon_start__@plt>:
400480: ff 25 aa 0b 20 00 jmpq *0x200baa(%rip) # 601030 <_GLOBAL_OFFSET_TABLE_+0x30>
400486: 68 03 00 00 00 pushq $0x3
40048b: e9 b0 ff ff ff jmpq 400440 <_init+0x28>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
kv@Eden:~/Code/Test$ gdb test

(gdb) l
1 #include <stdio.h>
2
3 void test() {
4 puts("Start");
5 printf("First");
6 printf("Second");
7 }
8
9 int main() {
10 test();
(gdb) b 4
Breakpoint 1 at 0x40058a: file test.c, line 4.
(gdb) b 5
Breakpoint 2 at 0x400594: file test.c, line 5.
(gdb) b 6
Breakpoint 3 at 0x4005a3: file test.c, line 6.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) r
Starting program: /home/kv/Code/Test/test

Breakpoint 1, test () at test.c:4
4 puts("First Puts");
(gdb) disas test
Dump of assembler code for function test:
0x0000000000400586 <+0>: push %rbp
0x0000000000400587 <+1>: mov %rsp,%rbp
=> 0x000000000040058a <+4>: mov $0x400654,%edi
0x000000000040058f <+9>: callq 0x400450 <puts@plt>
0x0000000000400594 <+14>: mov $0x40065f,%edi
0x0000000000400599 <+19>: mov $0x0,%eax
0x000000000040059e <+24>: callq 0x400460 <printf@plt>
0x00000000004005a3 <+29>: mov $0x40066c,%edi
0x00000000004005a8 <+34>: callq 0x400450 <puts@plt>
0x00000000004005ad <+39>: pop %rbp
0x00000000004005ae <+40>: retq
End of assembler dump.
1
2
3
4
5
6
7
8
(gdb) x /3i 0x400450
0x400450 <puts@plt>: jmpq *0x200bc2(%rip) # 0x601018 <puts@got.plt>
0x400456 <puts@plt+6>: pushq $0x0
0x40045b <puts@plt+11>: jmpq 0x400440
(gdb) x /3i 0x400460
0x400460 <printf@plt>: jmpq *0x200bba(%rip) # 0x601020 <printf@got.plt>
0x400466 <printf@plt+6>: pushq $0x1
0x40046b <printf@plt+11>: jmpq 0x400440
1
2
3
4
(gdb) x /2x 0x601018
0x601018 <puts@got.plt>: 0x00400456 0x00000000
(gdb) x /2x 0x601020
0x601020 <printf@got.plt>: 0x00400466 0x00000000
1
2
3
4
(gdb) x /3i 0x400440
0x400440: pushq 0x200bc2(%rip) # 0x601008
0x400446: jmpq *0x200bc4(%rip) # 0x601010
0x40044c: nopl 0x0(%rax)
1
2
(gdb) x /4x 0x601008
0x601008: 0xf7ffe188 0x00007fff 0xf7defed0 0x00007fff
1
2
3
4
5
6
7
(gdb) b *0x400446
Breakpoint 4 at 0x400446
(gdb) c
Continuing.
Breakpoint 4, 0x0000000000400446 in ?? ()
(gdb) ni
_dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:58
1
2
3
4
5
6
7
8
9
10
11
12
(gdb) c
Continuing.
First Puts
Breakpoint 2, test () at test.c:5
5 printf("First Printf");
(gdb) c
Continuing.
Breakpoint 4, 0x0000000000400446 in ?? ()
(gdb) c
Continuing.
Breakpoint 3, test () at test.c:6
6 puts("Second Puts");
1
2
(gdb) x /2x 0x601018
0x601018 <puts@got.plt>: 0xf7a7fa30 0x00007fff

plt:位于代码段,函数相关,实现延迟绑定功能。
got:位于数据段,变量相关,实现位置无关代码功能。
got.plt:位于在数据段,函数相关,实现位置无关代码功能。