Question

I am compiling this C program and comparing the generated assembly code:

int main(){ return 0; }

GCC gives this main function (cc hello.c -S):

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
    movl    $0, %eax
    leave
    ret

LLVM gives this main function (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:

What are movl $0, -4(%rbp) and popq %rbp needed for? Moving something on the stack and popping it directly afterwards seems useless to me.

Was it helpful?

Solution

Actually, they're comparable. Leave is a high level instruction:

From the Intel manual:

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.

basically, leave is equivalent to

movq %rbp, %rsp
popq %rbp

OTHER TIPS

The movl $0, -4(%rbp) instruction is dead, because this is unoptimized code. Try passing in -O to both compilers to see what changes.

It looks like LLVM is using a traditional function prolog/epilog, whereas GCC is taking advantage of the fact that the entry point doesn't need to clean up

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top