分类: LINUX
2009-06-28 13:22:19
3.5节的补充说明和例子:
静态全局变量的重定位过程和在文件中的存放位置。
内存变量有2个基本属性:变量的地址 和 变量的内容。编译器+汇编器 加工产出的文件包含1系列汇编语句代码, 包括 .text + .data + .bss,但有很多不确定的地址:主要有2部分地址需要确定:1。符号(即变量/函数名字)本身的偏移量是多少 2。符号里的内容如果是个地址,要确定该地址是多少。因此编译器把一些中间结果记录在一些辅助的section里。让连接器继续重定位,连接器如果还是定位不出具体地址,就把中间结果记录下来,让加载器继续重定位。
1。.so 里的汇编指令地址,都是记录的偏移量。.exe里的汇编指令地址,基本都是确定的虚拟内存地址,需要重定位的内容很少。
2。符号本身(在文件内)的偏移量。在编译/连接时就可以计算,因此直接记录在.symtab里,连接时要继续修改.symtab。编译器(汇编器)和连接器主要使用.symtab记录符号偏移量。动态加载器所需要确定的符号,很多都放在到.dynsym里,.symtab不那么重要了。
3。.text和.data里的符号里所包含的"内容"可能需要重定位计算。如果内容是1个地址,那么就是需要重定位的。因此分别会产生 .rel.text 和 .rel.dataxxx section,表示说:嗨!注意,这些符号里的内容是地址,要进行重定位计算。如果符号里的“内容”是1个常量,则一般连接器ld直接能计算出来,不必要重定位。
4。加载运行时,.data 内容先重定位(在main()之前),然后再对 .text 内容再重定位。
5。实际例子:
思路:(1)选取1个符号,先研究.o里的重定位项(供连接器使用),然后再研究.so里的重定位项(供动态加载器使用)。
(2)在.o里面,先找符号表,找到符号所在的section和偏移量 --> 再研究符号对应的重定位表项目
(3)研究的工具是:objdump和readelf.
例子:我们研究全局静态指针变量:static char *p222 = "aaaaaaaaaa";
[elf@redhat elf]# more bbb.c
int a111 = 15;
char *g111;
char *g222 = "456";
static char *p111;
static char *p222 = "aaaaaaaaaa";
static char *p333;
static char *p444 = "bbbb";
int foo2()
{
p333 = "cc";
char *p555 = "dd";
static char *p666= "123";
p111 = (char *)malloc(10);
strcpy(p111, "13579");
}
(一) 首先编译出位置无关代码:bbb.o
[elf@redhat elf]# gcc -fPIC -c bbb.c
(1)先在符号表里找到p222
[elf@redhat elf]# readelf -a bbb.o
Symbol table '.symtab' contains 21 entries: # 符号表记录所有符号本身的偏移值
Num: Value Size Type Bind
7: 00000004 4 OBJECT LOCAL DEFAULT 6 p222 # p222 所在节号为 6(.data.rel.local section),节内偏移量为4
(2)察看p222对应的重定位项目:
[elf@redhat elf]# readelf -a bbb.o
Relocation section '.rel.data.rel.local' at offset 0x558 contains 4 entries:
Offset Info Type Sym.Value Sym. Name
00000004 00000501 R_386_32 00000000 .rodata # 表示.rel.data.rel节中 偏移4处的内容是一个地址,此地址和.rodata相关,目前不能最终确定,需要继续重定位。
# 编译器产生此重定位项,表示自己不能确定出p222的最终地址,让连接器使用此信息继续完成重定位,一棒接一棒接力完成最终地址的重定
位。
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000058 00 AX 0 0 4
[ 2] .rel.text REL 00000000 000510 000048 08 11 1 4
[ 3] .data PROGBITS 00000000
[ 4] .bss NOBITS 00000000 000090 000008 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000090 000024
[ 6] .data.rel.local PROGBITS 00000000 0000b4 000010 00 WA 0 0 4
[ 7] .rel.data.rel.loc REL 00000000 000558 000020 08 11 6 4
[ 8] .note.GNU-stack NOTE 00000000
[ 9] .comment PROGBITS 00000000
[10] .shstrtab STRTAB 00000000
[11] .symtab SYMTAB 00000000 000364 000150 10 12 e 4
[12] .strtab STRTAB 00000000 0004b4
# .rel.data.rel.loc需要重定位的符号所在的符号表为11(.symtab section), 需要重定位的节号为6(.data.rel.local section)
(3)察看各个节包含的实际内容
[elf@redhat elf]# objdump -s bbb.o
Contents of section .data:
0000
Contents of section .rodata:
0000 34353600 61616161 61616161 61610062 456.aaaaaaaaaa.b
0010 62626200 31323300 63630064 64003133 bbb.123.cc.dd.13
0020 35373900 579.
Contents of section .data.rel.local:
0000 00000000 04000000
# 可以看到:
全局普通变量int a111=15=0f 直接存放在.data里。以后的连接过程中: .data section的位置会发生改变,int a111变量本身的地址需要随之重定位修改,但a111里面包含的内容(0f)是不会改变的。
.data.rel.local section里,存放4个指针变量:*g222 = 00; *p222 = 04; *p444 =
4个指针变量只是 临时存放在:.data.rel.local等待重定位处理。以后的连接过程中: .data section的位置会发生改变,4个指针变量本身的地址需要随之重定位修改;而且由于.rodata section的位置也会发生改变,指针变量里面包含的偏移量是指向.rodata的,也要进行重定位计算,并最终把4个指针变量存放在.data里面。
char *g222 = "456";
static char *p222 = "aaaaaaaaaa";
static char *p444 = "bbbb";
static char *p666= "123";
(二) 然后连接为bbb.so
[elf@redhat elf]# gcc -shared -o bbb.so ./bbb.o
(1)先在符号表找到p222
[elf@redhat elf]# readelf -a bbb.so
Symbol table '.symtab' contains 64 entries:
Num: Value Size Type Bind
42: 00001808 4 OBJECT LOCAL DEFAULT 14 p222 # p222 所在节号为 14(.data section),节内偏移量为 1808; 而且.dynsym里没有p222符号,说明静态变量不记录在.dynsym里,.dynsym只记录全局符号。
(2)重定位已经完成,不需要动态加载器继续重定位了,所以没有相关的重定位项了。
(3)察看各个节包含的实际内容
[elf@redhat elf]# objdump -s bbb.o
Contents of section .rodata:
07cf 34353600 61616161 61616161 61610062 456.aaaaaaaaaa.b
07df 62626200 31323300 63630064 64003133 bbb.123.cc.dd.13
07ef 35373900 579.
Contents of section .data:
1808 d3070000 de070000 e3070000 ............ # 偏移1808处的内容是000007d3
# 可以看到:程序连接后,.rodata 位置发生改变,开始地址变为:07cf;.data 位置发生改变,开始地址变为:
====================================================================
实际输出:
[elf@redhat elf]# readelf -a bbb.o
ELF Header:
Magic:
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 348 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 13
Section header string table index: 10
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000058 00 AX 0 0 4
[ 2] .rel.text REL 00000000 000510 000048 08 11 1 4
[ 3] .data PROGBITS 00000000
[ 4] .bss NOBITS 00000000 000090 000008 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000090 000024
[ 6] .data.rel.local PROGBITS 00000000 0000b4 000010 00 WA 0 0 4
[ 7] .rel.data.rel.loc REL 00000000 000558 000020 08 11 6 4
[ 8] .note.GNU-stack NOTE 00000000
[ 9] .comment PROGBITS 00000000
[10] .shstrtab STRTAB 00000000
[11] .symtab SYMTAB 00000000 000364 000150 10 12 e 4
[12] .strtab STRTAB 00000000 0004b4
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no program headers in this file.
Relocation section '.rel.text' at offset 0x510 contains 9 entries:
Offset Info Type Sym.Value Sym. Name
00000015 00000509 R_386_GOTOFF 00000000 .rodata
0000001b 00000409 R_386_GOTOFF 00000000 .bss
00000021 00000509 R_386_GOTOFF 00000000 .rodata
0000002e 00001204 R_386_PLT32 00000000 malloc
00000037 00000409 R_386_GOTOFF 00000000 .bss
00000040 00000509 R_386_GOTOFF 00000000 .rodata
00000047 00000409 R_386_GOTOFF 00000000 .bss
Relocation section '.rel.data.rel.local' at offset 0x558 contains 4 entries:
Offset Info Type Sym.Value Sym. Name
00000000 00000501 R_386_32 00000000 .rodata
00000004 00000501 R_386_32 00000000 .rodata
00000008 00000501 R_386_32 00000000 .rodata
There are no unwind sections in this file.
Symbol table '.symtab' contains 21 entries: # 符号表记录所有符号本身的偏移
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS bbb.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000004 4 OBJECT LOCAL DEFAULT 6 p222 # 比如 p222 所在section为 6(.data.rel.local),偏移为 4
8: 00000008 4 OBJECT LOCAL DEFAULT 6 p444 # 比如 p444 所在section为 6(.data.rel.local),偏移为 8
9:
10: 00000004 4 OBJECT LOCAL DEFAULT 4 p333 # 比如 p333 所在section为 4(.bss),偏移为 4
11: 00000000 4 OBJECT LOCAL DEFAULT 4 p111
12: 00000000 0 SECTION LOCAL DEFAULT 8
13: 00000000 0 SECTION LOCAL DEFAULT 9
14: 00000000 4 OBJECT GLOBAL DEFAULT
15: 00000000 4 OBJECT GLOBAL DEFAULT
16: 00000000 88 FUNC GLOBAL DEFAULT 1 foo2
17: 00000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
18: 00000000 0 NOTYPE GLOBAL DEFAULT UND malloc
19: 00000000 0 NOTYPE GLOBAL DEFAULT UND strcpy
20: 00000004 4 OBJECT GLOBAL DEFAULT COM g111
No version information found in this file.
[elf@redhat elf]# objdump -s bbb.o
bbb.o: file format elf32-i386
Contents of section .text:
0000 5589e553 83ec04e8 00000000 5b
0010 0000008d 83180000 00898304 0000008d ................
0020 831b0000
0030 ffff
0040 1e000000 50ffb300 000000e8 fcffffff ....P...........
0050
Contents of section .data:
0000
Contents of section .rodata:
0000 34353600 61616161 61616161 61610062 456.aaaaaaaaaa.b
0010 62626200 31323300 63630064 64003133 bbb.123.cc.dd.13
0020 35373900 579.
Contents of section .data.rel.local:
0000 00000000 04000000
Contents of section .note.GNU-stack:
Contents of section .comment:
0000 00474343
0010 33203230 30333035 30322028 54757262 3 20030502 (Turb
0020
0030 00 .
[elf@redhat elf]# objdump -d bbb.o
bbb.o: file format elf32-i386
Disassembly of section .text:
00000000
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 53 push %ebx
4: 83 ec 04 sub $0x4,%esp
7: e8 00 00 00 00 call c
c: 5b pop %ebx
d:
13: 8d 83 18 00 00 00 lea 0x18(%ebx),%eax
19: 89 83 04 00 00 00 mov %eax,0x4(%ebx)
25: 89
28: 83 ec
2b:
2d: e8 fc ff ff ff call 2e
32:
35: 89 83 00 00 00 00 mov %eax,0x0(%ebx)
3b: 83 ec 08 sub $0x8,%esp
3e: 8d 83 1e 00 00 00 lea 0x1e(%ebx),%eax
44: 50 push %eax
45: ff b3 00 00 00 00 pushl 0x0(%ebx)
4b: e8 fc ff ff ff call
50:
53: 8b 5d fc mov 0xfffffffc(%ebp),%ebx
56: c9 leave
57: c3 ret
================================================================
================================================================
对比一下,*.o和*.so在不同连接阶段的变化。
[elf@redhat elf]# objdump -s bbb.so
[elf@redhat elf]# objdump -d bbb.so