Учет особенностей компилятора
Полное описание процедуры
По-прежнему допустима сокращенная форма описания процедуры, при которой указывается только ее тип far или near Однако для того чтобы Макроассемблер взял на себя оформление текста процедуры, необходимо ее полное описание, которое имеет следующий вид:
метка PROC тип [спецификаторы] [, список_параметров]
Тип процедуры желательно указывать всегда, допустимые типы far, farie, far32, near, nearlG И near32. Имена far и near (без цифр) используются в тех случаях, когда тип процедуры соответствует типу сегмента, в котором она расположена. Тип сегмента, в свою очередь, зависит от модели памяти и директив 0.386,. 486,. 586.
Спецификаторы указывают тип языка (описан выше), доступность для других модулей (private, Public, Export) и аргументы пролога и эпилога. По умолчанию выбирается тип языка, описанный в директиве MODEL, общедоступная процедура public и стандартная форма пролога и эпилога, которая описана ниже.
Важно
Разделителями между именами типа и спецификаторов могут быть только пробелы. Первая запятая является признаком конца спецификаторов и начала списка параметров. При несоблюдении этого правила Макроассемблер выдает различные сообщения об ошибках и прерывает компиляцию модуля.
Список параметров по своему назначению аналогичен последовательности директив EQU, описанных в предыдущем разделе и позволяет использовать в основном тексте процедуры имена вместо ссылок на регистр bр. При его обработке Макроассемблер вычисляет смещение каждого параметра относительно регистра bp и подставляет нужные величины в команды подпрограммы. Если вы посмотрите листинг модуля, то увидите значения смещений для всех перечисленных в списке имен.
Параметры должны иметь уникальные имена, отличающиеся от других имен, описанных в данном модуле. После каждого имени указывается символ "двоеточие" и размер параметра (word, dword и т. п.). Если это не сделано, то по умолчанию размер параметра зависит от разрядности сегмента, в котором расположена процедура, – word для 16-разрядных и dword для 32-разрядных сегментов.
Таким образом, в полном описании процедуры появились два наиболее важных элемента – тип языка и список фактических параметров. Они содержат исчерпывающую информацию о способе компиляции процедуры.
Пролог и эпилог
В процессе компиляции подпрограммы Макроассемблер включает в объектный модуль две группы команд, одна из которых называется прологом (prologue), а другая эпилогом (epilogue). Пролог вставляется перед основным текстом подпрограммы, а эпилог перед командой ret. Вставляемые команды вам уже известны.
Стандартный вариант пролога содержит следующие две команды:
push bp; сохранение исходного содержимого bx mov bp, sp; bx = адрес верхушки стека
Соответственно эпилогом являются команды:
pop bp; восстановление содержимого регистра bx ret N; изменение команды ret зависит от langtype
Если значением Langtype является Basic, Fortran или Pascal, то при формировании эпилога к команде ret будет добавлен суммарный размер параметров в байтах для очистки стека при возврате из подпрограммы. Если значением Langtype является С, то команда ret не изменяется, а в текст вызывающего модуля вставляется команда add sp, N.
Обычно команды пролога и эпилога отсутствуют в листинге. Для того чтобы они в нем оказались в начале текста модуля, укажите директиву .Listaii (точка перед именем обязательна).
Пролог и эпилог можно как исключить, так и расширить. Для исключения пролога в текст модуля перед описанием сегмента включается директива:
OPTION PROLOGUE: NONE
Аналогичная директива существует и для эпилога, но ее использовать не обязательно. Макроассемблер вставляет эпилог только перед командой ret, поэтому для исключения эпилога достаточно использовать имена retn, retf или ret N, в зависимости от обстоятельств. Обратите внимание, наличие или отсутствие эпилога не влияет на включение команды add sp, N, поскольку она расположена в другом программном модуле.
В пролог можно добавить сохранение в стеке содержимого используемых регистров, а в эпилог – их восстановление. Для этого в описание процедуры включается спецификатор USES, а после него перечисляются используемые в подпрограмме регистры.
Замечание
Разделителем между именами регистров является пробел, указание запятых не допустимо.
Если процедура содержит свой сегмент данных, то в пролог можно включить команды переопределения содержимого регистра ds, при этом в эпилог добавляется команда, восстанавливающая из стека исходное значение регистра ds. Для выполнения этих действий в описание процедуры включается спецификатор <ioadds> (угловые скобки обязательны).
Таким образом, пролог и эпилог позволяют не записывать в основном тексте вспомогательные действия, выполняемые при входе в процедуру и выходе из нее. Целесообразность включения команд пролога и эпилога решается в каждом конкретном случае с учетом назначения процедуры.