MS-DOS и TASM 2.0. Часть 14. Конвенции вызова функции.

Функции в ассемблере реализация вызова различных конвенций.

Параметры функции.

Функции в ассемблере — это часть кода, которая решает конкретную задачу или несколько, объединённых одной целью задач. Функция может вызываться без дополнительного дублирования кода. Человек способен помнить, воспринимать  и использовать ограниченное число информации. Для облегчения понимания и создания кода его структурируют — дробят на определенные части. Функция — один из вариантов дробления кода — первый шаг к абстракции программы, упрощающий её структуру. Функция включает параметры.

Параметры функции:

  • Параметры ввода (Input Parameters или просто In) — может быть сколько угодно.
  • Параметры вывода (Output Parameters или просто Out) — может быть сколько угодно.
  • Возвращаемое значение (Return value или просто Return) — только одно.

Таким образом, «стандартная» функция «MyFunc» имеет вид:

  • return MyFunc (In,  In, Out, Out, In, Out,…);

Указанная (Си-подобная) структура функции условна. Любой из параметров может отсутствовать. Функция вообще может не иметь параметров.

Реализация вызовов функции в ассемблере.

Кроме параметров имеет значение алгоритм работы функции, так называемое «соглашение о вызове функции». Оно связано с построением работы в различных операционных системах различных высокоуровневых языков программирования.

В настоящее время существуют целый ряд принятых соглашений (конвенций) о вызове функций (подпрограмм): cdecl (язык Си, С++), pascal (язык Pascal), stdcall (WinApi), fastcall, safecall, thiscall. Все они начинали использоваться в разное время и с разными целями, решая определённые задачи, наиболее приемлемым способом.

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

Изучить примеры работы компиляторов языков высокого уровня крайне полезно, если вас интересует кодокопание в любом виде (крэкинг, реверс-программирование и др.) .

Передача параметров через регистры.

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

Функция (процедура) содержит два параметра:
myFunc (a,b)

Такой код имеет несколько недостатков, основной из которых — ограничение количества параметров (не больше, чем регистров). Есть и другие, менее очевидные сложности, которые мы не будем обсуждать в рамках этой статьи.

Из плюсов передачи параметров (и возврата значений) функции в ассемблере через регистры можно назвать скорость работы кода.

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

КонвенцияПередача параметровОсвобождение стека
CDECLзагоняются в стек слева направо — снизу вверхвызывающая программа
PASCALзагоняются в стек слева направо — сверху внизсама процедура
STDCALзагоняются в стек слева направо — снизу вверхсама процедура

Конвенция вызова функций PASCAL (Pascal, Basic, Fortran и др.).

Параметры загоняются в стек слева направо — сверху вниз, стек очищается вызываемой функцией:

Функция (процедура) содержит пять параметров:
myFunc (a,b,c,d,e)

Конвенция вызова функций CDECL (Си, С++ и др.).

Параметры загоняются в стек слева направо — снизу вверх, стек очищается вызывающая функция:

Функция (процедура) содержит пять параметров:
myFunc (a,b,c,d,e)

Конвенция вызова функций STDCALL (WinApi : Windows 95 — Windows 10).

Операционная система Windows содержит набор встроенных функций, которые обеспечивают удобство программирования, обслуживания и работы системы — так называемые WinApi — Windows Application programming interfaces.

Функций огромное количество. Они входят в стандартный пакет Windows любой версии и содержаться в библиотеках *.dll, расположенных в системных директориях Windows (System, System32, SysWOW64 — для 64 битной системы). Например, kernel32.dll содержит огромное количество функций, входящих в т.н. «Ядро операционной системы», например MoveFile — «переместить файл».

Для операционной системы Windows (WinApi) был разработана отдельная конвенция вызова функций. Она включила в себя преимущества PASCAL и С (Си) конвенций.

Конвенция STDCALL (WinApi) имеет следующие особенности.

Параметры загоняются в стек слева направо — снизу вверх, стек очищается вызываемая функция.

К слову можно сказать, что возвращаемое функцией WinApi значение содержиться в 32 битном регистре eax (нам он пока не известен, но это расширенный до 32 бит регистр ax).

Функция (процедура) содержит пять параметров:
myFunc (a,b,c,d,e)

Преимущество C (Си) конвенции по сравнению с PASCAL.

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

Например, если вызываются несколькл функций подряд, принимающих одни и теже параметры, можно не заполнять стек заново:

2. Более просто создавать функции с изменяемым числом параметров (printf).

Преимущество PASCAL конвенции по сравнению с C (Си).

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

Реализация конвенции PASCAL встроена в TASM с помощью макро-возможностей. Практическая реализация и код рассмотрены в статье «MS-DOS и TASM 2.0. Часть 18. Упрощаем вызов функции в TASM«.

Преимущество STDCALL конвенции.

1. Создана специально для Windows API, достаточно удобна, поддерживается макрокомандами наиболее используемых для программирования современных Windows приложений ассемблерами MASM32, FASM.

Очень скоро мы перейдём от 16 битного DOS программирования к 32 битному программированию для Windows, где будет использоваться преимущественно именно конвенция STDCALL (WinApi), хотя никто не запрещает Вам использовать любые способы организации вызова функции в ассемблере с любым видом передачи параметров и освобождения стека.

Добавить комментарий