Ric*_*cky 5 c++ assembly x86-64 abi relocation
我试图了解小代码模型中使用的 RIP 相对偏移量。也许互联网上有关此主题的唯一可用资源是: https: //eli.thegreenplace.net/2012/01/03/understanding-the-x64-code-models 但在这篇文章中也有一些事情不清楚。我使用这个简单的程序来了解一些事情:
// sample.cc
int arr[10] = {0};
int arr_big[100000] = {0};
int arr2[500] = {0};
int main() {
int t = 0;
t += arr[7];
t +=arr_big[6];
t += arr2[10];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
汇编:g++ -c sample.cc -o sample.o
.text 部分的目标代码:( objdump -dS sample.o)
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
b: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 11 <main+0x11>
11: 01 45 fc add %eax,-0x4(%rbp)
14: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 1a <main+0x1a>
1a: 01 45 fc add %eax,-0x4(%rbp)
1d: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 23 <main+0x23>
23: 01 45 fc add %eax,-0x4(%rbp)
26: b8 00 00 00 00 mov $0x0,%eax
2b: 5d pop %rbp
2c: c3 ret
Run Code Online (Sandbox Code Playgroud)
重定位表:( readelf -r sample.o)
Relocation section '.rela.text' at offset 0x1a8 contains 3 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000000000d 000300000002 R_X86_64_PC32 0000000000000000 arr + 18
000000000016 000400000002 R_X86_64_PC32 0000000000000040 arr_big + 14
00000000001f 000500000002 R_X86_64_PC32 0000000000061ac0 arr2 + 24
Run Code Online (Sandbox Code Playgroud)
从这个答案中我了解到,偏移量是必须修改的文本部分的第一个字节。编译器事先不知道任何可重定位条目的位置,这就是为什么它创建00将由链接器填充的部分。一旦我们查看输出,这个解释就可以理解objdump。第一个重定位有偏移量0xd,.text 中的“第 d”字节是该行中包含 0 的部分8b 05 00 00 00 00。
因此,链接器将在该位置填充 的地址arr。R_X86_64_PC32意思是“取符号值,加上加数并减去偏移量”。我不明白这个计算。“符号价值”是什么意思?在小代码模型中,所有偏移量都将相对于指令指针(RIP)。因此,对于行mov 0x0(%rip),%eax,RIP 值将是下一条指令地址 ( 0x11)。偏移量为0xd,加数为0x18。因此,如果我们将加数添加到 RIP 并减去偏移量 ( 0x11 + 0x18 - 0xd),则它变为0x1c第 7 个整数(1 int = 4 字节)。这是有道理的,因为该指令正在尝试访问 array 中的第七个索引arr。我不明白的是:
arr计算的。它是由链接器在链接时计算的吗?arr具有 sym 值0,因为它是 .bss 部分中的第一个条目。arr_big有40作为符号。值,因为它是 40 字节长后的第二个条目arr,并且arr2具有0x61ac0sym。arr_big 和 arr 之后的值(40 + 100000 字节)。提前致谢。
链接器将段存储到以图像基址绝对地址(例如 0x0040_0000)开始的内存中。.text节存储在 0x0040_1000 处,.data 节存储 在 0x0040_2000 处。符号main
的值位于.text节中的偏移量 0 处,即 0x0040_1000。符号arr
的值位于.data节中的偏移量 0 处,即 0x0040_2000。
只有这样,搬迁问题才能得到解决。
Offset Info Type Sym. Value Sym. Name + Addend
00000000000d 000300000002 R_X86_64_PC32 0000000000000000 arr + 18
Relocation.Info(2)告诉我们它的类型是程序计数器相对32位字段重定位在.text节中偏移量0xd处,所以它的绝对虚拟地址(VA)是0x0040_100d。
Relocation.Info (3) 表明它与符号表中的第 3 项相关,该项代表VA 0x0040_2000 的.data节。
了解所有符号的最终地址后,链接器现在可以执行计算。
在上面提到的语句中,
b: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 11 <main+0x11>
它采用目标符号arr VA 0x0040_2000,减去字段偏移量 0x0040_100d,添加加数 0x18,然后将结果 0x100B 添加到编译器向指令体发出的任何内容(值 0x00000000)。
CPU 会将语句视为mov 0x0(%rip),%eax,b: 8b 05 0b 10 00 00正如您在调试器中看到的那样。该指令的 RIP 是 0x0040_1011,当您将 32 位 imm 值 0x100b 添加到 RIP 时,寄存器 EAX 将从 VA 0x0040_201c 加载,这是arr的第 7 个 DWORD 。
- sym. 是什么意思?重定位表中的值表示什么?
这是readelf为了方便起见,由目标值+加数计算出来的信息,实际上它只是作为Rela.Info的高位双字间接包含在重定位记录中。以序数的形式存入符号表。