Почему LLVM добавляет две дополнительные инструкции для одной и той же программы?


Я компилирую эту программу на языке Си и сравниваю сгенерированный ассемблерный код:

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? Двигать что-то на стопке и сразу же после этого класть это кажется мне бесполезным.

3 8

3 ответа:

На самом деле, они сравнимы. Отпуск-это инструкция высокого уровня:

Из руководства Intel:

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

Инструкция movl $0, -4(%rbp) мертва, потому что это неоптимизированный код. Попробуйте передать -O обоим компиляторам, чтобы увидеть, что изменится.

Похоже, LLVM использует традиционную функцию prolog / epilog, в то время как GCC использует тот факт, что точка входа не нуждается в очистке