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

#c #gcc #assembly #compilation #x86

#c #gcc #сборка #Сборник #x86

Вопрос:

Я узнаю о том, как компиляторы представляют программы на C в сборке. У меня есть вопрос о чем-то, что делает компилятор, в чем я не могу разобраться. Вот некоторый код C :

 class Class1 {
public:
  int i;
  char ch;
};

int main() {
  Class1 cls;
}
  

Компиляция с помощью «g -S» выводит это (я удалил все, кроме определения функции):

 main:
    push    ebp
    mov     ebp, esp
    sub     esp, 16
    mov     eax, 0
    leave
    ret
  

Я не понимаю строку sub esp, 16 . Зачем ему выделять 16 байт для экземпляра этого класса, которому требуется всего 8, если учесть выравнивание и заполнение структуры данных?

Это должно быть

 [int i - 4 bytes][char ch - 1 byte][padding - 3 bytes]
  

не так ли?

Когда я скомпилировал код с определением класса, также включающим double, т.е.

 class Class1 {
public:
  int i;
  char ch;
  double dub;
}; 
  

он по-прежнему выделял 16 байт, что имело смысл в этом случае.

Итак, почему компилятор выделяет 16 байт, когда ему нужно всего 8?

Комментарии:

1. 1 за хорошо сформулированный и хорошо проработанный вопрос!

Ответ №1:

Это связано с выравниванием стекового фрейма, а не с выравниванием структуры.

Если вы выполнили a sizeof() для своих объектов, вы увидите, что ожидаете от выравнивания структуры и заполнения.

Однако стековые фреймы немного отличаются. В большинстве современных систем выравнивание стека составляет 16 байт (или более) для обеспечения доступа к памяти SSE.

Комментарии:

1. Это, кажется, покрывает это. Есть ли простой для объяснения ответ на вопрос, что именно представляет собой доступ к памяти SSE?

2. SSE — это набор 128-битных инструкций SIMD на x86. Регистры имеют длину 16 байт. Поэтому стек должен быть выровнен по 16 байтам. ( en.wikipedia.org/wiki/Streaming_SIMD_Extensions )