关于以下小代码,它在另一篇关于结构体大小和正确对齐数据的帖子中有所说明:
struct
{
char Data1;
short Data2;
int Data3;
char Data4;
} x;
unsigned fun ( void )
{
x.Data1=1;
x.Data2=2;
x.Data3=3;
x.Data4=4;
return(sizeof(x));
}
我得到了相应的反汇编(使用64位)
0000000000000000 <fun>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: c6 05 00 00 00 00 01 movb $0x1,0x0(%rip) # b <fun+0xb>
b: 66 c7 05 00 00 00 00 movw $0x2,0x0(%rip) # 14 <fun+0x14>
12: 02 00
14: c7 05 00 00 00 00 03 movl $0x3,0x0(%rip) # 1e <fun+0x1e>
1b: 00 00 00
1e: c6 05 00 00 00 00 04 movb $0x4,0x0(%rip) # 25 <fun+0x25>
25: b8 0c 00 00 00 mov $0xc,%eax
2a: 5d pop %rbp
2b: c3 retq
我不知道如何计算右侧出现的术语,这似乎是使用本地变量地址
。此外,我不知道如何使用%rip寄存器
计算它。
您能否给出一个示例,显示%rip
和%rsp
或%rbp
之间的联系,即特别是在使用move
指令时计算地址时。
movb $0x4,0x0
将字节值4
存储到绝对地址0
的内存中。movb $0x4,0x0(%rip)
将字节值4
存储到绝对地址rip + 0
,即相对于 RIP 地址为0
的地方。这与使用其他寄存器进行寻址相同,例如movb $4,0(%edi)
。区别在于,rip
在评估时指向下一条指令的开头。因此,使用rip
进行相对寻址允许编译器生成“PIC”位置无关代码。然后,操作系统需要将数据和代码一起加载以保持它们相对于彼此的位置不变。 - Ped7grip
,您将无法确定数据的位置,并且您仍然需要加载rip
来查看代码的位置,并通过它来调整寻址。因此,让编译器+链接器使用类似于variable_x(%rip)
的助记符自动重新计算所有偏移量,可以使程序员更轻松地使代码与PIC兼容。通常以PIC兼容方式编译x86_64目标代码(在某些操作系统中,如Mac的OS X中是强制性的),而32位x86目标通常使用绝对代码,期望在内存中具有特定位置。 - Ped7grip
(当然是32位的eip
变体,64位的rip
在32位模式下不可用)。 - Ped7geip
寻址,所以代码使用call
调用本地函数来从堆栈(返回地址)读取代码位置(call
执行时的eip
值),然后使用这个值相对于代码位置来寻址数据。编译器的好处就在于它们不会忘记基础知识... ;) :D - Ped7g