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

问题描述 投票:0回答:1

我是装配试图理解以下函数的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

谢谢!

gcc assembly x86-64 calling-convention
1个回答
3
投票
  1. edi来自哪里?

......从上面看,显然edi包含了这个论点。

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

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

并且因为你的C编译器将int解释为32位,所以只使用rdirax的低32位 - 这是edieax

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
© www.soinside.com 2019 - 2024. All rights reserved.