у всех функций есть "пролог функции", который уменьшает указатель стека для местных жителей? - PullRequest
0 голосов
/ 02 мая 2018

У меня есть несколько основных вопросов, касающихся сборки.

при написании функции на ассемблере все функции имеют "пролог функции"? Я вижу некоторые функции, написанные в Интернете, и у них их нет, что меня смущает. Я думаю, что вам всегда нужно это для нового базового указателя и локальных переменных путем уменьшения стека?

Кроме того, каждая инструкция push требует инструкции вычитания для стека указателя, потому что мы всегда хотим, чтобы указатель стека был на вершине стека, и если нет, то почему? так что если

 push %eax
 sub $4, %esp

Мой последний вопрос: есть ли какие-либо ресурсы для объяснения сборки в терминах непрофессионалов?

1 Ответ

0 голосов
/ 02 мая 2018

Довольно просто создать собственный пример, просто нужно что-то в стеке функции (это не оптимизирует).

unsigned int more_fun ( unsigned int );
void fun_too ( unsigned int *);
void fun ( void )
{
    unsigned int ra;
    unsigned int ray[64];
    for(ra=0;ra<64;ra++) ray[ra]=more_fun(ra);
    fun_too(ray);
}



0000000000000000 <fun>:
   0:   53                      push   %rbx
   1:   31 db                   xor    %ebx,%ebx
   3:   48 81 ec 10 01 00 00    sub    $0x110,%rsp
   a:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  11:   00 00 
  13:   48 89 84 24 08 01 00    mov    %rax,0x108(%rsp)
  1a:   00 
  1b:   31 c0                   xor    %eax,%eax
  1d:   0f 1f 00                nopl   (%rax)
  20:   89 df                   mov    %ebx,%edi
  22:   e8 00 00 00 00          callq  27 <fun+0x27>
  27:   89 04 9c                mov    %eax,(%rsp,%rbx,4)
  2a:   48 83 c3 01             add    $0x1,%rbx
  2e:   48 83 fb 40             cmp    $0x40,%rbx
  32:   75 ec                   jne    20 <fun+0x20>
  34:   48 89 e7                mov    %rsp,%rdi
  37:   e8 00 00 00 00          callq  3c <fun+0x3c>
  3c:   48 8b 84 24 08 01 00    mov    0x108(%rsp),%rax
  43:   00 
  44:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4b:   00 00 
  4d:   75 09                   jne    58 <fun+0x58>
  4f:   48 81 c4 10 01 00 00    add    $0x110,%rsp
  56:   5b                      pop    %rbx
  57:   c3                      retq   

(он не связан, поэтому непосредственные в вызове нули, чтобы компоновщик мог их заполнить)

Вместо того, чтобы вычитать или добавлять константу в rsp, вы могли бы вместо этого поместить длинный список толчков и всплесков, как указал Шут в комментариях. Это просто трата пространства кода и времени выполнения, сложение и вычитание имеют больше смысла.

Теперь можно утверждать, что вы могли бы реализовать этот код таким образом, чтобы каждый раз при прохождении цикла вы передавали результат more_fun (); Выращивание стека только по мере необходимости для функции и использование толчков по вашему желанию, а не вычитание из rsp. Но по возвращении вы бы хотели добавить в rsp одну инструкцию, а не тратить время и пространство на отдельные всплывающие окна или цикл всплывающих окон. Это решение труднее отладить как автор компилятора и труднее понять как пользователь / читатель вывода компилятора. (и если вы хотите сохранить, скажем, 64-битное выравнивание в стеке и сказать, что здесь беззнаковое целое - это 32 бита, как показано, то вы бы сожгли еще несколько инструкций, просто чтобы разобраться с этим)

...