Соглашены о передаче параметров, принятые в Borland Pascal

Borland Pascal выполняет передачу параметров, используя стек процессора или сопроцессора (для параметров типа Single, Double, Extended или Coinp). Параметры всегда вычисляются и помещаются в стек в том порядке, в котором они использованы в объявлении процедуры, т. е. слева направо.

19.2.1. Параметры-значения и параметры-переменные

Параметры значения — это параметры, значение которых нельзя изменить подпрограммой, в которую они передаются. Так же, как и другие компиляторы, Borland Pascal не всегда передает эти параметры в подпрограмму только с использованием стека процессора, конкретный метод определяется типом этих параметров.

Параметры-значенияскалярного типа (Boolean, Char, Shortint, Byte, Integer, Word, Longint и перечислимые типы) передаются в процедуру путем помещения их значения в стек. Если при этом размер параметра составляет 1 байт, то он помещается в стек в виде целого слова, но информация, содержащаяся в старшем байте этого слова, не может быть использована. Параметры размером в 2 и 4 байта помещаются в стек в виде слова и двойного слова соответственно. По соглашениям, принятым для процессора 8086, первым в стек помещается старшее слово четырехбайтных параметров.

Параметры-значениявещественного типа Real помещаются в стек в виде шести-бпйтного значения. Для всех остальных типов (Single, Double, Extended и C-onip) выполняются стандартные для компиляторов Borland соглашения — они передаются в стек процессора вместе с другими параметрами командами вызова сопроцессора.

Параметры-значенияуказателей всех типов помещаются в стек в виде дальних указателей - сначала слово, содержащее сегмент, затем слово, содержащее смещение. Таким образом, по соглашениям Intel, значение сегмента занимает старший адрес. Для загрузки значения указателя ассемблерные программы могут использовать командыLDS илиLES.

Строковые параметры, независимо от их размера, никогда не помещаются непосредственно в стек. Вместо этого Borland Basca) помещает в стзк указатель на строку, имеющий тип FAR. Вызываемая подпрограмма не должна изменять значение строки, описываемое данным указателем, и при необходимости может работать с копией этой строки.

Записи, массивы и объекты, имеющие размер 1, 2 или 4 байта, передаются непосредственно через стек. Для всех других размеров (включая 3 байта) в стек помещается указатель, причем для модификации этих параметров в таком случае необходимо использовать их локальную копию.

Множества так же, как и строки, никогда не передаются через стек непосредственно, а только с помощью указателя, который адресует 32-байтовое представление множества. Первый бит младшего байта в таком представлении всегда соответствует базовому элементу множества с порядковым чилимт""" "

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

19.2.2. Работа со стеком

По соглашениям, принятым в Borland Pascal, вызываемая процедура должна перед возвратом управления выполнить очистку стека от переданных в нее параметров.

Для этого можно использовать два способа. Первый из них заключается в применении командыRET n, где n - это размер переданных параметров в байтах. Вторым способом является сохранение адреса возврата в регистре или в памяти и последовательное извлечение всех параметров процедуры из стека с помощью команды POP. Применение командPOP позволяет выполнить оптимизацию программы по скорости, а также уменьшает размер подпрограммы, поскольку каждая из них занимает всего один байт.

При использовании директив.MODEL, PROC и ARG Turbo Assembler автоматически добавляет нужное значение во все командыRET подпрограммы.

19.2.3. Осуществление доступа к параметрам из ассемблерных процедур

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

Для доступа к этим параметрам Turbo Assembler поддерживает три метода:

• с использованием регистра ВР;

• с использованием другого базового или индексного регистра;

• с помощью командPOP.

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

Пример использования регистраВР:

CODE SEGMENT

ASSUME cs:CODE AsmProc PROC FAR ;procedure AsmProc(i,j :word);

PUBLIC AsmProc j EQU WORD PTR [BP+6] i EQU WORD PTR [BP+8]

push bp

mov bp,sp

mov ax,i

В приведенном примере для обращения к параметрам использованы текстовые ' выражения, что позволяет улучшить читаемость текста программы. Для создания таких выражений может использоваться только директиваEQU, которая; с отличие от директивы =, не позволяет переопределять идентификаторы, однажды определенные в данном модуле. При использовании такого способа описания параметров необходимо задавать несовпадающие мнемонические имена переменных в процедурах ассемблерного модуля или помещать каждую процедуру в отдельный срайл.

Более удобно для использования базовой адресации через регистр ВР для вы полнения доступа к параметрам применение директивыARG. Если в процедуре используется директиваARG, то Turbo Assembler автоматически определяет смещение указанных в ней параметров относительно содержимого регистра ВР, а также вычисляет размер всего блока параметров для последующего использования в ко мандеRET. При использовании этой директивы отпадает необходимость указыва-п. неповторяющиеся имена для обозначения параметров разных процедур.

Предыдущий пример с использованием директивыARG имеет следующий вид:

CODE SEGMENT

ASSUME cs:CODE I AsmProc PROC FAR ;procedure AsmProc (i;j:word);

PUBLIC AsmProc

ARG j:WORD, i:WORD = RetBytes

push bp

mov bp,sp

mov ax,i

Директива Turbo AssemblerARG связывает идентификаторы i и / с передавав мыми в процедуру параметрами. Строка

ARG j:WORD, i:WORD=RetBytes

автоматически назначает идентификатору i значение WORD PTR [BP + б], идентификатору^ — значение WORD PTR [ВР+8], а идентификатору RetByres - значение 4 (общий размер блока параметров в байтах) для дальнейшего использования в процедуре. Указанные значения включают вычисления, необходимые для учета помещения в стек регистра BP и адреса возврата. Если изменить тип процедуры на NEAR, то идентификатор г автоматически приобретет значение [BP + 4], а/ — [BP + G).

ДирективаARG должна указывать параметры в порядке, обратном тому, который используется в списке параметров объявления этой процедуры или функции в модуле Borland Pascal. Таким образом, последний параметр процедуры Pascal должен быть первым в директивеARG ассемблерного модуля и т. д.

Второй особенностью применения директивыARG в ассемблерных процедурах, предназначенных для вызова из Borland Pascal, является необходимость дополнения байтовых параметров до размера слова. Например, если в программе на Borland Pascal объявлена функция

function AsmProc (i,j :Char):string; external;

то директиваARG в ассемблерном тексте этой функции должна иметь следующий вид:

ARJ j:byte:.2, i:byte:2 = RetBytes RETURNS ResStr: DWORD

Указание ":2" после каждого аргумента заставляет Turbo Assembler генерировать команды для размещения каждого аргумента в стеке в виде слова, старший байт которого имеет неопределенное значение.

Функции, возвращающие значение типа String (подобно указанной в примере), могут использовать необязательный параметрRETURNS директивыARG, который позволяет применять символьное имя, эквивалентное временному указателю на результат функции. Переменная, указанная вRETURNS, не влияет на суммарный размер блока переменных директивыARG.

Еще более удобна для разработки ассемблерных процедур, предназначенных для вызова из Borland Pascal, директива.MODEL. Для программ Borland Pascal в качестве модели памяти следует всегда выбирать модель LAR-GE.

Пример ассемблерной функции, в которой используется'директива.MODEL:

.MODEL LARGE.PASCAL •CODE

AsmProc PROC FAR i:byte,j:byte RETURNS result:DWORD PUBLIC AsmProc mov ax,i

ret

Как можно заметить, использование директивы.MODEL позволяет описывать параметры процедуры прямо при ее объявлении директивойPROC, причем параметры в объявлении следуют в том же порядке, в котором они указаны в Pascal- модуле. Кроме того, выбор модели PASCAL приводит к автоматической генерации кодов пролога и эпилога процедуры.

В качестве базового регистра для доступа к параметрам процедуры используются регистры ВХ, SI или DI. Единственная особенность использования этих регистров заключается в том, что все они по умолчанию используют регистр. DS, а не SS. По этой причине при применении регистров ВХ, SJ или DI в качестве базовых необхо-

димо указывать префикс переопределения сегмента или загружать регистр SS нужным значением.

Пример использования регистра ВХ в качестве базового:

CODE SEGMENT

ASSUME cs:CODE AsmProc PROC FAR

iprocedure AsmProc (i,j: integer);

PUBLIC AsmProc j EQU WORD PTR ss:[bx+4] i EQU WORD PTR ss:[bx+6]

mov bp.sp

mov ax,i

Такой подход оправдан в случае применения небольших по размеру процедур,

поскольку при использовании регистра ВХ нет необходимости в сохранении и восстановлении его содержимого, как для регистра ВР.

Наши рекомендации