重定位符号信息

166 阅读3分钟

重定位相关

示例代码:

/* 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-64RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
000000000000001a R_X86_64_PC32     shared-0x0000000000000004
0000000000000027 R_X86_64_PLT32    swap-0x0000000000000004RELOCATION RECORDS FOR [.eh_frame]:
OFFSET           TYPE              VALUE
0000000000000020 R_X86_64_PC32     .text

在该重定位表中还标注了重定位类型,其对应的修正方法诸如:

宏定义重定位修正方法
R_386_321绝对寻址修正 S + A
R_386_PC322相对寻址修正 S + A - P

A = 保存在被修正位置的值

P = 被修正的位置

S = 符号的实际地址

修正过程:

在链接器合并a.ob.o文件时,会将相似的段合并并产生虚拟地址即上述修正方法中的S值,结合对应的修正方法即可对重定位符号地址进行修正。