1.源代碼(a.c
b.c
)
extern int shared;
int main()
{
int a = 100;
swap( &a, &shared );
return 0;
}
int shared = 1;
void swap( int *a, int *b )
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
結(jié)合$ readelf -S
和$ readelf -s
的輸出被环,可以獲取到兩個(gè)目標(biāo)文件的Section信息和symbol信息等
2.空間和地址分配
目標(biāo)文件a.o和b.o鏈接輸出可執(zhí)行文件ab糙及,它們的Section是如何合并到輸出文件中的?輸出文件和虛擬內(nèi)存中的地址和空間又是如何分配的筛欢?
- 相似段合并
- 空間與地址分配
掃描所有的目標(biāo)文件浸锨,獲取各個(gè)Section的長(zhǎng)度、屬性和位置版姑,收集符號(hào)表中的所有符號(hào)定義和符號(hào)引用柱搜;合并,計(jì)算出輸出文件中各個(gè)段合并后的位置和長(zhǎng)度剥险,并建立映射關(guān)系 $ ld a.o b.o -e main -o ab -melf_i386
- 空間與地址分配
$ objdump -h a.o b.o ab
a.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000002c 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000060 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000060 2**2
ALLOC
3 .comment 0000002b 00000000 00000000 00000060 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 0000008b 2**0
CONTENTS, READONLY
5 .eh_frame 00000038 00000000 00000000 0000008c 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
b.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000038 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 00000000 00000000 0000006c 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000070 2**2
ALLOC
3 .comment 0000002b 00000000 00000000 00000070 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 0000009b 2**0
CONTENTS, READONLY
5 .eh_frame 00000038 00000000 00000000 0000009c 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
ab: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000064 08048094 08048094 00000094 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .eh_frame 00000058 080480f8 080480f8 000000f8 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .data 00000004 08049150 08049150 00000150 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .comment 0000002a 00000000 00000000 00000154 2**0
CONTENTS, READONLY
從合并后的文件ab可以看出聪蘸,合并的各個(gè)段已經(jīng)在虛擬內(nèi)存中分配了地址(VMA)
- 符號(hào)地址的確定
- 符號(hào)解析與重定位
使用第一步收集到的所有信息,讀取輸入文件中的Section的數(shù)據(jù)表制、重定位信息健爬,進(jìn)行符號(hào)解析與重定位、調(diào)整代碼中的地址 - 經(jīng)過(guò)相似段合并過(guò)程么介,各個(gè)段在虛擬地址空間中的地址已經(jīng)確定了娜遵,各個(gè)符號(hào)定義 的地址也已經(jīng)確定了(段的虛擬地址加上符號(hào)定義的偏移量)
- 重定位過(guò)程是針對(duì)代碼中的符號(hào)引用的地址的修改
- 符號(hào)解析與重定位
$ objdump -d a.o ab 部分結(jié)果,主要是main函數(shù)
a.o: file format elf32-i386
Disassembly of section .text:
00000000 <main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 20 sub $0x20,%esp
9: c7 44 24 1c 64 00 00 movl $0x64,0x1c(%esp)
10: 00
11: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) 對(duì)shared變量的引用
18: 00
19: 8d 44 24 1c lea 0x1c(%esp),%eax
1d: 89 04 24 mov %eax,(%esp)
20: e8 fc ff ff ff call 21 <main+0x21> 對(duì)swap函數(shù)的調(diào)用
25: b8 00 00 00 00 mov $0x0,%eax
2a: c9 leave
2b: c3 ret
ab: file format elf32-i386
Disassembly of section .text:
08048094 <main>:
8048094: 55 push %ebp
8048095: 89 e5 mov %esp,%ebp
8048097: 83 e4 f0 and $0xfffffff0,%esp
804809a: 83 ec 20 sub $0x20,%esp
804809d: c7 44 24 1c 64 00 00 movl $0x64,0x1c(%esp)
80480a4: 00
80480a5: c7 44 24 04 50 91 04 movl $0x8049150,0x4(%esp) 對(duì)shared變量的地址引用&shared
80480ac: 08
80480ad: 8d 44 24 1c lea 0x1c(%esp),%eax
80480b1: 89 04 24 mov %eax,(%esp)
80480b4: e8 07 00 00 00 call 80480c0 <swap> 對(duì)swap函數(shù)的調(diào)用
80480b9: b8 00 00 00 00 mov $0x0,%eax
80480be: c9 leave
80480bf: c3 ret
c7 44 24 是movl指令夭拌,后邊的4個(gè)字節(jié)是地址魔熏,可以看到鏈接過(guò)程,對(duì)符號(hào)地址做了重定位修正
重定位過(guò)程的完成需要重定位表的協(xié)助鸽扁,.text
的重定位表是.rel.text
- 重定位表每一個(gè)表項(xiàng)的結(jié)構(gòu)體
typedef struct
{
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
} Elf32_Rel;
offset 代表相對(duì)于要修正的段的偏移地址蒜绽,r_info 包含了重定位符號(hào)的信息(符號(hào)表的下標(biāo))