2016-12-14 2 views
2

Почему компилятор GCC добавляет эти три строки при использовании double, а не когда Int?Int vs Double in assembly


С междунар:

#include <cstdio> 

int main(){ 
    int i = 1; 
} 

==>

main: 
     push ebp 
     mov  ebp, esp 
     sub  esp, 16 
     mov  DWORD PTR [ebp-4], 1 
     mov  eax, 0 
     leave 
     ret 

С двойной:

#include <cstdio> 

int main(){ 
    double i = 1; 
} 

==>

main: 
     lea  ecx, [esp+4]   // This three lines 
     and  esp, -8     // ... 
     push DWORD PTR [ecx-4]  // ... 
     push ebp 
     mov  ebp, esp 
     push ecx 
     sub  esp, 20 
     fld1 
     fstp QWORD PTR [ebp-16] 
     mov  eax, 0 
     add  esp, 20 
     pop  ecx 
     pop  ebp 
     lea  esp, [ecx-4] 
     ret 

Аналогично происходит при использовании указателей, например, int * s = new int (4);

Можете ли вы объяснить, почему это происходит, и почему не всегда?

+2

Если вы не используете переключатель '-O3', компилятор генерирует код, который может быть избыточным или бессмысленным (хотя и по-прежнему правильным) –

+0

Да, я знаю. Я просто изучаю :) –

+0

Является ли это C или C++? Это разные языки, и для ввода/выхода функции, вероятно, будет создан код с кодом. – Olaf

ответ

7

В случае double в автоматическом объеме (в стеке) дополнительный код выравнивает фрейм стека с четной границей по 8 байт, так что переменная double хранится по адресу памяти с подходящим выравниванием. Указатель стека при вводе функции не может быть выровнен на четной 8-байтовой границе, а компилятор добавляет дополнительный код, чтобы сделать это так.

Это то, что делает and esp, -8. -8 - 0xFFFFFFF8. Это очищает последние 3 бита esp, используя and, что указывает на четный адрес граничной памяти по 8 байт, корректируя его (стек растет с адресов высокой и низкой памяти).

+0

Конечно, вот что делает код. Но почему он делает это для 'double', но не для' int'? (Серьезный вопрос, а не троллинг: я долго не смотрел на проблемы генерации кода ...) –

+2

В x86 «double» является 64-битным типом и требует 8-байтового выравнивания, но ABI не требует что стек будет выровнен по 8 байт. То же самое происходит для 'long long', BTW, так как это также 8-байтовый тип. Это не обязательно для 'int', потому что это всего лишь 4-байтовый тип, и указатель стека гарантированно выравнивается по 4 байт. –