Соглашение вызова
Соглашение вызова или модель вызова (англ. Calling convention) — часть двоичного интерфейса приложений, которая регламентирует технические особенности вызова подпрограммы, передачи параметров, возврата из подпрограммы и передачи результата вычислений в точку вызова.
Состав соглашения вызова
Соглашение вызова определяет следующие особенности процесса использования подпрограмм:
- Расположение входных параметров подпрограммы и возвращаемых ею значений. Наиболее распространённые варианты:
- Порядок передачи параметров. При использовании для параметров стека определяет, в каком порядке параметры должны быть помещены в стек, при использовании регистров — порядок сопоставления параметров и регистров. Варианты:
- прямой порядок — параметры размещаются в том же порядке, в котором они перечислены в описании подпрограммы. Преимущество — единообразие кода и записи на языке высокого уровня;
- обратный порядок — параметры передаются в порядке от конца к началу. Преимущество — при любом количестве параметров на вершине стека после адреса возврата оказывается сначала первый параметр, за ним второй и так далее. Это упрощает реализацию подпрограмм с неопределённым числом параметров произвольных типов.
- Кто возвращает указатель стека на исходную позицию:
- вызываемая подпрограмма — это сокращает объём команд, необходимых для вызова подпрограммы, поскольку команды восстановления указателя стека записываются только один раз, в конце подпрограммы;
- вызывающая программа — в этом случае вызов становится сложнее, но облегчается использование подпрограмм с переменным количеством и типом параметров.
- Какой командой вызывать подпрограмму и какой — возвращаться в основную программу. Например, в стандартном режиме x86 подпрограмму можно вызвать через
call near
,call far
иpushf/call far
(для возврата применяются соответственноretn
,retf
,iret
). - Содержимое каких регистров процессора подпрограмма обязана восстановить перед возвратом.
Соглашения вызова зависят от архитектуры целевой машины и компилятора.
Когда это важно
- При оптимизации программы — выбирается лучшее по параметру оптимизации (скорости, количеству команд) соглашение вызова из доступных.
- При сопряжении программы с написанной на другом языке подпрограммой — программе необходимо соблюдать соглашение вызова, которое использовалось при компиляции подпрограммы.
- При вызове функций стандартных системных библиотек (например, функций API).
- При обратной разработке программы — зависящие от соглашения вызова последовательности команд, генерируемые компилятором, позволяют идентифицировать стандартные операции языка высокого уровня.
Наиболее распространённые соглашения вызова на 32-битном x86
- Список неполный, написаны основные из применяемых по сей день.
Во всех нижеперечисленных соглашениях подпрограмма обязана обеспечить восстановление перед возвратом значений сегментных регистров процессора, а также регистров ESP
и EBP
. Значения остальных могут не восстанавливаться. Возвращаемое значение функции хранится в регистре eax
. Если его размер слишком велик для размещения в регистре, то оно размещается на верхушке стека, а значение в регистре eax
будет указывать на него.
cdecl
Основной способ вызова для Си (отсюда название, сокращение от «c-declaration»). Аргументы передаются через стек, справа налево. Очистку стека производит вызывающая подпрограмма. Это основной способ вызова функций с переменным числом аргументов (напр. printf(...))
pascal
Основной способ вызова для Паскаля, также применялся в Windows 3.x. Аргументы передаются через стек, слева направо. Указатель стека на исходную позицию возвращает подпрограмма.
stdcall/winapi
Применяется при вызове функций Win32 API. Аргументы передаются через стек, справа налево. Очистку стека производит вызываемая подпрограмма.
fastcall
Передача параметров через регистры, обычно самая быстрая; если все параметры и промежуточные результаты умещаются в регистрах, манипуляции со стеком вообще не нужны. Fastcall не стандартизирован, поэтому используется только в функциях, которые программа не экспортирует наружу. Например, у Borland параметры передаются слева направо в eax
, edx
, ecx
и, если параметров больше трёх, в стеке. Указатель стека на исходное значение возвращает подпрограмма.
Fastcall Borland применяется по умолчанию в Delphi.
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.
Программирование | Это незавершённая статья о программировании. Вы можете помочь проекту, исправив и дополнив её. |
bg:Конвенции на извикване de:Aufrufkonvention en:Calling convention ja:呼出規約
Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....