为什么生成的程序集将 edi 移动到堆栈上的变量?

Abs*_*ful 1 assembly gcc x86-64 calling-convention

我是汇编的新手,试图了解以下函数的 objdump:

int nothing(int num) {
    return num;
}
Run Code Online (Sandbox Code Playgroud)

这是结果(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    
Run Code Online (Sandbox Code Playgroud)

我的问题是: 1.edi从哪里来?阅读一些介绍文档,我的印象是[rbp-0x4]将包含num. 2. 从上面可以看出,edi 显然包含了这个论点。但是,它[rbp-0x4]扮演什么角色呢?为什么不只是mov eax, edi

谢谢!

Mar*_*nau 5

  1. 哪里edi来的呢?

...从上面,显然edi包含论点。

这是调用约定(适用于 Linux 和许多其他操作系统):

这些操作系统的所有编程语言都在rdi. 结果(返回值)传入rax.

并且由于您的 C 编译器解释int为 32 位,因此仅使用rdi和的低 32 位rax- 即edieax

Windows 的编程语言在rcx...中传递第一个参数

但是,它[rbp-0x4]扮演什么角色呢?

rbp在这里使用主要有历史原因。在 16 位代码中(如 1980 年代和 1990 年代 PC 中使用的那样),无法使用sp寄存器(对应于rsp)对堆栈上的数据进行寻址。唯一允许在堆栈上轻松寻址值的bp寄存器是寄存器(对应于rbp)。

即使在 32 位或 64 位代码中,编写一个使用rsp而不是使用rbp.

编译器在知道 C 函数中做了什么之前会生成汇编代码的前 3 条指令。编译器将值放在堆栈上,因为您可以address = &num在代码中执行类似操作。然而,当num在寄存器中时这是不可能的,而只有当num位于内存中时才可能。

为什么不只是mov eax, edi

如果你告诉编译器优化代码,它会在生成第一条汇编指令之前先检查 C 函数的内容。它会发现不需要将值放入内存中。

在这种情况下,代码确实如下所示:

mov eax, edi
ret
Run Code Online (Sandbox Code Playgroud)