我正在编译这个C程序并比较生成的汇编代码:
int main(){ return 0; }
GCC给出了这个主要功能(cc hello.c -S
):
_main:
LFB2:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
movl $0, %eax
leave
ret
LLVM给出了这个主要功能(clang hello.c -S
):
_main:
Leh_func_begin0:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
movl $0, %eax
movl $0, -4(%rbp)
popq %rbp
ret
Leh_func_end0:
movl $0, -4(%rbp)
和popq %rbp
需要什么?在堆栈上移动东西然后直接弹出它对我来说似乎毫无用处。
答案 0 :(得分:9)
实际上,它们具有可比性。离开是一个高级别的指令:
来自英特尔手册:
16-bit: C9 LEAVE A Valid Valid Set SP to BP, then pop BP.
32-bit: C9 LEAVE A N.E. Valid Set ESP to EBP, then pop EBP.
64-bit: C9 LEAVE A Valid N.E. Set RSP to RBP, then pop RBP.
基本上,离开等同于
movq %rbp, %rsp
popq %rbp
答案 1 :(得分:9)
movl $0, -4(%rbp)
指令已经死了,因为这是未经优化的代码。尝试将-O
传递给两个编译器以查看更改。
答案 2 :(得分:2)
看起来LLVM正在使用传统的函数prolog / epilog,而GCC正在利用入口点不需要清理的事实