我是装配试图理解以下函数的objdump的新手:
int nothing(int num) {
return num;
}
这是结果(linux,x86-64,gcc 8):
push rbp
mov rbp,rsp
mov DWORD PTR [rbp-0x4],edi
mov eax,DWORD PTR [rbp-0x4]
pop rbp
ret
我的问题是:1。edi
来自哪里?通过一些介绍文档阅读,我的印象是[rbp-0x4]
将包含num
。从上面看,显然edi包含了这个论点。但那么[rbp-0x4]
扮演什么角色?为什么不只是mov eax, edi
?
谢谢!
edi
来自哪里?......从上面看,显然edi包含了这个论点。
这是调用约定(适用于Linux和许多其他操作系统):
这些操作系统的所有编程语言都传递了rdi
中的第一个参数。结果(返回的值)在rax
中传递。
并且因为你的C编译器将int
解释为32位,所以只使用rdi
和rax
的低32位 - 这是edi
和eax
。
Windows的编程语言传递rcx
中的第一个参数...
但那么
[rbp-0x4]
扮演什么角色?
使用rbp
主要是历史原因。在16位代码中(因为它在20世纪80年代和90年代的PC中使用),使用sp
寄存器(对应于rsp
)无法在堆栈上寻址数据。允许在堆栈上寻址值的唯一寄存器是bp
寄存器(对应于rbp
)。
即使在32位或64位代码中,编写使用rsp
而不是使用rbp
来解决局部变量(在堆栈上)的编译器也更加困难。
编译器在知道C函数中的操作之前,会生成汇编代码的前3条指令。编译器将值放在堆栈上,因为您可以在代码中执行类似address = &num
的操作。然而,当num
在寄存器中但仅当num
位于存储器中时,这是不可能的。
为什么不只是
mov eax, edi
?
如果告诉编译器优化代码,它将在生成第一个汇编程序指令之前首先检查C函数的内容。它会发现不需要将值放入内存中。
在这种情况下,代码确实如下所示:
mov eax, edi
ret