重定位相关
示例代码:
/* 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;
}
编译生成可重定位文件a.o,b.o
gcc -c a.c b.c -m32 -fno-stack-protector # -fno-stack-protector 关闭栈检查
查看重定位文件a.o
root@A029129-PC:~/workspace/temp_dir# objdump -d a.o
a.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 83 ec 10 sub $0x10,%rsp
c: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
13: 48 8d 45 fc lea -0x4(%rbp),%rax
17: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 1e <main+0x1e>
1e: 48 89 c7 mov %rax,%rdi
21: b8 00 00 00 00 mov $0x0,%eax
26: e8 00 00 00 00 callq 2b <main+0x2b> # 使用0x00000000作为swap的暂存地址
2b: b8 00 00 00 00 mov $0x0,%eax
30: c9 leaveq
31: c3 retq
通过查看汇编代码发现:
在偏移地址为17处,编译器使用0x0作为暂时偏移,来获取shared数据。
在偏移地址为26处,编译器使用0x00000000作为暂时偏移,来调用swap函数。
使用连接器将a.o,b.o链接成ab
ld a.o b.o -e main -o ab
查看可执行文件ab
root@A029129-PC:~/workspace/temp_dir# objdump -d ab
ab: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <main>:
401000: f3 0f 1e fa endbr64
401004: 55 push %rbp
401005: 48 89 e5 mov %rsp,%rbp
401008: 48 83 ec 10 sub $0x10,%rsp
40100c: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
401013: 48 8d 45 fc lea -0x4(%rbp),%rax
401017: 48 8d 35 e2 2f 00 00 lea 0x2fe2(%rip),%rsi # 404000 <shared>
40101e: 48 89 c7 mov %rax,%rdi
401021: b8 00 00 00 00 mov $0x0,%eax
401026: e8 07 00 00 00 callq 401032 <swap>
40102b: b8 00 00 00 00 mov $0x0,%eax
401030: c9 leaveq
401031: c3 retq
0000000000401032 <swap>:
401032: f3 0f 1e fa endbr64
401036: 55 push %rbp
401037: 48 89 e5 mov %rsp,%rbp
40103a: 48 89 7d f8 mov %rdi,-0x8(%rbp)
40103e: 48 89 75 f0 mov %rsi,-0x10(%rbp)
401042: 48 8b 45 f8 mov -0x8(%rbp),%rax
......
查看偏移地址为401017,401026处代码发现,链接后的重定位符号都已被修正到正确的位置。
实现原理:
对于可重定位的ELF文件,每一个可重定位节都存在对应的保存其重定位信息的节,如代码段”.text“存在要被重定位的地方,那么会有一个相对应叫”.rel.text“的节。
查看重定位表
”.text“节中有两处需要重定位,地址与”a.o“中lea,call指令地址对应。
root@A029129-PC:~/workspace/temp_dir# objdump -r a.o
a.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
000000000000001a R_X86_64_PC32 shared-0x0000000000000004
0000000000000027 R_X86_64_PLT32 swap-0x0000000000000004
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
0000000000000020 R_X86_64_PC32 .text
在该重定位表中还标注了重定位类型,其对应的修正方法诸如:
| 宏定义 | 值 | 重定位修正方法 |
|---|---|---|
| R_386_32 | 1 | 绝对寻址修正 S + A |
| R_386_PC32 | 2 | 相对寻址修正 S + A - P |
A = 保存在被修正位置的值
P = 被修正的位置
S = 符号的实际地址
修正过程:
在链接器合并a.o和b.o文件时,会将相似的段合并并产生虚拟地址即上述修正方法中的S值,结合对应的修正方法即可对重定位符号地址进行修正。