所以,我最近开始了解x86汇编语言。 我创建了以下C ++代码的目标文件,并使用objdump -S查看创建的.o文件。
void func(){
int d,f;
d=10;
f=1;
}
int main(){
int x;
x = 1;
}
我得到了以下汇编代码:
t1.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <_Z4funcv>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%rbp)
b: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
12: 5d pop %rbp
13: c3 retq
0000000000000014 <main>:
14: 55 push %rbp
15: 48 89 e5 mov %rsp,%rbp
18: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
1f: b8 00 00 00 00 mov $0x0,%eax
24: 5d pop %rbp
25: c3 retq
有人可以使用汇编代码指令做什么吗?我知道push和pop用于存储和从堆栈中删除。但是教学的确切用途是什么?
答案 0 :(得分:3)
调用约定要求保留哪些寄存器,包括rbp
。这意味着,如果您的函数想要将rbp
用于其自身目的,则必须确保它在函数出口处保持与在函数入口处相同的值。实现此目的的便捷方法是push
和pop
。
rbp
用于什么?从历史上看,bp
寄存器用于标记堆栈帧并访问局部变量和函数参数。其中一个原因是在旧的16位代码中,您无法相对于堆栈指针sp
进行寻址。此外,了解堆栈帧边界可能有助于调试和堆栈展开。在32位和现在的64位代码中,您可以相对于堆栈指针进行寻址,并且调试由专门的调试信息辅助,即使没有帧指针也能正常工作。因此,通常的做法是禁用帧指针,有效地释放一个寄存器以供一般使用。此代码尚未在启用优化的情况下编译,这就是您使用rbp
的原因。
好的,让我们看看发生了什么。如上所述,行0
保存rbp
。然后,行1
将堆栈指针的当前值保存在那里,标记堆栈帧。行4
和b
只是初始化您的两个变量。请注意,它们位于堆栈指针下的128字节红色区域中,x86-64 ABI允许您在不分配的情况下使用它。通常,您会看到sub rsp, size-of-locals
种用于从堆栈中分配空间的指令。行12
恢复rbp
的原始值,最后行13
返回给调用者。
main
函数非常相似,唯一有趣的区别在于1f
,它将0
加载到eax
。该寄存器用于将返回值传递回调用者。
这只是对调用约定主题的快速浏览。有关更深入的详细信息,请参阅相应的文档。