assembly - 编译器在这段汇编代码中做了什么?

标签 assembly compiler-construction

我试图了解 C 编译器在编译为程序集时会做什么。我编译成程序集的代码是这样的:

void main() {
    int x = 10;
    int y = 10;
    int a = x + y;
}

生成以下程序集:

                .Ltext0:
                    .globl  main
                main:
                .LFB0:
0000 55             pushq   %rbp
0001 4889E5         movq    %rsp, %rbp
0004 C745F40A       movl    $10, -12(%rbp)
000b C745F80A       movl    $10, -8(%rbp)
0012 8B45F8         movl    -8(%rbp), %eax
0015 8B55F4         movl    -12(%rbp), %edx
0018 01D0           addl    %edx, %eax
001a 8945FC         movl    %eax, -4(%rbp)
001d 5D             popq    %rbp
001e C3             ret

但是,我在理解这段代码中具体发生的事情时遇到了一些困难。我理解所有标签和一些组件。我认为它的作用如下:

  • 推 rbp? - 这是用于堆栈框架还是其他东西?
  • 将堆栈指针设置为基指针? (即清除堆栈)
  • 将 10 移入堆栈?偏移-12?为什么是 12,为什么是负数?
  • 将 10 移入堆栈,不过这次是 -8 而不是 -12(相差 4,可能是字节或其他什么?)
  • 将 -8 处的值移至 eax
  • 将 -12 处的值移至 edx
  • 添加 eax 和 edc
  • 将值从 eax 移入堆栈
  • 流行 rbp?函数堆栈帧可能结束吗?
  • 从函数返回?

任何人都可以澄清这个程序集的某些要点,也许是编译器选择 -8、-12 的原因,为什么它选择 eax 和 edc 而不是其他一些寄存器,为什么它推送和弹出 rbp 等?

最佳答案

push rbp? - is this for a stack frame or something?

是的。编译器为局部变量创建一个堆栈帧。 push %rbp/movq %rsp, %rbp 是执行此操作的标准方法。它允许轻松访问局部变量。

moves 10 into stack? Offset by -12? Why 12, and why is it negative?

在本例中,编译器选择使用从 -12(%rbp)- 的堆栈的 4 字节(int 大小)部分9(%rbp) 表示变量 x

创建堆栈帧后,您可以访问具有负偏移量的局部变量和具有正偏移量的函数参数:

------------------------------------------------------
                        | R |
     New stack (locals) | B | Old stack (parameters)
                        | P |
------------------------------------------------------
                          ^
                          RBP is updated to point here as well so you get negative offsets (to the left) for locals and positive offsets (to the right) for parameters.

请注意,由于存储的 RBP 以及函数的返回地址也占用空间,因此需要为任何参数偏移量添加 16 个字节。 (32位系统为8字节)

通常,您必须在使用局部变量进行任何操作之前更新 RSP,如下所示:subq $12, %rsp。离开该功能时,请使用 addq $12、%rspleave。此示例更新堆栈指针以显示我们正在堆栈上使用 12 个字节。当您完成它们后,您只需恢复堆栈指针即可。但在您的示例中,这些都不需要,因为除了局部变量之外,该函数对堆栈没有其他用途。

moves 10 into stack, though this time at -8 instead of -12

再次引用局部变量,只不过这次编译器选择了从 -8(%rbp)-5(%rbp) 的 4 字节部分> 对于变量 y

在这种情况下,pop %rbp 将函数末尾的堆栈恢复到进入之前的状态:

------------------------------------------------------
                        | R |
     New stack (locals) | B | Old stack (parameters)
                        | P |
------------------------------------------------------
                          ^
                          RSP points here, so a `pop %rbp` will restore both RSP and RBP

编译器可能首先尝试使用 EAXEDX,因为 EAX 是为数学运算而设计的,而 EDX专为通用数据操作而设计。您经常会发现它们在操作中配对。

关于assembly - 编译器在这段汇编代码中做了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33302295/

相关文章:

c++ - 如何制作跨平台的c++内联汇编语言?

c - 如何将C语言转换为汇编语言

c++ - 将函数定义直接放在头文件中以便编译器可以内联?

c++ - 如何解决重复符号错误?

linux - 在 Linux 中轻松检查 Intel 汇编操作码

assembly - 你能从机器代码中判断一条指令是否可重定位吗?

c - xorl %eax - IA-32 中的指令集架构

algorithm - 上下文无关文法

linux - 好的,用于 Linux 的小型 Haskell 编译器?

c - 结构的两个 malloc 定义之间的区别