Объясните концепцию стекового фрейма в двух словах

Кажется, я понял идею стека вызовов в дизайне языка программирования. Но я не могу найти (возможно, я просто недостаточно тщательно ищу) какое-либо достойное объяснение того, что такое фрейм стека.

Поэтому я хотел бы попросить кого-нибудь объяснить мне это в нескольких словах.

6 ответов

Решение

Кадр стека - это кадр данных, который помещается в стек. В случае стека вызовов кадр стека будет представлять вызов функции и данные ее аргумента.

Если я правильно помню, адрес возврата функции помещается сначала в стек, затем в аргументы и место для локальных переменных. Вместе они составляют "кадр", хотя это, скорее всего, зависит от архитектуры. Процессор знает, сколько байтов находится в каждом кадре, и соответственно перемещает указатель стека, когда кадры выталкиваются и выталкиваются из стека.

РЕДАКТИРОВАТЬ:

Существует большая разница между стеками вызовов более высокого уровня и стеком вызовов процессора.

Когда мы говорим о стеке вызовов процессора, мы говорим о работе с адресами и значениями на уровне байтов / слов в сборке или машинном коде. Существуют "стеки вызовов", когда речь идет о языках более высокого уровня, но они являются средством отладки / выполнения, управляемым средой выполнения, так что вы можете регистрировать, что пошло не так с вашей программой (на высоком уровне). На этом уровне такие вещи, как номера строк, имена методов и классов, часто известны. К тому времени, когда процессор получает код, он совершенно не имеет понятия об этих вещах.

Если вы хорошо понимаете стек, то вы поймете, как работает память в программе, и если вы поймете, как память работает в программе, вы поймете, как хранится функция в программе, и если вы поймете, как хранится функция в программе, вы поймете, как работает рекурсивная функция, и если вы поймете, как работает рекурсивная функция, вы поймете, как работает компилятор, и если вы поймете, как работает компилятор, ваш ум будет работать как компилятор, и вы очень легко отладите любую программу

Позвольте мне объяснить, как работает стек:

Сначала вы должны знать, как функция хранится в стеке:

Кучи хранят значения динамического выделения памяти. Стек хранить автоматическое размещение и удаление значений.

введите описание изображения здесь

Давайте разберемся с примером:

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(4)

Теперь разберитесь в частях этой программы:

введите описание изображения здесь

Теперь давайте посмотрим, что такое стек и что такое части стека:

введите описание изображения здесь

Выделение стека:

Помните одно: если какая-либо функция получит "return", независимо от того, загружены ли все его локальные переменные или что-то, что она немедленно вернет из стека, будет его стековым фреймом. Это означает, что когда любая рекурсивная функция получает базовое условие, и мы ставим return после базового условия, чтобы базовое условие не дожидалось загрузки локальных переменных, находящихся в "остальной" части программы, она немедленно возвращает текущий кадр из стека и теперь, если один кадр возвращать следующий кадр в записи активации. Смотрите это на практике:

введите описание изображения здесь

Выделение блока:

Так что теперь, когда функция находит оператор возврата, она удаляет текущий кадр из стека.

при возврате из стека значение вернется в обратном порядке, в котором они размещены в стеке.

введите описание изображения здесь

Это очень краткое описание, и если вы хотите узнать больше о стеке и двойной рекурсии, прочитайте два поста этого блога:

Подробнее о стеке шаг за шагом

Подробнее о двойной рекурсии шаг за шагом со стеком

Быстрое завершение. Может быть, у кого-то есть лучшее объяснение.

Стек вызовов состоит из 1 или нескольких стековых кадров. Каждый кадр стека соответствует вызову функции или процедуры, которая еще не завершена с возвратом.

Чтобы использовать кадр стека, поток сохраняет два указателя, один из которых называется указателем стека (SP), а другой - указателем кадра (FP). SP всегда указывает на "вершину" стека, а FP всегда указывает на "вершину" кадра. Кроме того, поток также поддерживает программный счетчик (ПК), который указывает на следующую команду, которая будет выполнена.

В стеке хранятся следующие данные: локальные переменные и временные значения, фактические параметры текущей инструкции (процедура, функция и т. Д.)

В отношении очистки стека существуют разные соглашения о вызовах.

"Стек вызовов состоит из кадров стека..." - Википедия

Кадр стека - это то, что вы кладете в стек. Это структуры данных, которые содержат информацию о подпрограммах для вызова.

У программистов могут возникнуть вопросы о фреймах стека не в широком смысле (что это единая сущность в стеке, которая обслуживает только один вызов функции и сохраняет адрес возврата, аргументы и локальные переменные), но в узком смысле - когда термин stack frames упоминается в контексте параметров компилятора.

Независимо от того, имел в виду автор вопроса или нет, но концепция стекового фрейма с точки зрения опций компилятора - очень важная проблема, которая здесь не рассматривается в других ответах.

Например, компилятор Microsoft Visual Studio 2015 C/C++ имеет следующий параметр, связанный с stack frames:

  • / Oy (Frame-Pointer Omission)

GCC имеют следующее:

  • -fomit-frame-pointer (Не хранить указатель кадра в регистре для функций, которые в нем не нуждаются. Это позволяет избежать инструкций по сохранению, настройке и восстановлению указателей кадра; также делает дополнительный регистр доступным во многих функциях)

Компилятор Intel C++ имеет следующее:

  • -fomit-frame-pointer (Определяет, используется ли EBP как регистр общего назначения при оптимизации)

который имеет следующий псевдоним:

  • / Oy

Delphi имеет следующую опцию командной строки:

  • - $ W + (Создание кадров стека)

В этом конкретном смысле, с точки зрения компилятора, кадр стека - это просто код входа и выхода для подпрограммы, который вставляет привязку к стеку - который также может использоваться для отладки и обработки исключений. Инструменты отладки могут сканировать данные стека и использовать эти якоря для обратного отслеживания, находя call sites в стеке, то есть для отображения имен функций в том порядке, в котором они были вызваны иерархически. Для архитектуры Intel это push ebp; mov ebp, esp или же enter для входа и mov esp, ebp; pop ebp или же leave для выхода.

Вот почему для программиста очень важно понять, что такое стековый фрейм, когда дело доходит до опций компилятора - потому что компилятор может контролировать, генерировать этот код или нет.

В некоторых случаях кадр стека (код входа и выхода для подпрограммы) может быть пропущен компилятором, и переменные будут напрямую доступны через указатель стека (SP/ESP/RSP), а не через удобный базовый указатель (BP/ESP/ РСП). Условия пропуска стекового фрейма, например:

  • функция является конечной (то есть конечной сущностью, которая не вызывает другие функции);
  • не существует try/finally или try / кроме или аналогичных конструкций, т.е. не используются исключения;
  • никакие процедуры не вызываются с исходящими параметрами в стеке;
  • функция не имеет параметров;
  • функция не имеет встроенного кода сборки;
  • так далее...

Пропуск стековых фреймов (код входа и выхода для подпрограммы) может сделать код меньше и быстрее, но это может также негативно повлиять на способность отладчиков отслеживать данные в стеке и отображать их для программиста. Это параметры компилятора, которые определяют, при каких условиях функция должна иметь код входа и выхода, например: (a) всегда, (b) никогда, (c) при необходимости (с указанием условий).

Кадр стека - это упакованная информация, связанная с вызовом функции. Эта информация обычно включает аргументы, передаваемые в функцию, локальные переменные и куда возвращаться после завершения. Запись активации - это другое имя стекового фрейма. Расположение кадра стека определяется в ABI производителем, и каждый компилятор, поддерживающий ISA, должен соответствовать этому стандарту, однако схема расположения может зависеть от компилятора. Обычно размер кадра стека не ограничен, но существует концепция, называемая "красная / защищенная зона", позволяющая системным вызовам... и т. Д. Выполняться без вмешательства в кадр стека.

Всегда есть SP, но на некоторых ABI (например, ARM и PowerPC) FP не обязателен. Аргументы, которые нужно было поместить в стек, можно сместить только с помощью SP. Будет ли сгенерирован кадр стека для вызова функции или нет, зависит от типа и количества аргументов, локальных переменных и от того, как вообще доступны локальные переменные. В большинстве ISA, во-первых, используются регистры, и если имеется больше аргументов, чем регистров, выделенных для передачи аргументов, они помещаются в стек (например, x86 ABI имеет 6 регистров для передачи целочисленных аргументов). Следовательно, иногда некоторые функции не нуждаются в размещении кадра стека в стеке, просто адрес возврата помещается в стек.

Другие вопросы по тегам