WikiDer > Пролог функции
В язык ассемблера программирование, то пролог функции это несколько строк кода в начале функции, которые подготавливают куча и регистры для использования в функции. Точно так же эпилог функции появляется в конце функции и восстанавливает стек и регистры до состояния, в котором они находились до вызова функции.
Пролог и эпилог не являются частью самого языка ассемблера; они представляют собой соглашение, используемое языком ассемблера программисты, и компиляторы многих высокоуровневых языки. Они довольно жесткие, имеют одинаковую форму для каждой функции.
Пролог и эпилог функции также иногда содержат код для защита от переполнения буфера.
Пролог
Пролог функции обычно выполняет следующие действия, если в архитектуре есть базовый указатель (также известный как указатель кадра) и указатель стека:
- Помещает текущий базовый указатель в стек, чтобы его можно было восстановить позже.
- Присваивает значение базового указателя адресу указателя стека (который указывает на вершину стека), чтобы базовый указатель указывал на вершину стека.
- Перемещает указатель стека дальше, уменьшая или увеличивая его значение, в зависимости от того, растет ли стек вниз или вверх. На x86 указатель стека уменьшается, чтобы освободить место для локальных переменных функции.
Можно написать несколько возможных прологов, что приведет к несколько иной конфигурации стека. Эти различия допустимы, если программист или компилятор правильно использует стек внутри функции.
В качестве примера приведем типичный язык ассемблера x86 пролог функции, созданный GCC
толкать ebp mov ebp, особенно суб особенно, N
В N Немедленное значение - это количество байтов, зарезервированных в стеке для локального использования.
Такого же результата можно достичь, используя войти
инструкция:
войти N, 0
Более сложные прологи могут быть получены с использованием других значений (кроме 0) для второго операнда войти
инструкция. Эти прологи выдвигают несколько указателей на базу / фрейм, чтобы учесть вложенные функции, как того требуют такие языки, как Паскаль. Однако современные версии этих языков не используют эти инструкции, потому что в некоторых случаях они ограничивают глубину вложенности.[нужна цитата]
Эпилог
Функциональный эпилог отменяет действия пролога функции и возвращает управление вызывающей функции. Обычно он выполняет следующие действия (эта процедура может отличаться от одной архитектуры к другой):
- Перетащите указатель стека на текущий базовый указатель, чтобы освободить место, зарезервированное в прологе для локальных переменных.
- Извлекает базовый указатель из стека, поэтому он восстанавливается до своего значения перед прологом.
- Возврат к вызывающей функции путем извлечения счетчика программы предыдущего кадра из стека и перехода к нему.
Данный эпилог отменяет действие любого из вышеупомянутых прологов (либо полного, либо того, в котором войти
). При определенных соглашения о вызовах вызываемый объект несет ответственность за очистку аргументов из стека, поэтому эпилог может также включать шаг перемещения указателя стека вниз или вверх.
Например, эти три шага могут быть выполнены на 32-битном языке ассемблера x86 с помощью следующих инструкций:
mov особенно, ebp поп ebp Ret
Как и в прологе, x86 процессор содержит встроенную инструкцию, которая выполняет часть эпилога. Следующий код эквивалентен приведенному выше коду:
покинуть Ret
В покинуть
инструкция выполняет mov
и поп
инструкции, как указано выше.
Функция может содержать несколько эпилогов. Каждая точка выхода из функции должна либо переходить к общему эпилогу в конце, либо содержать свой собственный эпилог. Поэтому программисты или компиляторы часто используют комбинацию покинуть
и Ret
для выхода из функции в любой момент. (Например, C компилятор заменит возвращаться
заявление с покинуть
/Ret
последовательность).
дальнейшее чтение
- де Бойн Поллар, Джонатан (2010). "Угрозы генерации функций". Часто задаваемые ответы.