Почему стековая память выделяется, когда она не используется? - PullRequest
14 голосов
/ 08 января 2020

Рассмотрим следующий пример:

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 могут быть опущены. Оптимизированные сборки MSV C и g cc также используют пространство стека для этой функции (см. godbolt ), поэтому должна быть причина.

1 Ответ

11 голосов
/ 08 января 2020

Распределяет пространство стека, поэтому стек выравнивается по 16 байтов. Это необходимо, поскольку адрес возврата занимает 8 байтов, поэтому для сохранения 16-байтового стека требуется дополнительное 8-байтовое пространство.

Выравнивание кадров стека может быть настроено с аргументами командной строки для некоторых компиляторы.

  • MSV C: в документации говорится, что стек всегда выровнен по 16 байтов. Никакой аргумент командной строки не может изменить это. Пример Godbolt показывает, что 40 байтов вычитаются из rsp в начале функции, что означает, что что-то еще также влияет на это.
  • clang : -mstack-alignment Опция определяет выравнивание стека. Кажется, что по умолчанию 16, хотя не задокументировано. Если установить значение 8, выделение стека (push и pop) исчезнет из сгенерированного кода сборки.
  • g cc: -mpreferred-stack-boundary Опция определяет выравнивание стека. Если заданное значение равно N, это означает 2 ^ N байтов выравнивания. Значение по умолчанию 4, что означает 16 байтов. Если установить значение 3 (т. Е. 8 байтов), выделение стека (sub и add для rsp) исчезнет из сгенерированного кода сборки.

Проверить на godbolt .

...