Как gcc может сгенерировать сборку, которая может установить кадр стека с помощью инструкции ENTER - PullRequest
0 голосов
/ 14 мая 2019

Я генерирую код ассемблера, например, с помощью gcc. Может ли gcc сгенерировать код, имеющий ENTER для фрейма стека?

.file   "temp.c"
.text
.globl  main
.type   main, @function
main:
pushq   %rbp
movq    %rsp, %rbp
movl    $0, -12(%rbp)
movl    $0, -8(%rbp)
movl    $0, -4(%rbp)
movl    $0, %eax
popq    %rbp
ret
.size   main, .-main
.ident  "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0"
.section    .note.GNU-stack,"",@progbits

Вот оригинальный код:

 #include <stdio.h>
  int main(){
   int a;
   int b;
   int c;
   a = 0;
   b = 0;
   c = 0;
}

1 Ответ

3 голосов
/ 14 мая 2019

GCC никогда не будет излучать enter, потому что он очень медленный по сравнению с обычной установкой указателя кадра, состоящей из 2 или 3 однопроходных инструкций.

(Если он вообще создает указатель кадра; gcc -O1 и выше включает -fomit-frame-pointer. За исключением случаев оптимизации по размеру, поскольку в режимах адресации x(%rsp) используется дополнительный байт по сравнению с режимами x(%rbp).)

# equivalent to  enter $24, $0  (4 bytes)
    push   %rbp               # 1 byte
    mov    %rsp, %rbp         # 3 bytes
    sub    $24, %rsp          # 4 bytes only for a non-zero immediate

В частности, на Skylake enter составляет 12 мопов и по одному на 8-тактную пропускную способность для enter a, 0 ( Таблицы команд Агнера Фога ). С ненулевым уровнем вложенности он безумно медленный, как 87 cycles + 7 * nesting level.

На Райзене enter равен 12 моп, с пропускной способностью по одному на 16 циклов.

leave хорошо, хотя: это только 3 моп на процессорах Intel. (Тем не менее, это на единицу больше, чем mov %rbp, %rsp / pop %rbp. 3 мопа не включают в себя синхронизацию стека; это 3, даже если механизм стека был синхронизирован до leave.)


Единственная причина использования enter - оптимизация под размер кода за счет скорости. Но даже gcc -Os недостаточно заботится о размере кода, чтобы иметь возможность для этого.

Даже clang -Oz (который будет использовать push $1 / pop %rax для сохранения 2 байтов против mov $1, %eax) не использует enter. ( Проводник компилятора Godbolt )

Но enter 0,0 даже не сохраняет размер кода, так что это просто плохо.

И я следую инструкции, в которой говорится, что запуск программы начинается с ENTER

Это один (устаревший и не рекомендуемый) вариант.

Если вы хотите написать свой собственный компилятор, который делает медленный код, продолжайте.

...