_main:
; create stack frame
pushl %ebp
movl %esp, %ebp
; save one local variable
subl $8, %esp
; zero four rightmost bits of esp
andl $-16, %esp
; set eax to (0 + 15 + 15) / 2^4 * 2^4 = 16
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
; set local variable to eax (16)
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
; call allocation and main
call __alloca
call ___main
; set eax to zero (return value)
movl $0, %eax
; fold stack frame and return to caller
leave
ret
我使用int main(){return 0;}
(在Windows上)编译了一个gcc -S return_zero.c
C代码,这就是我得到的内容(我删除了汇编程序指令并添加了解释注释,就像我理解的那样。纠正我,如果我'我错了,拜托。)
我不明白三件事:
我对互联网上的#1和#3都有一些不清楚的解释,所以我想如果有人能够更深入地回答而且#2我没有找到任何解释,所以如果有人能解释它会很棒。
如果需要任何进一步的信息,我会发布评论。
谢谢!
答案 0 :(得分:1)
Intel Core i5 使用64位架构 解决问题1和部分2,来自 an Overview of x64 Calling Conventions :
对齐
大多数结构与其自然对齐对齐。首要的 异常是堆栈指针和malloc或alloca内存,其中 对齐到16个字节以帮助提高性能。对齐上面 16个字节必须手动完成,但由于16个字节是常见的 XMM操作的对齐大小,这适用于大多数代码。对于 有关结构布局和对齐的更多信息,请参阅类型和 存储。有关堆栈布局的信息,请参阅堆栈使用。
关于你问题的一部分: ...为什么以这么复杂的方式完成。只是猜测,但从引用来看,复杂性可能部分是为了适应可移植性。
借用 this post ,(也有标记compiler-construction
,assembly
& $variable[propertyObject][property]
)是一个非常好的逐行解释您尝试解释的一些相同代码。摘录:
在步骤1中,我们将指针保存到堆栈上的旧堆栈帧 打电话,pushl%ebp。由于main是第一个被调用的函数,我有 不知道%ebp的先前值是什么。
第2步,我们正在进入一个新的堆栈框架,因为我们正在进入 新功能(主要)。因此,我们必须设置一个新的堆栈框架基础 指针。我们使用esp中的值作为堆栈的开头 帧。
步骤3.在堆栈上分配8个字节的空间。正如我们提到的 上面,堆栈向低地址增长,因此减去8, 将堆栈顶部移动8个字节 ......
关于致电__alloca& __main
...
步骤12和13设置c库。