На этом шаге мы рассмотрим использование утилиты H2ASH.
Наиболее трудоемкий процесс в написании внешних ассемблерных модулей - разработка интерфейса с внутренней структурой данных программы. Ассемблер не предназначен для выполнения операций над структурами, массивами, строками C, а также классами C++, однако вы можете воспользоваться несколькими "трюками" для доступа к объектов этих и других типов из операторов ассемблера.
Утилита H2ASH.EXE, поставляемая вместе с TASM, может помочь вам сократить время поиска ответа на вопрос: "Как мне получить доступ к программным данным с помощью ассемблерных инструкций и директив?" H2ASH преобразует объявления, содержащиеся в заголовочных файлах C и C++ в эквивалентные объявления TASM, хранимые в файлах с расширением .ash (заголовочный файл ассемблера). Вы можете воспользоваться этими объявлениями для доступа к вашим программным данным или же, руководствуясь ими, написать свои собственные директивы.
Утилита H2ASH поддерживает большинство конструкций C и классов C++. Она обрабатывает файлы #include и может пользоваться преимуществами идеального режима - расширенный MASM - подобный синтаксис TASM. К сожалению, H2ASH не распознает множественного наследования, виртуальных базовых классов и шаблонов. Она также выдает предупреждения для элементов, подобных макросам, которые не транслируются так просто в директивы TASM. Следует рассматривать H2ASH как рекомендацию, а не последнее слово в преобразовании объявлений C и C++ в ассемблерный код. Для 32-битного кода следует пользоваться утилитой H2ASH32.
Продемонстрируем работу утилиты H2ASH, обработав с ее помощью несколько образцов заголовочных файлов. Например, найдите заголовочный файл Db.h (листинг 1) Скопируйте этот файл и h2ash.exe в папку \BC45\BIN, и введите команду h2ash db.h для создания нового файла Db.ash с эквивалентными директивами TASM. Поскольку в Db.h включается заголовочный файл STDIO.H, утилита H2ASH преобразует содержащиеся в нем объявлении так же, как в Db.h. (Во время выполнения H2ASH может предупреждать вас время от времени о макросах и других элементах, которые нельзя преобразовать.)
Листинг 1. db.h (Создание заголовочного файла образца базы данных)
#include <stdio.h> #include <limits.h> #define FALSE 0 #define TRUE 1 #define NAMELEN 30 #define ADDRLEN 30 #define CSZLEN 30 #define PHONELEN 13 typedef struct record { union { long numrecs; long custnum; } info; char name[NAMELEN]; char addr[ADDRLEN]; char csz[CSZLEN]; char phone[PHONELEN]; double balance; } Record; #define MAXREC (LONG_MAX/sizeof(Record)) int CreateBD(const char *path); FILE *OpenBD(const char *path, Record *header); int ReadRecord(FILE *f, long recnum, Record *recp); int WriteRecord(FILE *f, long recnum, Record *recp); int AppendRecord(FILE *f, long recnum, Record *recp); void InputLong(const char *label, long *lp); void InputChar(const char *label, char*cp, int len); void InputDouble(const char *label, double *db);
Несмотря на несовершенство результатов, утилита H2ASH мастерски справляется с преобразованием большинства объявлений. Например, в Db.h определяются следующие константы:
#define FALSE 0 #define TRUE 1 #define NAMELEN 30 #define ADDRLEN 30 #define CSZLEN 30 #define PHONELEN 13
Утилита H2ASH переводит их в эквивалентные директивы TASM:
FALSE EQU 0 TRUE EQU 1 NAMELEN EQU 30 ADDRLEN EQU 30 CSZLEN EQU 30 PHONELEN EQU 13
Утилите H2ASH "по зубам" и более заковыристые объявления:
typedef struct record { union { long numrecs; long custnum; } info; char name[NAMELEN]; char addr[ADDRLEN]; char csz[CSZLEN]; char phone[PHONELEN]; double balance; } Record;
Эта структура легко преобразуется утилитой H2ASH, которая выдаст следующие эквивалентные директивы TASM:
tag$1UNION numrecs DD ? custnum DD ? tag$1ENDS record struct info tag$1 <> name DB 30 DUP ( ? ) addr DB 30 DUP ( ? ) csz DB 30 DUP ( ? ) phone DB 30 DUP ( ? ) balance DQ ? record ENDS
В дополнение к преобразованию существующих имен, таких, как numrecs и phone, утилита H2ASH создает все необходимые имена, подобные tag$1. Она также создает объявления, необходимые для вызова функций C или C++, для которых в программе есть прототипы:
GLOBAL C CreateDB :NEAR GLOBAL C OpenDB :NEAR GLOBAL C ReadRecord :NEAR GLOBAL C WriteRecord :NEAR
На следующем шаге мы рассмотрим написание внешних модулей TASM.