Мне трудно понять, почему компилятор решил сместить пространство стека так, как это было с написанным мною кодом.
Я играл с компилятором компилятора Годболта, чтобы изучить соглашение о вызовах языка Си, когда придумал простой код, который меня озадачил своим выбором.
Код находится в этой ссылке . Я выбрал GCC 8.2 x86-64, но ориентируюсь на процессоры x86, и это важно. Ниже приведена транскрипция кода C и сгенерированной сборки, сообщенная обозревателем компиляторов.
// C code
int testing(char a, int b, char c) {
return 42;
}
int main() {
int x = testing('0', 0, '7');
return 0;
}
; Generated assembly
testing(char, int, char):
push ebp
mov ebp, esp
sub esp, 8
mov edx, DWORD PTR [ebp+8]
mov eax, DWORD PTR [ebp+16]
mov BYTE PTR [ebp-4], dl
mov BYTE PTR [ebp-8], al
mov eax, 42
leave
ret
main:
push ebp
mov ebp, esp
sub esp, 16
push 55
push 0
push 48
call testing(char, int, char)
add esp, 12
mov DWORD PTR [ebp-4], eax
mov eax, 0
leave
ret
Теперь, глядя на столбец сборки, как я понял, строка 15 отвечает за резервирование места в стеке для локальных переменных. Проблема в том, что у меня есть только один локальный int
, а смещение составило 16 байтов вместо 4. Это похоже на потерянное пространство.
Это как-то связано с выравниванием слов? Но даже если это так, если размеры регистров общего назначения составляют 4 байта, разве это выравнивание не должно быть в отношении 4 байтов?
Еще одна странная вещь, которую я вижу, касается размещения локальных char
s testing
функции. Кажется, что они занимают по 4 байта в стеке, как показано в строках 7-8, но манипулируют только младшими байтами. Почему бы не использовать только 1 байт каждый?
Эти выборы, вероятно, хорошо спланированы, и мне бы очень хотелось понять их цель (или нет цели). Или, может быть, я просто растерялся и не совсем понял.