1. 程式人生 > >可重定位的目標檔案phase1.o,在生成執行程式的過程中重定位的方法( 隨機段地址版)

可重定位的目標檔案phase1.o,在生成執行程式的過程中重定位的方法( 隨機段地址版)

可重定位的目標檔案phase1.o,在生成執行程式的過程中重定位的方法

隨機段地址版

gcc main.o phase1.o -o linkbomb1
連線時,在各個.o合併生成了執行程式linkbomb1後,要對linkbomb1進行重定位。

1.檢視phase1.o的重定位條目

$readelf -r phase1.o
Relocation section ‘.rela.text’ at offset 0x2b8 contains 2 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000007 000300000002 R_X86_64_PC32 0000000000000000 .data + 10
00000000000f 000c00000004 R_X86_64_PLT32 0000000000000000 puts - 4
Relocation section ‘.rela.data.rel.local’ at offset 0x2e8 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000000 000a00000001 R_X86_64_64 0000000000000000 do_phase + 0

$objdump -d -r phase1.o
Disassembly of section .text:
0000000000000000 <do_phase>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # b <do_phase+0xb>
7: R_X86_64_PC32 .data+0x10
b: 48 89 c7 mov %rax,%rdi
e: e8 00 00 00 00 callq 13 <do_phase+0x13>
f: R_X86_64_PLT32 puts-0x4
13: 90 nop
14: 5d pop %rbp
15: c3 retq

2.phase1.o中資料節.data的重定位
2.1 檢視資料節需要重定位的條目

$readelf -x.rel.data phase1.o
.rel.data
r1=00000000 00000000 01000000 0A000000 00000000 00000000
{
offset=0;
type=1; R_X86_64_64
sybmol=0a; do_phase
addend=0x0;
}
這個就是void (*phase)()=do_phase; 全域性變數phase被初始化為do_phase子程式的起始地址。
而do_phase的地址,只有連線生成執行程式linkbomb1後,各個text合併後,才能確定do_phase的地址,重新對這個變數phase賦初值。

2.2 確定需要重定位的資料位置和長度: 0, 8

$readelf -x.data.rel.local phase1.o
Hex dump of section ‘.data.rel.local’:
NOTE: This section has relocations against it, but these have NOT been applied to this dump.
0x00000000 00000000 00000000

2.3 生成執行程式linkbomb1時,可重定位專案的重定位方法:

phase1.o中.data節的重定位如下:
refptr=s+r1.offset=.data.rel.local節在linkbomb中的.data段的地址+r1.offset=0x201088+0=0x201088
0x201088=linkbomb的.data段地址+phase1.o的.data.rel.local節在此段的偏移 =0x0x201000+0x88
0x88=main.o+init.o+phase1.o等的資料.data佔的空間
*refptr=(unsigned long)(ADDR(r1.symbol)+r1.addend)==(0x0698 + 0x0)=0x0000000000000698

2.4 檢視已重定位的.data節

$readelf -x.data linkbomb1
Hex dump of section ‘.data’: .data段地址0x201000
0x00201000 00000000 00000000 08102000 00000000 … …
0x00201010 00000000 00000000 00000000 00000000 …
0x00201020 5a354a48 526a6970 47713774 70674263 Z5JHRjipGq7tpgBc
0x00201030 62474454 50755061 49514b4d 48517465 bGDTPuPaIQKMHQte
0x00201040 62724b09 33795178 774c4d74 6c346b78 brK.3yQxwLMtl4kx
0x00201050 65477766 73354255 345a6762 49334572 eGwfs5BU4ZgbI3Er
0x00201060 5461516a 63444634 4c596462 73425430 TaQjcDF4LYdbsBT0
0x00201070 57553447 4b6c7654 36737053 315a4b76 WU4GKlvT6spS1ZKv
0x00201080 20780000 00000000 98060000 00000000 x…

3.phase1.o程式碼節.text的重定位

init.o+main.o+phase1.o===>linkbomb1 各程式碼節需要合併成程式碼段

3.1 檢視.text程式碼節的重定位條目

$readelf -x.rel.text phase1.o
.rel.text
r1=07000000 00000000 02000000 03000000 10000000 00000000
{
offset=7;
type=0x02; R_X86_64_PC32
sybmol=3; .data 是本phase1.o的.data,與最後執行程式的.data不是一個,應加上偏移。
addend=0x10;
}
r2=0f000000 00000000 04000000 0c000000 fcffffff ffffffff
{
offset=0x0f;
type=4; R_X86_64_PLT32
sybmol=0x0c; puts
addend=-4;
}

3.2 反彙編.text程式碼節,進一步驗證重定位條目。

$objdump -d -r phase1.o
Disassembly of section .text:
0000000000000000 <do_phase>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # b <do_phase+0xb>
7: R_X86_64_PC32 .data+0x10
b: 48 89 c7 mov %rax,%rdi
e: e8 00 00 00 00 callq 13 <do_phase+0x13>
f: R_X86_64_PLT32 puts-0x4
13: 90 nop
14: 5d pop %rbp
15: c3 retq

3.3 確定phase1.o的程式碼節.text在linkbomb1中的起始地址

$ objdump -d linkbomb1
0000000000000698 <do_phase>:
698: 55 push %rbp
699: 48 89 e5 mov %rsp,%rbp
69c: 48 8d 05 91 09 20 00 lea 0x200991(%rip),%rax # 201034 <MBMlYcfY+0x14>
6a3: 48 89 c7 mov %rax,%rdi
6a6: e8 85 fe ff ff callq 530 [email protected]
6ab: 90 nop
6ac: 5d pop %rbp
6ad: c3 retq
6ae: 66 90 xchg %ax,%ax
do_phase是phase1.o中.text節的第一個函式,此地址就是.text地址

3.4 R_X86_64_PC32的重定位(R1):

refptr=s+r1.offset=<do_phase>地址+r1.offset=0x0698+0x07=0x069f
refaddr=ADDR(s)+r1.offset= 0x0698+0x07 == refptr
*refptr=(unsigned)(ADDR(r1.symbol)+r1.addend-refaddr)==0x201020+ 0x10 -0x069f = 0x200991
0x201020=是phase1.o中.data節,在linkbomb1的.data段的實際地址。

3.5 R_X86_64_PLT32的重定位(R2):

先計算要修改的地址refptr,再確定要寫入的內容*refptr:
refptr=s+r2.offset=0x0698+0x0f=0x06a7
s=在執行程式linkbomb1的text段(合併了各text節)中原來phase1.o的.text節需重定位地址=<do_phase>地址=0x0698
*refptr=(unsigned)(ADDR(r2.symbol)+r2.addend-refptr)==(0x0530-0x04 - 0x06a7 = 0xfe85

通過 objdump -d linkbomb1 或者 objdump -d -j .plt linkbomb1 檢視puts的地址
Disassembly of section .plt:
0000000000000520 <.plt>:
520: ff 35 9a 0a 20 00 pushq 0x200a9a(%rip) # 200fc0 <GLOBAL_OFFSET_TABLE+0x8>
526: ff 25 9c 0a 20 00 jmpq *0x200a9c(%rip) # 200fc8 <GLOBAL_OFFSET_TABLE+0x10>
52c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000000530 [email protected]:
530: ff 25 9a 0a 20 00 jmpq *0x200a9a(%rip) # 200fd0 <[email protected]_2.2.5>
536: 68 00 00 00 00 pushq $0x0
53b: e9 e0 ff ff ff jmpq 520 <.plt>