Соглашение вызова

Соглашение вызова

Соглашение вызова или модель вызова (англ. Calling convention) — часть двоичного интерфейса приложений, которая регламентирует технические особенности вызова подпрограммы, передачи параметров, возврата из подпрограммы и передачи результата вычислений в точку вызова.

Содержание

Состав соглашения вызова

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

  • Расположение входных параметров подпрограммы и возвращаемых ею значений. Наиболее распространённые варианты:
  • Порядок передачи параметров. При использовании для параметров стека определяет, в каком порядке параметры должны быть помещены в стек, при использовании регистров — порядок сопоставления параметров и регистров. Варианты:
    • прямой порядок — параметры размещаются в том же порядке, в котором они перечислены в описании подпрограммы. Преимущество — единообразие кода и записи на языке высокого уровня;
    • обратный порядок — параметры передаются в порядке от конца к началу. Преимущество — при любом количестве параметров на вершине стека после адреса возврата оказывается сначала первый параметр, за ним второй и так далее. Это упрощает реализацию подпрограмм с неопределённым числом параметров произвольных типов.
  • Кто возвращает указатель стека на исходную позицию:
    • вызываемая подпрограмма — это сокращает объём команд, необходимых для вызова подпрограммы, поскольку команды восстановления указателя стека записываются только один раз, в конце подпрограммы;
    • вызывающая программа — в этом случае вызов становится сложнее, но облегчается использование подпрограмм с переменным количеством и типом параметров.
  • Какой командой вызывать подпрограмму и какой — возвращаться в основную программу. Например, в стандартном режиме x86 подпрограмму можно вызвать через call near, call far и pushf/call far (для возврата применяются соответственно retn, retf, iret).
  • Содержимое каких регистров процессора подпрограмма обязана восстановить перед возвратом.

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

Когда это важно

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

Наиболее распространённые соглашения вызова на 32-битном x86

Список неполный, написаны основные из применяемых по сей день.

Во всех нижеперечисленных соглашениях(кроме cdecl) подпрограмма обязана обеспечить восстановление перед возвратом значений сегментных регистров процессора, а также регистров ESP и EBP. Значения остальных могут не восстанавливаться. Возвращаемое значение функции хранится в регистре eax. Если его размер слишком велик для размещения в регистре, то оно размещается на верхушке стека, а значение в регистре eax будет указывать на него.

cdecl

Основной способ вызова для Си (отсюда название, сокращение от «c-declaration»). Аргументы передаются через стек, справа налево. Очистку стека производит вызывающая программа. Это основной способ вызова функций с переменным числом аргументов (например, printf(…))

pascal

Основной способ вызова для Паскаля, также применялся в Windows 3.x. Аргументы передаются через стек, слева направо. Указатель стека на исходную позицию возвращает подпрограмма. Причём, изменяемые параметры передаются только по ссылке, а у функций неявно создаётся дополнительный первый изменяемый параметр Result, через который и возвращается значение.

stdcall/winapi

Применяется при вызове функций WinAPI. Аргументы передаются через стек, справа налево. Очистку стека производит вызываемая подпрограмма.

fastcall

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

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

В компиляторе Borland, для соглашения __fastcall, называемого также register,[1] параметры передаются слева направо в eax, edx, ecx и, если параметров больше трёх, в стеке, также слева направо. Указатель стека на исходное значение возвращает вызываемая подпрограмма.

Fastcall Borland применяется по умолчанию в Delphi.

Соглашение __fastcall Microsoft, также называемое __msfastcall, в 32-хразрядной версии компилятора Microsoft,[2] а также компилятора GCC,[3] определяет передачу первых двух параметров слева направо в ecx и edx, а остальные параметры передаются справа налево в стеке. Очистку стека производит вызываемая подпрограмма.

Для x64 целей компилятор Microsoft VisualStudio 2010 CL принимает данное соглашение по умолчанию, остальные игнорируются, даже если заданы явно. Передача параметров в данном случае происходит при помощи 4х 64х разрядных регистра: rcx, rdx, r8, r9. В случае если параметров больше — остальные передаются через стек.

safecall

Обеспечивает более удобный для использования в распространённых языках высокого уровня способ вызова методов интерфейсов при использовании модели COM.

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

Можно считать, что вызов

function DoSomething(a: DWORD): DWORD; safecall;

в действительности представляет собой вызов

function DoSomething(a: DWORD; out Result: DWORD): HResult; stdcall;

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

thiscall

Используется в компиляторах C++. Обеспечивает передачу аргументов при вызовах методов класса в объектно ориентированной среде. Аргументы передаются через стек, справа налево. Очистку стека производит вызываемая функция, то есть тот же самый stdcall. Указатель (this) на объект, для которого вызывается метод, записывается в регистр ECX [4].

Примечания

  1. Program Control: Register Convention. docwiki.embarcadero.com (1 июня 2010). Архивировано из первоисточника 20 ноября 2012. Проверено 27 сентября 2010.
  2. __fastcall. msdn.microsoft.com. Архивировано из первоисточника 20 ноября 2012. Проверено 27 сентября 2010.
  3. Ohse, Uwe gcc attribute overview: function fastcall. ohse.de. Архивировано из первоисточника 20 ноября 2012. Проверено 27 сентября 2010.
  4. thiscall (C++)  (англ.). msdn.microsoft.com.



Wikimedia Foundation. 2010.

Игры ⚽ Нужна курсовая?

Полезное


Смотреть что такое "Соглашение вызова" в других словарях:

  • Лондонское соглашение — документ из 22 статей, регламентирующий условия проведения матчей на первенство мира по шахматам среди мужчин. Составлено и подписано чемпион мира X. Р. Капабланкой и несколькими сильнейшими шахматистами мира того времени… …   Википедия

  • БАРРЕРА - ПРИНЕТТИ СОГЛАШЕНИЕ 1902 — заключено между Францией и Италией 1 2. XI. Италия не была удовлетворена своим положением в Тройственном союзе (см.). Встретив сопротивление со стороны Австро Венгрии своим попыткам расширить колониальные владения за счёт Турции, Италия стала… …   Дипломатический словарь

  • БАРРЕРА-ПРИНЕТТИ СОГЛАШЕНИЕ 1902 — секретное соглашение между Францией и Италией, заключенное 1 2 нояб. путем обмена письмами между франц. послом в Риме Баррером (Barrere) и итал. мин. иностр. дел Принетти (Prinetti). Предусматривало взаимный нейтралитет Франции и Италии в случае …   Советская историческая энциклопедия

  • франко-итальянское соглашение 1902 — франко итальянское соглашение 1902, о разделе сфер влияния в Северной Африке. Явилось развитием соглашения 1900, по которому Франция признавала итальянские притязания наТриполитанию и Киренаику, а Италия — притязания Франции на Марокко. По Ф …   Энциклопедический справочник «Африка»

  • Стековый кадр — (англ. stack frame) механизм передачи аргументов и выделения временной памяти (в процедурах языков программирования высокого уровня) с использованием системного стека. Содержание 1 Технология 1.1 Передача аргументов …   Википедия

  • Подпрограмма — (англ. subroutine)  поименованная или иным образом идентифицированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы. В языках… …   Википедия

  • Процедура (программирование) — Подпрограмма (англ. subprogram)  поименованная или иным образом идентифицированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы. В языках… …   Википедия

  • Стек вызовов — (от англ. call stack; применительно к процессорам  просто «стек»)  в теории вычислительных систем, LIFO стек, хранящий информацию для возврата управления из подпрограмм (процедур) в программу (или подпрограмму, при вложенных или… …   Википедия

  • Type library — У этого термина существуют и другие значения, см. библиотека (значения). TLB (англ. Type Library  библиотека типов)  иерархическое хранилище информации о возможностях ActiveX сервера в OLE Automation. Библиотека типов  одно из …   Википедия

  • Двоичный интерфейс приложений — Двоичный (бинарный) интерфейс приложений (англ. Application Binary Interface, англ. ABI)  набор соглашений между программами, библиотеками и операционной системой, обеспечивающих взаимодействие этих компонентов на низком уровне на… …   Википедия


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»