Почему выделяется стековая память, когда она не используется?

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

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), поэтому должен быть причина.


person Dr. Gut    schedule 07.01.2020    source источник
comment
Вы учли неявный параметр this?   -  person dan04    schedule 08.01.2020
comment
@ dan04: Да. this передается в rcx регистре в MSVC и в rdi в clang и gcc. См. Этот пример. Не требует стека.   -  person Dr. Gut    schedule 08.01.2020
comment
Вы пробовали использовать действительно определенную vector::size() функцию?   -  person Bob__    schedule 08.01.2020
comment
@Bob__: Нет. Почему я должен? vector::size() не определен в примере, чтобы имитировать, что он не встроен.   -  person Dr. Gut    schedule 08.01.2020
comment
Итак, как компилятор может оптимизировать то, чего он не знает?   -  person Bob__    schedule 08.01.2020
comment
@Bob__: Я думаю, что знание реализации vector::size() не имеет отношения к выделению или невыделению кадра стека для vector::empty(). В empty() он просто называется, как бы там ни было.   -  person Dr. Gut    schedule 08.01.2020
comment
Итак, вы вызываете функцию, которая возвращает что-то, вам нужно место для этого (если вы не знаете ничего лучше).   -  person Bob__    schedule 08.01.2020
comment
@Bob__: Возвращаемое значение находится в eax. Для этого стек не нужен.   -  person Fred Larson    schedule 08.01.2020
comment
push и pop нельзя опускать, потому что они не используют один и тот же регистр.   -  person Mark Ransom    schedule 08.01.2020
comment
@MarkRansom: Так есть идеи, почему они там? Похоже, они мало чего достигают, за исключением сохранения значения rax, но перемещения его в rcx.   -  person Fred Larson    schedule 08.01.2020
comment
@FredLarson: это просто фиктивные инструкции по выравниванию стека. Они короче, чем эквивалентные add rsp-подобные инструкции. Регистрация здесь не имеет значения. Для pop используется rcx, потому что он может быть удален.   -  person geza    schedule 08.01.2020
comment
stackoverflow.com/questions/2362097/   -  person parktomatomi    schedule 08.01.2020


Ответы (1)


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

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

  • MSVC: документация говорит, что стек всегда выровнен по 16 байт. Отсутствует аргумент командной строки может это изменить. Пример Godbolt показывает, что 40 байтов вычитаются из rsp в начале функции, что означает, что на это влияет что-то еще.
  • clang: _2 _ опция определяет выравнивание стека. Кажется, что значение по умолчанию - 16, хотя это не задокументировано. Если вы установите его на 8, выделение стека (push и pop) исчезнет из сгенерированного кода сборки.
  • gcc: _5 _ опция определяет выравнивание стека. Если заданное значение равно N, это означает 2 ^ N байтов выравнивания. Значение по умолчанию - 4, что означает 16 байтов. Если вы установите его на 3 (т.е. 8 байтов), выделение стека (sub и add для rsp) исчезнет из сгенерированного кода сборки.

Посетите godbolt.

person geza    schedule 07.01.2020
comment
Вот почему гуру c ++, эксперты всегда предупреждали: помещайте элементы структуры / класса в порядке от самого длинного / самого большого размера до самого маленького ... только так это будет правильно эффективно - person ; 08.01.2020
comment
@geza: Спасибо. Я провел небольшое исследование для двух других компиляторов и написал это к вашему ответу. Вам нравится это? - person Dr. Gut; 08.01.2020
comment
@ Доктор Гут: спасибо, вы сделали ответ намного лучше и полнее. Обратите внимание, что выравнивание стека обычно документируется в ABI для системы (например, для некоторых систем вот документы: github.com/hjl-tools/x86-psABI/wiki/X86-psABI). - person geza; 08.01.2020
comment
@geza: Спасибо. - person Dr. Gut; 09.01.2020