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

我想了解一下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等?


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

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

    将10移入堆栈? 偏移量为-12? 为什么12,为什么是负面的?

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

    一旦创建了堆栈框架,您就可以访问具有负偏移量的局部变量,以及具有正偏移量的函数参数:

    ------------------------------------------------------
                            | 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)的变量y开始的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
    

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


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

    链接地址: http://www.djcxy.com/p/72413.html

    上一篇: What does the compiler do in this assembly code?

    下一篇: Are all programs eventually converted to assembly instructions?