Почему выделяется стековая память, когда она не используется?
Рассмотрим следующий пример:
struct vector {
int size() const;
bool empty() const;
};
bool vector::empty() const
{
return size() == 0;
}
Сгенерированный код сборки для vector::empty
(по clang, с оптимизациями):
push rax
call vector::size() const
test eax, eax
sete al
pop rcx
ret
Почему он выделяет место в стеке? Он вообще не используется. Вpush
а также pop
можно опустить. Оптимизированные сборки MSVC и gcc также используют стековое пространство для этой функции (см. Godbolt), поэтому должна быть причина.
1 ответ
Решение
Он выделяет пространство стека, поэтому стек выровнен по 16 байт. Это необходимо, потому что адрес возврата занимает 8 байтов, поэтому требуется дополнительное 8-байтовое пространство для выравнивания 16-байтового стека.
Для некоторых компиляторов выравнивание кадров стека можно настроить с помощью аргументов командной строки.
- MSVC: в документации сказано, что стек всегда выровнен по 16 байт. Никакой аргумент командной строки не может это изменить. Пример Godbolt показывает, что 40 байтов вычитаются из
rsp
в начале функции, что означает, что на это влияет что-то еще. - clang: The
-mstack-alignment
опция определяет выравнивание стека. Кажется, что значение по умолчанию - 16, хотя это не задокументировано. Если вы установите его на 8, распределение стека (push
а такжеpop
) исчезает из сгенерированного кода сборки. - gcc: The
-mpreferred-stack-boundary
опция определяет выравнивание стека. Если заданное значение равно N, это означает 2^N байтов выравнивания. Значение по умолчанию - 4, что означает 16 байтов. Если вы установите его на 3 (т.е. 8 байтов), выделение стека (sub
а такжеadd
заrsp
) исчезает из сгенерированного кода сборки.
Проверьте Godbolt.