- /*a.c*/
- extern int shared;
-
- int main()
- {
- int a = 100 ;
- swap( &a , &shared);
- }
- /*b.c*/
- int shared = 1;
-
- void swap( int *a , int * b)
- {
- *a^=*b^=*a^=*b;
- }
编译:
链接:
得到链接前后各个段的属性:
- Idx Name Size VMA LMA File off Algn
- 0 .text 00000027 00000000 00000000 00000034 2**2
- CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
- 1 .data 00000000 00000000 00000000 0000005c 2**2
- CONTENTS, ALLOC, LOAD, DATA
- 2 .bss 00000000 00000000 00000000 0000005c 2**2
- ALLOC
- 3 .comment 00000026 00000000 00000000 0000005c 2**0
- CONTENTS, READONLY
- 4 .note.GNU-stack 00000000 00000000 00000000 00000082 2**0
- CONTENTS, READONLY
-
- Sections:
- Idx Name Size VMA LMA File off Algn
- 0 .text 0000003a 00000000 00000000 00000034 2**2
- CONTENTS, ALLOC, LOAD, READONLY, CODE
- 1 .data 00000004 00000000 00000000 00000070 2**2
- CONTENTS, ALLOC, LOAD, DATA
- 2 .bss 00000000 00000000 00000000 00000074 2**2
- ALLOC
- 3 .comment 00000026 00000000 00000000 00000074 2**0
- CONTENTS, READONLY
- 4 .note.GNU-stack 00000000 00000000 00000000 0000009a 2**0
- CONTENTS, READONLY
- Sections:
- Idx Name Size VMA LMA File off Algn
- 0 .text 00000062 08048094 08048094 00000094 2**2
- CONTENTS, ALLOC, LOAD, READONLY, CODE
- 1 .data 00000004 080490f8 080490f8 000000f8 2**2
- CONTENTS, ALLOC, LOAD, DATA
- 2 .comment 00000025 00000000 00000000 000000fc 2**0
- CONTENTS, READONLY
链接的第一步就是空间与地址分配,扫描所有的输入目标文件,获得它们的各个段的长度、属性和位置。
将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个全局符号表。
(这一步中,链接器将能够获得所有输入目标文件的段的长度,并且将它们合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系)
我们分别对a.o b.o 和ab的代码段进行反汇编,可以看到重定位的结果(swap不需要重定位,是没有变化的)
(1) main被映射到08048094,原因是Linux默认的ref映射是从08048000,而代码段的起始地址是08048094
(2) &share是0x080490f8
(3) swap的调用从-4(没有从定位的地址均设置为-4)变为了03,因为在ab中,swap的地址已经知道了(就在main函数的后面),就在3个字节之后
重定位的过程如下,
(1) 搜集重定位信息(b.o中没有重定位信息)
我们根据段表信息找到rel.text(代码段重定位)
在代码段中的位置 类型 在symtab 中的idx
- 15 00 00 00 01 08 00 00
- 21 00 00 00 02 09 00 00
objdump -r a.o 可以直接得到有用的信息
- RELOCATION RECORDS FOR [.text]:
- OFFSET TYPE VALUE
- 00000015 R_386_32 shared
- 00000021 R_386_PC32 swap
拿到在symtab 中的idx 可以到symtab去查询,就是最后两个 UND的符号需要重定位
- Num: Value Size Type Bind Vis Ndx Name
- 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
- 1: 00000000 0 FILE LOCAL DEFAULT ABS a.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 6
- 6: 00000000 0 SECTION LOCAL DEFAULT 5
- 7: 00000000 39 FUNC GLOBAL DEFAULT 1 main
- 8: 00000000 0 NOTYPE GLOBAL DEFAULT UND shared
- 9: 00000000 0 NOTYPE GLOBAL DEFAULT UND swap
现在我们就可以进行修改了,首先是位于代码段offset为0x15的地方,修改方式是R_386_32,即绝对寻址修正
修正值 = 原始值 + 在可执行文件中的实际地址
然后是offset为0x21的地方,修改方式为R_386_PC32 ,即相对寻址修正
修正值 = 原始值 + 相关符号可执行文件分配到的虚拟地址 - 原始值在可执行文件分配到的虚拟地址
(相关符号可执行文件分配到的虚拟地址 - 原始值在可执行文件分配到的虚拟地址 实际就是在代码段中相距的位置)
|