Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / Турбо Ассемблер / Использование Турбо Ассемблера /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Интерфейс Турбо Ассемблера и Borland C++ - Программирование от RIN.RU
Интерфейс Турбо Ассемблера и Borland C++



Выполнение вызова


Все, что требуется от вас для передачи параметров в функцию C++, это занесение в стек самого правого параметра первым, затем следующего по порядку параметра и так далее, пока в стеке не окажется самый левый параметр. После этого нужно просто вызвать функцию. Например, при программировании на Borland C++ для вызова библиотечной функции Borland C++ strcpy для копирования строки SourceString в строку DestString можно ввести:


strcpy(DestString, SourceString);


Для выполнения того же вызова на Ассемблере нужно использовать инструкции:


lea ax,SourceString ; правый параметр
push ax
lea ax,DestString ; левый параметр
push ax
call _strcpy ; скопировать строку
add sp,4 ; отбросить параметры


При настройке SP после вызова не забывайте очищать стек от параметров.


Можно упростить ваш код и сделать его независимым от языка, воспользовавшись расширением команды Турбо Ассемблера CALL:


call назначение [язык [,аргумент_1] .]


где "язык" - это C, PASCAL, BASIC, FORTRAN, PROLOG или NOLANGUAGE, а "аргумент_n" это любой допустимый аргумент программы, который может быть прямо помещен в стек процессора.


Используя данное средство, можно записать:


lea ax,SourceString
lea bx,DestString
call strcpy c,bx,ax


Турбо Ассемблер автоматически вставит команды помещения аргументов в стек в последовательности, принятой в С++ (сначала AX, затем BX), выполнит вызов _strcopy (перед именами С++ Турбо Ассемблер автоматически вставляет символ подчеркивания), и очищает стек после вызова.


Если вы вызываете функцию С++, которая использует соглашения Паскаля, заносите в стек параметры слева направо. После вызова настраивать указатель стека SP не требуется.


lea ax,DestString ; левый параметр
push ax
lea ax,SourceString ; правый параметр
push ax
call CTRCPY ; скопировать строку


Можно опять упростить ваш код, воспользовавшись расширением команды Турбо Ассемблера CALL:


lea bx,DestString ; самый левый параметр
lea ax,SourceString ; самый правый параметр
call strcpy pascal,bx,ax


Турбо Ассемблер автоматически вставит команды помещения аргументов в стек в последовательности, принятой в Паскале (сначала 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 <stdio.h>
extern float Average(int far * ValuePtr, int
NumberOfValues);
#define NUMBER_OF_TEST_VALUES 10
int TestValues(NUMBER_OF_TEST_VALUES) = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};


main()
{
printf("Среднее арифметическое равно: %f\n",
Average(TestValues, NUMBER_OF_TEST_VALUES));
}
float IntDivide(int Divedent, int Divisor)
}
return( (float) Divident / (float) Divisor );


}



а часть программы на Ассемблере (AVERAGE.ASM) имеет вид:


; Вызываемая из С++ функция с малой моделью памяти,
; которая возвращает среднее арифметическое последова-
; тельности целых чисел. Для выполнения завершающего
; деления вызывает функцию С++ IntDivide().
;
; Прототип функции:
; extern float Average(int far * ValuePtr,
; int NumberOfValues);
;
; Ввод:
; int far * ValuePtr: ; массив значений для вычисления среднего
; int NumberOfValues: ; число значений для вычисления среднего
.MODEL SMALL
EXTRN _IntDivide:PROC
.CODE
PUBLIC _Average
_Average PROC
push bp
mov bp,sp
les bx,[bp+4] ; ES:BX указывает на массив значений
mov cx,[bp+8] ; число значений, для которых нужно вычислить среднее
mov ax,0
AverageLoop:
add ax,es:[bx] ; прибавить текущее значение
add ax,2 ; ссылка на следующее значение
loop AverageLoop
push WORD PTR [bp+8] ; получить снова число значений, переданных
; в функцию IntDivide в правом параметре
push ax ; передать сумму в левом параметре
call _IntDivide ; вычислить среднее значение с плавающей точкой
add sp,4 ; отбросить параметры
pop bp
ret ; среднее значение в регистре вершины стека сопроцессора 8087


_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


<<<  Назад
 1  2  3  4  5  6  7  8  9 


 8  Комментарии к статье  8 8  Обсудить в чате

8  В тему

Начало работы на Турбо Ассемблере

Использование директив и параметров

Общие принципы программирования

Объектно-ориентированное программирование

Использование выражений и значений идентификаторов

Директивы выбора процессора

Использование моделей памяти программы и сегментации

Определение типов данных

Задание и использование счетчика адреса

Описание процедур

Управление областью действия идентификаторов

Определение данных

Расширенные инструкции

Использование макрокоманд

Использование условных директив

Интерфейс с компоновщиком

Генерация листинга

Интерфейс Турбо Ассемблера с Турбо Паскалем

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь