Стековый фрейм и соглашения о вызове функций

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

Наиболее часто используется так называемое соглашение о вызове функций языка C (C declaration syntax). Параметры функции, объявленной в стиле языка С, записываются в стек в обратном порядке (справа налево, то есть первый параметр записывается в стек последним). Для вызванной функции это удобно, потому что в подобном случае первый параметр выталкивается из стека в первую очередь. По завершении функции вызывающая программа очищает стек, зная число и тип ранее размещенных в стеке параметров. Описанное соглашение о вызове функций позволяет передать ей переменное число параметров. Этот вариант по умолчанию используется для генерации кода MS Visual C/C++ и широко распространен на многих платформах. Иногда его называют синтаксисом вызова cdecl (cdecl calling syntax). Функция printf() является примером функции, которая использует синтаксис cdecl для обработки переменного числа параметров. По завершении функции printf() вызвавшая ее программа очищает стек.

Другое широко используемое соглашение о вызове функций получило название синтаксиса стандартного вызова (standard call syntax). Аналогично синтаксису cdecl переданные функции параметры записываются в стек в обратном порядке. Разница состоит в том, что вызванная функция изменяет указатель стека до своего завершения. Иногда это удобно, поскольку в вызывающей программе не надо думать, как правильно изменить указатель стека. Кроме того, это позволяет локализовать программный код изменения стека в вызванной функции. Большинство функций WIN32 API написано с использованием синтаксиса стандартного вызова, иногда известного как stdcall.

Третий вариант соглашения о вызове функций получил название синтаксиса быстрого вызова (fast call syntax). Он схож на синтаксис стандартного вызова тем, что вызываемая функция перед своим завершением очищает стек, но отличается способом записи параметров в стек. Первые два параметра функции передаются через регистры, поэтому они в стек не записываются и вызываемая функция обращается к первым двум параметрам через регистры, в которые они были помещены. Синтаксис быстрого вызова часто используется в программном коде Delphi-программ и в пространстве ядра операционной системы NT (пространство ядра (kernel space) – блок виртуальной памяти, отведенный для использования программного ядра в привилегированном режиме).

Наконец, следует упомянуть о явном порядке (синтаксисе) вызова функций (naked syntax). На самом деле этот вариант соглашения о вызове функций не придерживается никаких правил вызова, поскольку при его использовании не предполагается генерации стандартных команд вызова функций. Явный порядок вызова функций заставляет программиста самостоятельно учитывать все нюансы обращения к функциям. Он редко используется, и если предполагается его использовать, то на это должны быть веские причины, например поддержка очень старого участка выполнимого программного кода.

Загрузка...