Руководство по языку B.Pascal 7

         

Процедуры и функции ассемблера


До сих пор мы рассматривали конструкцию asm...end, как опе- ратор с обычной частью begin...end. Директива assembler в Borland Pascal позволяет вам писать на встроенном ассемблере целиком про- цедуры и функции без необходимости begin...end. Приведем пример функции на ассемблере:

function LongMul(X, Y: Integer) : Longint; assembler; asm mov ax,X imul Y end;

Директива assembler приводит к тому, что Borland Pascal вы- полняет при генерации кода следующую оптимизацию:

- Компилятор не генерирует код для копирования парамет- ров-значений в локальные переменные. Это влияет на все па- раметры-значения строкового типа и другие значения-пара- метры, размер которых не равен 1, 2 или 4 байтам. Внутри процедуры или функции такие параметры должны интерпретиро- ваться, как если бы они были параметрами-переменными.

- Компилятор не выделяет память для результата функции, и ссылка на идентификатор @Result будет ошибкой. Однако строковые функции являются исключением из этого правила - они всегда имеют указатель @Result, который распределяется пользователем.

- Для процедур и функций, не имеющих параметров и локальных переменных, компилятор не генерирует кадров стека.

- Для процедуры и функции на ассемблере автоматически гене- рируется код выхода:

push bp ; присутствует, если Locals <> 0 или ; Params <> 0 mov bp,sp ; присутствует, если Locals <> 0 или ; Params <> 0 sub sp,Locals ; присутствует, если Locals <> 0 ... mov sp,bp ; присутствует, если Locals <> 0 pop bp ; присутствует, если Locals <> 0 или ; Params <> 0 ret Params ; всегда присутствует

где Locals - размер локальных переменных, а Params - раз- мер параметров. Если и Locals и Params = 0, то кода входа не будет, и код выхода состоит просто из инструкции RET.

Функции, использующие директиву assembler, должны возвращать результат следующим образом:

- результаты функции порядкового типа (Integer, Char, Boolean, перечислимые типы) возвращаются в AL (8-разрядное значение), AX (16-разрядное значение) или DX:AX (32-раз- рядное значение);


- результаты функции вещественного типа (Real) возвращаются в DX:BX:AX;

- результаты функции типов 8087 (Single, Double, Extended, Comp) возвращаются в ST(0) (регистр стека сопроцессора 8087);

- результаты функции типа указатель возвращаются в DX:AX;

- результаты функции строкового типа возвращаются во времен- ной ячейке, на которую указывает @Result.

Директива assembler во многом похожа на директиву external. Процедуры и функции на ассемблере должны должны подчиняться тем же правилам, что и процедуры и функции типа external. Следующие примеры показывают некоторые отличия операторов asm в обычных процедурах и функциях от процедур и функций ассемблера. В первом примере оператор asm используется в обычной функции для преобра- зования строки в верхний регистр. Заметим, что значение параметра Str в этом случае ссылается на локальную переменную, поскольку компилятор автоматически генерирует код входа, копирующий факти- ческий параметр в локальную память.

function UpperCase(Str: String): String; begin asm cld lea si,Str les di,@Result SEGSS lodsb stosb xor ah,ah xchg ax,cx jcxz @3 @1: SEGSS lodsb cmp al,'a' ja @2 cmp al,'a' ja @2 cmp al,'z' jb @2 sub al,20H @2: stosb loop @1

@3: end; end;

Второй пример на ассемблере представляет собой версию функ- ции UpperCase. В этом случае Str не копируется в локальную па- мять, и функция должна интерпретировать Str, как параметр-пере- менную.

function UpperCase(S: String): String; assembler; asm push ds cld lds si,Str les di@Result lodsb stosb xor ah,ah xchg ax,cx jcxz @3 @1: lodsb cmp al,'a' ja @2 cmp al,'z' jb @2 sub al,20H @2: stosb loop @1 @3: pop ds end;






Содержание раздела