Уменьшение стека на 24, когда нужно всего 8 байтов? - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть C код:

long fib(long n) {
  if (n < 2) return 1;
  return fib(n-1) + fib(n-2);
}

int main(int argc, char** argv) {
    return 0;
}

, который я скомпилировал, запустив gcc -O0 -fno-optimize-sibling-calls -S file.c, получив код сборки, который не был оптимизирован:

    .file   "long.c"
    .text
    .globl  fib
    .type   fib, @function
fib:
.LFB5:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $24, %rsp
    .cfi_offset 3, -24
    movq    %rdi, -24(%rbp)
    cmpq    $1, -24(%rbp)
    jg  .L2
    movl    $1, %eax
    jmp .L3
.L2:
    movq    -24(%rbp), %rax
    subq    $1, %rax
    movq    %rax, %rdi
    call    fib
    movq    %rax, %rbx
    movq    -24(%rbp), %rax
    subq    $2, %rax
    movq    %rax, %rdi
    call    fib
    addq    %rbx, %rax
.L3:
    addq    $24, %rsp
    popq    %rbx
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE5:
    .size   fib, .-fib
    .globl  main
    .type   main, @function
main:
.LFB6:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE6:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

Мой вопрос :

Почему мы уменьшаем указатель стека на 24 subq $24, %rsp? Насколько я понимаю, мы сохраняем только один элемент, первый аргумент n в %rdi, в стеке после первых двух нажатий. Так почему бы просто не уменьшить указатель стека на 8, а затем переместить n в -8(%rbp)? Итак

subq    $8, %rsp
movq    %rdi, -8(%rbp)

1 Ответ

3 голосов
/ 08 апреля 2020

G CC не полностью оптимизируется с -O0, даже при использовании стека. (Это может помочь в отладке, сделав некоторые из его использования стека более прозрачными для людей. Например, объекты a, b и c могут совместно использовать одно расположение стека, если их активные времена жизни (определенные для использования в программе, а не по модели времени жизни в стандарте C с -O3, но может иметь отдельно зарезервированные места в стеке с -O0, и это упрощает понимание человеком, где a , b и c используются в ассемблерном коде. Потерянные 16 байтов могут быть побочным эффектом этого, так как эти пробелы могут быть зарезервированы для некоторой цели, которую эта маленькая функция не использовала, например, пробел чтобы сохранить определенные регистры, если необходимо.)

Изменение оптимизации на -O3 приводит к G CC вычитанию только восьми из указателя стека.

...