Assembly 编译器在这个汇编代码中做什么?
我试图理解C编译器编译成汇编时会做什么。我编译成汇编的代码如下: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
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移到堆栈中
- 流行限制性商业惯例?函数堆栈帧是否可能结束
- 从函数返回
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吗?或者这只是优化了,因为该方法不调用任何子函数?