Использование turbo pascal с языком ассемблера. Встроенный ассемблер, страница 10

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

- Компилятор  не генерирует кадра стека для процедур и функций без параметров и локальных переменных.

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

push   bp

mov    bp,sp

sub    sp,Locals

...

mov    sp,bp

pop    bp

ret    Params

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

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

- Функции  порядкового  типа   (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.

Ассемблерная директива  во  многом   сравнима   с   директивой

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    a1,'z'

jb     @2

sub    a1,20H

@2:

stosb

loop

@3:

end;

end;

Второй пример  - это ассемблерная версия функции UpperCase.  В

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

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    a1,'a'

ja     @2

cmp    a1,'z'

jb     @2

sub    a1,20H

@2:

stosb

loop   @1

@3:

pop    ds

end;


ГЛАВА 23.

РЕДАКТИРОВАНИЕ АССЕМБЛЕРНОГО КОДА.

Процедуры и  функции,  написанные  на  ассемблере  могут  быть связаны  с  программами и модулями Turbo Pascal с помощью директивы компилятора  $L.  Исходный   файл   на   ассемблере   должен   быть ассемблирован в  объектный файл (.OВJ) с помощью Turbo Assembler. С

программой или модулем можно связать несколько объектных  файлов  с помощью нескольких директив $L.

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

function LoCase(Ch: Char): Char; external;

В соответствующей  исходной  программе  на   ассемблере,   все процедуры  и  функции  должны  быть расположены в сегменте с именем

CODE или CSEG,  или в сегменте,  чье имя оканчивается _TEXT и имена внешних процедур и функций должны быть в директиве PUBLIC.

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

(NEAR  или  FAR),  числу  параметров,  типу   параметров   и   типу результата.

Исходный файл на ассемблере может объявлять инициализированные переменные  в  сегменте  с  именем  CONST  или в сегменте,  чье имя оканчивается _DATA и неинициализированные переменные в  сегменте  с именем  DATA или DSEG,  или в сегменте,  чье имя оканчивается _BSS.