Ассемблерные прграммы
Ассемблерные подпрограммы - это процедуры и функции, объявленные с директивой
Assembler. В таких подпрограммах исполняемая часть не содержит begin... end и
состоит из единственного ассемблерного оператора asm... end. Например:
Function LongMul(X,Y:Integer):LongInt; Assembler;
asm
mov ax, X
imul Y {DX/AX содержат "длинный" результат}
end;
При компиляции ассемблерных подпрограмм выполняется ряд оптимизаций кода, в
том числе:
- параметры-значения строкового типа, а также длиной в 1, 2 и 4 байта не
копируются во временную память, т.е. внутри подпрограммы они считаются
параметрами-переменными ;
- компилятор не создает переменную @Result для результата функции, и ссылка
на эту переменную в ассемблерной функции недопустима; исключением являются
функции, возвращающие значения строкового типа, для них разрешается использовать
ссылку на @Result;
- генерируются следующие команды на входе в подпрограмму и на ее выходе:
push bp {Сохраняется ВР}
mov bp,sp {ВР содержит текущую границу стека}
sub sp,Locals {Резервируется часть стека для размещения локальных переменных}
.......
mov sp,bp {Восстанавливается граница стека}
pop bp {Восстанавливается ВР}
ret Params {Из стека удаляются параметры
подпрограммы и осуществляется выход из нее}
Здесь Locals - общая длина в байтах всех объявленных в подпрограмме локальных
переменных, a Params - длина (в байтах) всех формальных параметров. Если Locals
и Params равны нулю, входной код не создается, а выходной содержит единственную
инструкцию RET.
Все локальные переменные Турбо Паскаль размещает в стеке. Это относится как к
обычным, так и к ассемблерным подпрограммам. Для ссылки на локальные переменные
используется адресация по базе, задаваемой парой DS: ВР, поэтому при входе в
процедуру всегда создается так называемый
локальный стек: в регистр ВР
помещается текущая граница стека, а сама эта граница смещается вверх на
суммарную длину всех локальных переменных, чтобы работа со стеком внутри
подпрограммы не разрушила локальные переменные. Например:
Procedure ...;
Assembler;
var
X: Word;
Y: Byte;
asm
mov X, ax {Компилируется в mov [BP-2], ax}
mov ah,Y {Компилируется в mov ah,[BP-3]}
end;
Ассемблерные функции должны следующим образом возвращать результат своей
работы:
- длиной 1 байт (Byte, Char и т.п.) - в регистре
AL;
- длиной 2 байта (Integer, Word) - в регистре АХ;
- длиной 4 байта (Pointer,
LongInt) - в регистрах DX (старшее слово) и АХ
(младшее слово);
- типа Real - в регистрах DX, BX, АХ (старшее слово - в DX, младшее в АХ);
- вещественных типов Single, Double, Extended, Comp - в регистре ST (0)
сопроцессора;
- строкового типа - во временной области памяти, на которую ссылается
@Result.