我试图了解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;
}
编译: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
重新定位表:(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
从这个answer我理解的是,offset是必须修改的文本部分的第一个字节。编译器事先不知道任何可重定位条目的位置,这就是为什么它创建了用00
填充的部分,这些部分将由链接器填充。如果我们看一下objdump
的输出,这个解释就可以理解了。第一个重定位的偏移量为0xd
,.text中的“第d个”字节是此行8b 05 00 00 00 00
中包含0的部分。
因此,链接器将在此位置填充arr
的地址。R_X86_64_PC32
表示“取符号值,加上加数并减去偏移量”。我不明白这个计算。他们所说的“符号价值”是什么意思?在小代码模型中,所有偏移量都是相对于指令指针(RIP)的。因此,对于行mov 0x0(%rip),%eax
,RIP值将是下一个指令地址(0x11
)。偏移量为0xd
,加数为0x18
。因此,如果我们将加数添加到RIP并减去偏移量(0x11 + 0x18 - 0xd
),则变为0x1c
,这是第7个整数(1 int = 4字节)。这是有意义的,因为该指令试图访问数组arr
中的第7个索引。我不明白的是
- RIP和
arr
之间的相对偏移是如何计算的。是链接器在链接时计算的东西吗?
1.为什么一定要32位?
1.什么是sym重定位表中的值是否表示?我假设这是符号在其部分中的相对位置。例如,arr
具有sym值0
,因为它是.bss部分中的第一个条目。arr_big
具有40
作为sym。值,因为它是40字节长arr
和arr2
之后的第二个条目,0x61ac0
作为sym。在arr_big和arr之后的值(40 + 100000字节)。
先谢谢你。
1条答案
按热度按时间ecfdbz9o1#
链接器将以图像基绝对地址(例如0x0040_0000)开始的部分存储到内存中。节**.text存储在0x0040_1000,.data存储在0x0040_2000。
symbolmain的值位于.text节中的偏移量0处,即0x0040_1000。
symbolarr的值位于.data节中的偏移量0处,即0x0040_2000。
只有这样,搬迁问题才能得到解决。
Offset Info Type Sym. Value Sym. Name + Addend
00000000000d 000300000002 R_X86_64_PC32 0000000000000000 arr + 18
Relocation.Info(2)告诉它的类型是 Program Counter relative 32bit field relocation in.textsection at offset 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>
它获取目标符号arrVA 0x0040_2000,减去字段偏移量0x0040_100d,加上加数0x18,然后将结果0x100B添加到编译器发出到指令体的任何内容(值0x0000000)。
CPU将把
mov 0x0(%rip),%eax
语句视为b: 8b 05 0b 10 00 00
,正如您在调试器中看到的那样。此指令的RIP为0x0040_1011,当您将32位imm值0x100b添加到RIP时,将从VA 0x0040_201c加载寄存器EAX,VA 0x0040_201c是arr**的第7个DWORD。1.什么是sym重定位表中的值是否表示?
为了方便起见,这是通过 readelf 从目标值+加数计算出来的信息,实际上它只是间接地作为Rela.Info的高dword包含在重定位记录中。以序数的形式转化为符号表。