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

Assembly 编译器在这个汇编代码中做什么?,assembly,compiler-construction,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 000

我试图理解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移到堆栈中
  • 流行限制性商业惯例?函数堆栈帧是否可能结束
  • 从函数返回
有人能澄清这个程序集的某些要点吗?也许是编译器选择-8、-12的原因,为什么它选择eax和edc而不是其他寄存器,为什么它推送和弹出rbp,等等

推动rbp?-这是一个堆栈帧还是什么

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

将10移动到堆栈中?被-12抵消?为什么是12,为什么是负数

在本例中,编译器选择使用堆栈中从
-12(%rbp)
-9(%rbp)
的4字节(
int
size)部分作为变量
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,%rsp
leave
。此示例更新堆栈指针,以显示我们正在堆栈上使用12个字节。完成这些操作后,只需恢复堆栈指针。不过,在您的示例中,这些都不需要,因为该函数除了局部变量之外,对堆栈没有其他用途

将10移动到堆栈中,不过这次是-8而不是-12

再次引用局部变量(这次除外),编译器为变量
y
选择从
-8(%rbp)
-5(%rbp)
的4字节部分

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

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

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

要理解编译器生成的程序集,您必须了解堆栈帧。SP是堆栈指针,BP指向当前堆栈帧,用于寻址局部变量(因此将值“10”移动到[BP-12]和[BP-8]。然后将其加载到第一个可用寄存器进行加法(本例中为ax和dx)并执行添加。最后,它恢复旧堆栈并返回。

您的每一个问题的答案都是“阅读有关堆栈框架的介绍性文章”@WumpusQ.Wumbley哈哈,好的,我会这么做的!编译器不应该在使用负偏移量对其局部变量进行EBP之前更新SP吗?或者这只是优化了,因为该方法不调用任何子函数?