Что такое .cfi и .LFE в коде сборки, созданным GCC из программы С++?

У меня есть следующий код С++

int factorial(int n){

    if(n==0){
        return 1;
    }
    return n*factorial(n-1);

}

int main(void){
    factorial(5);
    return 0;
}

Когда я создаю файл сборки с помощью g++ -S factorial.cpp, я получаю следующее:

    .file   "tail_call_opt.cpp"
    .text
.globl _Z9factoriali
    .type   _Z9factoriali, @function
_Z9factoriali:
.LFB0:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    subl    $24, %esp
    cmpl    $0, 8(%ebp)
    jne .L2
    movl    $1, %eax
    jmp .L3
.L2:
    movl    8(%ebp), %eax
    subl    $1, %eax
    movl    %eax, (%esp)
    call    _Z9factoriali
    imull   8(%ebp), %eax
.L3:
    leave
    ret
    .cfi_endproc
.LFE0:
    .size   _Z9factoriali, .-_Z9factoriali
.globl main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $16, %esp
    movl    $5, (%esp)
    call    _Z9factoriali
    movl    $0, %eax
    leave
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

Я могу выполнить большинство из этого, но какова цель .cfi и частей .LFE? Где я могу узнать больше об сборке, созданной gcc?

Ответ 1

Эти директивы сообщают газ, чтобы испускать теги информации о кадре с карликами, которые, по-видимому, используются для восстановления стоп-кадра в стеке, когда отсутствует указатель кадра. В вашем случае присутствует указатель кадра, поэтому я предполагаю, что он может использоваться для выполнения размотки во время обработки исключений. Такой механизм имеет меньше накладных расходов, чем старый sjlj (setjump/longjump). См. здесь, а также связанную специфика Dwarf.

Что касается ярлыков .Lxx, префикс .L указывает, что метка локальна для этого файла и поэтому не будет конфликтовать с одноименными метками в других файлах. GCC обычно использует .L для автогенерированных меток. В этом случае, скорее всего, "FB" означает "начало функции", а "FE" означает "конец функции".