编译器在这个汇编代码中做了什么?

时间:2015-10-23 12:25:22

标签: 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移到堆栈中
  • pop rbp?函数堆栈结束可能吗?
  • 从函数返回??

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

2 个答案:

答案 0 :(得分:4)

  

推rbp? - 这是堆栈框架还是什么?

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

  

将10移入堆栈?抵消-12?为什么12,为什么它是否定的?

在这种情况下,编译器选择使用从int-12(%rbp)的堆栈的4字节(-9(%rbp)大小)部分作为变量x。< / p>

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

------------------------------------------------------
                        | 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个字节。完成它们后,只需恢复堆栈指针即可。但是,在您的示例中,不需要这样做,因为该函数对堆栈没有其他用途,而不是局部变量。

  

将10移动到堆栈中,但这次是-8而不是-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是为通用数据运算而设计的。你会经常发现它们在操作中配对。

答案 1 :(得分:0)

要了解编译器生成的程序集,您必须了解堆栈帧。 SP是堆栈指针,BP指向当前堆栈帧,用于寻址局部变量(因此将值&#34; 10&#34;移动到[bp-12]和[bp-8]。然后加载这是添加的第一个可用寄存器(在这种情况下是ax和dx)并执行添加。最后,它恢复旧堆栈并返回。