Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / Турбо Ассемблер / Использование Турбо Ассемблера /
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++



Компоновка ассемблерных модулей с С++


Важной концепцией С++ является безопасная с точки зрения стыковки типов компоновка. Компилятор и компоновщик должны работать согласованно, чтобы гарантировать правильность типов передаваемых между функциями аргументов. Процесс, называемый "корректировкой имен" (name-mangling), обеспечивает необходимую информацию о типах аргументов. "Корректировка имени" модифицирует имя функции таким образом, чтобы оно несло информацию о принимаемых функцией аргументах.


Когда программа пишется целиком на С++, корректировка имен происходит автоматически и прозрачно для программы. Однако, когда вы пишете ассемблерный модуль для последующей его компоновки с программой на С++, вы сами обязаны обеспечить корректировку имен в модуле. Это легко сделать, написав пустую функцию на С+ и скомпилировав ее с ассемблерным модулем. Генерируемый при этом Borland С++ файл .ASM будет содержать исправленные имена. Затем вы можете их использовать при написании реального ассемблерного модуля.


Например, следующий фрагмент кода определяет четыре различные версии функции с именем test:


void test()
{
}


void test( int )
{
}


void test( int, int )
{
}


void test( float, double )
{
}


Если этот код компилируется с параметром -S, то компилятор создает на выходе файл на языке Ассемблера (.ASM). Вот как он выглядит (несущественные детали убраны):


; void test()
@testSqv proc near
push bp
mov bp,sp
popo bp
ret
@testSqv endp


; void test( int )
@testSqi proc near
push bp
mov bp,sp
popo bp
ret
@testSqi endp


; void test( int, int )
@testSqii proc near
push bp
mov bp,sp
popo bp
ret
@testSqii endp


; void test( float, double )
@testSqfd proc near
push bp
mov bp,sp
popo bp
ret
@testSqfd endp




Использование Extern "C" для упрощения компоновки


При желании вы можете использовать в ассемблерных функциях неисправленные имена, не пытаясь выяснить, как должны выглядеть правленные. Использование нескорректированных имен защитит ваши ассемблерные функции от возможных изменений алгоритма в будущем. Borland С++ позволяет определять в программах С++ стандартные имена функций С++, как в следующем примере:


extern "C" {
int add(int *a, int b);
}


Любые функции, объявленные внутри фигурных скобок, получат имена в стиле языка Си. Ниже показаны соответствующие определения в ассемблерном модуле:


public _add
_add proc


Объявление ассемблерной функции в блоке extern "C" позволит вам избежать проблем со "откорректированными именами". При этом улучшится и читаемость кода.


Модели памяти и сегменты


Чтобы данная функция Ассемблера могла могла вызываться из С++, она должна использовать ту же модель памяти, что и программа на языке С++, а также совместимый с С++ сегмент кода. Аналогично, чтобы данные, определенные в модуле Ассемблера, были доступны в программе на языке С++ (или данные С++ были доступны в программе Ассемблера), в программе на Ассемблере должны соблюдаться соглашения языка С++ по наименованию сегмента данных.


Модели памяти и обработку сегментов на Ассемблере может оказаться реализовать довольно сложно. К счастью, Турбо Ассемблер сам выполняет почти всю работу по реализации моделей памяти и сегментов, совместимых с Borland C++, при использовании упрощенных директив определения сегментов.


Упрощенные директивы определения сегментов и Borland C++


Директива .MODEL указывает Турбо Ассемблеру, что сегменты, создаваемые с помощью упрощенных директив определения сегментов, должны быть совместимы с выбранной моделью памяти (TINY - крохотной, SMALL - малой, COMPACT - компактной, MEDIUM - средней, LARGEбольшой или HUGE - громадной) и управляет назначаемым по умолчанию типом (FAR или NEAR) процедур, создаваемых по директиве PROC. Модели памяти, определенные с помощью директивы .MODEL, совместимы с моделями Borland C++ с соответствующими именами.


Наконец, упрощенные директивы определения сегментов .DATA, .CODE, .DATA?, .FARDATA, .FARDATA? и .CONST генерируют сегменты, совместимые с Borland C++.


Например, рассмотрим следующий модуль Турбо Ассемблера с именем DOTOTAL.ASM:


.MODEL SMALL ; выбрать малую модель памяти (ближний код и данные)
.DATA ; инициализация сегмента данных, совместимого с Borland C++
EXTRN _Repetitions:WORD ; внешний идентификатор
PUBLIC _StartingValue ; доступен для других модулей
_StartValue DW 0
.DATA? ; инициализированный сегмент данных, совместимый с Borland C++
RunningTotal DW ?
.CODE ; сегмент кода, совместимый с Borland C++
PUBLIC _DoTotal
_DoTotal PROC ; функция (в малой модели памяти вызывается с помощью вызова ближнего типа)
mov cx,[_Repetitions] ; счетчик выполнения
mov ax,[_StartValue]
mov [RunningTotal],ax ; задать начальное
; значение
TotalLoop:
inc [RunningTotal] ; RunningTotal++
loop TotalLoop
mov ax,[RunningTotal] ; возвратить конечное значение (результат)
ret
_DoTotal ENDP
END


Написанная на Ассемблере процедура _DoTotal при использовании малой модели памяти может вызываться из Borland C++ с помощью оператора:


DoTotal();


Заметим, что в процедуре DoTotal предполагается, что где-то в другой части программы определена внешняя переменная Repetitions. Аналогично, переменная StartingValue объявлена, как общедоступная, поэтому она доступна в других частях программы. Следующий модуль Borland C++ (который называется SHOWTOT.CPP) обращается к данным в DOTOTAL.ASM и обеспечивает для модуля DOTOTAL.ASM внешние данные:


extern int StartingValue;
extern int DoTotal(word);
int Repetitions;
main()
{
int i;
Repetitions = 10;
StartingValue = 2;
print("%d\n", DoTotal());
}


Чтобы создать из модулей DOTOTAL.ASM и SHOWTOT.CPP выполняемую программу SHOWTOT.EXE, введите команду:


bcc showtot.cpp dototal.asm


Если бы вы захотели скомпоновать процедуру _DoTotal с программой на языке C++, использующей компактную модель памяти, то пришлось бы просто заменить директиву .MODEL на .MODEL COMPACT, а если бы вам потребовалось использовать в DOTATOL.ASM сегмент дальнего типа, то можно было бы использовать директиву .FARDATA.


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


<<<  НазадВперед  >>>
 1  2  3  4  5  6  7  8  9 


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

8  В тему

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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