为什么生成的程序集mov edi变为堆栈上的变量?

时间:2019-04-07 20:01:53

标签: gcc assembly x86-64 calling-convention

我是汇编的新手,试图了解以下功能的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。   2.从以上所述,显然edi包含自变量。但是[rbp-0x4]起什么作用呢?为什么不只是mov eax, edi

谢谢!

1 个答案:

答案 0 :(得分:3)

  
      
  1. edi来自哪里?
  2.   
     

...从上面看,显然edi包含参数。

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

这些操作系统的所有编程语言都通过rdi中的第一个参数。结果(返回值)在rax中传递。

并且由于您的C编译器将int解释为32位,因此仅使用rdirax的低32位-edi和{{1} }。

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

  

但是rcx扮演什么角色?

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

即使在32位或64位代码中,编写使用rbp而不是rsp来寻址局部变量(在堆栈上)的编译器也更加困难。

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

  

为什么不只是num

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

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

mov eax, edi