Страница 29 из 54
lea bx,DestString ; самый левый параметр
lea ax,SourceString ; самый правый параметр
call strcpy pascal,bx,ax
Турбо Ассемблер 3.0/tasm/#2-2 = 114 =
Турбо Ассемблер автоматически вставит команды помещения ар-
гументов в стек в последовательности, принятой в Паскале (сначала
BX, затем AX), и выполнит вызов STRCPY (преобразуя имя к верхнему
регистру, как принято в соглашениях Паскаля).
В последнем случае конечно подразумевается, что вы переком-
пилировали функцию strcpy с параметром -p, так как в стандартной
библиотечной версии данной функции используются соглашения по вы-
зову, принятые в С++, а не в Паскале.
Функции С++ сохраняют следующие регистры (и только их): SI,
DI, BP, DS, SS, SP и CS. Регистры AX, BX, CX, DX, ES и флаги мо-
гут произвольно изменяться.
Вызов из Турбо Ассемблера функции Borland C++
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Одним из случаев, когда вам может потребоваться вызвать из
Турбо Ассемблера функцию Borland C++, является необходимость вы-
полнения сложных вычислений, поскольку вычисления гораздо проще
выполнять на С++, чем на Ассемблера. Особенно это относится к
случаю смешанных вычислений, где используются и значения с плава-
ющей точкой и целые числа. Лучше возложить функции по выполнению
преобразования типов и реализации арифметики с плавающей точкой
на С++.
Давайте рассмотрим пример программы на Ассемблере, которая
вызывает функцию Borland C++, чтобы выполнить вычисления с плава-
ющей точкой. Фактически в данном примере функция Borland C++ пе-
редает последовательность целых чисел другой функции Турбо Ас-
семблера, которая суммирует числа и в свою очередь вызывает
другую функцию Borland C++ для выполнения вычислений с плавающей
точкой (вычисление среднего значения).
Часть программы CALCAVG.CPP, реализованная на С++
(CALCAVG.CPP), выглядит следующим образом:
#include
; значение
add ax,2 ; ссылка на следующее
; значение
loop AverageLoop
push WORD PTR [bp+8] ; получить снова число
; значений, переданных
; в функцию IntDivide
; в правом параметре
push ax ; передать сумму в
; левом параметре
call _IntDivide ; вычислить среднее
; значение с плавающей
; точкой
add sp,4 ; отбросить параметры
pop bp
ret ; среднее значение в
; регистре вершины
; стека сопроцессора
; 8087
Турбо Ассемблер 3.0/tasm/#2-2 = 116 =
_Average ENDP
END
Основная функция (main) на языке С++ передает указатель на
массив целых чисел TestValues и длину массива в функцию на Ас-
семблере Average. Эта функция вычисляет сумму целых чисел, а за-
тем передает эту сумму и число значений в функцию С++ IntDivide.
Функция IntDivide приводит сумму и число значений к типу с плава-
ющей точкой и вычисляет среднее значение (делая это с помощью од-
ной строки на С++, в то время как на Ассемблере для этого потре-
бовалось бы несколько строк). Функция IntDivide возвращает сред-
нее значение (Average) в регистре вершины стека сопроцессора 8087
и передает управление обратно основной функции.
Программы CALCAVG.CPP и AVERAGE.ASM можно скомпилировать и
скомпоновать в выполняемую программу CALCAVG.EXE с помощью коман-
ды:
bcc calcavg.cpp average.asm
Отметим, что функция Average будет работать как с малой, так
и с большой моделью данных без необходимости изменения ее исход-
ного кода, так как во всех моделях передается указатель дальнего
типа. Для поддержки больших моделей кода (сверхбольшой, большой и
средней) пришлось бы только изменить соответствующую директиву
.MODEL.
Пользуясь преимуществами расширений, обеспечивающих незави-
симость Турбо Ассемблера от языка, ассемблерный код из предыдуще-
го примера можно записать более сжато (CONSISE.ASM):
.MODEL small,C
EXTRN C IntDivide:PROC
.CODE
PUBLIC C Average
Average PROC C ValuePtr:DWORD, NumberOfValues:WORD
les bx,ValuePtr
mov cx,NumberOfValues
mov ax,0
AverageLoop:
add ax,es:[bx]
add bx,2 ;установить указатель
;на следующее значение
loop AverageLoop
call _IntDivide C,ax,NumberOfValues
ret
Average ENDP
END
Турбо Ассемблер 3.0/tasm/#2-2 = 117 =
Глава 19. Интерфейс Турбо Ассемблера с Турбо Паскалем
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
В Турбо Ассемблере предусмотрены расширенные и мощные
средства, позволяющие вам добавлять код Ассемблера к программам
Турбо Паскаля. В данной главе мы подробно расскажем вам о том,
что нужно знать, чтобы полностью использовать данные средства,
приведем множество примеров и дадим некоторую более глубокую ин-
формацию.
Большинство программ, которые вы захотите написать, можно
реализовать целиком на Турбо Паскале. В отличие от большинства
других компиляторов Паскаля, Турбо Паскаль позволяет вам с по-
мощью массивов Port[], Mem[], MemW[] и MemL[] непосредственно об-
ращаться ко всем ресурсам компьютера, а с помощью процедур
Intr() и MsDos() вы можете обращаться к базовой системе ввода-вы-
вода (BIOS) и операционной системе.
Для чего же тогда может потребоваться использовать совместно
с Турбо Паскалем Ассемблер? Для этого существуют две вероятные
причины: выполнение некоторого небольшого числа операций, которые
непосредственно в Турбо Паскале недоступны, и использование преи-
муществ высокой скорости работы, которые дает Ассемблер. (Сам
Турбо Паскаль работает достаточно быстро, потому что он написан
на языке Ассемблера.) В данной главе мы покажем вам, как можно
использовать в Турбо Паскале преимущества Ассемблера.