Turbo Assembler 3.0. Руководство пользователя

         

MODEL можно за- давать USE32


(32-битовые флаги без директивы .386 не допускаются)

Это средство расширено. Теперь в операторе . MODEL можно за- давать USE32 и LARGESTACK. Ранее это было сообщение "USE32 not allowed without .386").


Адресные подтипы данных


Подтипы идентификаторов описывают идентификатор, представля- ющий адрес байта, слова и т.д. Простые адресные подтипы, которые предусмотрены в Турбо Ассемблере, приведены в Таблице 5.5.

Адресные подтипы Таблица 5.5 --------------------T-------------------------------------------¬ ¦ Выражение типа ¦ Значение ¦ +-------------------+-------------------------------------------+ ¦ UNKNOWN ¦ Неизвестный или неопределенный адресный ¦ ¦ ¦ подтип. ¦ ¦ ¦ ¦ ¦ BYTE ¦ Адрес, описывающий байт. ¦ ¦ ¦ ¦ ¦ WORD ¦ Адрес, описывающий слово. ¦ ¦ ¦ ¦ ¦ DWORD ¦ Адрес, описывающий 4-байтовую величину. ¦ ¦ ¦ ¦ ¦ PWORD или FWORD ¦ Адрес, описывающий 6-байтовую величину. ¦ ¦ ¦ ¦ ¦ QWORD ¦ Адрес, описывающий 8-байтовую величину. ¦ ¦ ¦ ¦ ¦ TBYTE ¦ Адрес, описывающий 10-байтовую величину. ¦ ¦ ¦ ¦ ¦ SHORT ¦ Адрес, описывающий короткий адрес метки/ ¦ ¦ ¦ процедуры. ¦ ¦ ¦ ¦ ¦ NEAR ¦ Адрес, описывающий ближний адрес метки/ ¦ ¦ ¦ процедуры. ¦ ¦ ¦ ¦ ¦ FAR ¦ Адрес, описывающий дальний адрес метки/ ¦ ¦ ¦ процедуры. ¦ ¦ ¦ ¦ ¦ PROC ¦ Адрес, описывающий ближний или дальний ¦ ¦ ¦ адрес метки/процедуры, в зависимости от ¦ ¦ ¦ текущей модели. ¦ ¦ ¦ ¦ ¦ DATAPTR ¦ Адрес, описывающий слово, двойное слово ¦ ¦ ¦ или величину pword, в зависимости от те- ¦ ¦ ¦ кущей выбранной модели. ¦ ¦ ¦ ¦ ¦ CODEPTR ¦ Адрес, описывающий слово, двойное слово ¦ ¦ ¦ или величину pword, в зависимости от те- ¦ ¦ ¦ кущей выбранной модели. ¦ ¦ ¦ ¦ ¦ имя структуры/ ¦ Адрес, описывающий экземпляр названной ¦ ¦ объединения ¦ структуры или объединения. ¦ ¦ ¦ ¦ ¦ имя таблицы ¦ Адрес, описывающий экземпляр указанной ¦ ¦ ¦ таблицы. ¦ ¦ ¦ ¦ ¦ имя записи ¦ Адрес, описывающий экземпляр указанной ¦ ¦ ¦ записи (байт, слово или двойное слово). ¦ ¦ ¦ ¦ ¦ имя перечисления ¦ Адрес, описывающий экземпляр перечислимо- ¦ ¦ ¦ го типа данных. ¦ ¦ ¦ ¦ ¦ имя типа ¦ Адрес, описывающий экземпляр указанного ¦ ¦ ¦ типа. ¦ ¦ ¦ ¦ ¦ TYPE выражение ¦ Адрес, описывающий элемент, подтип кото- ¦ ¦ ¦ рого является адресом подтипа выражения ¦ ¦ ¦ (только для режима Ideal). ¦ L-------------------+--------------------------------------------



Argument needs type override


(Требуется явно указать тип операнда)

Требуется явно указать размер, или тип, выражения, т.к. он не может быть определен из контекста. Например, ошибочной являет- ся следующая команда:

mov [bx],1

Ошибки такого рода обычно корректируются с помощью операции PTR, позволяющей установить размер операнда:

mov WORD PTR[bx],1



Argument to operation or instruction has illegal size


(Операнд операции или команды имеет недопустимый размер)

В операции указан операнд, имеющий тип, недопустимый для данной операции. Например:



Q LABEL QWORD QNOT = NOT Q ; операнд операции отрицания не может ; иметь тип QWORD



Arithmetic overflow


(Арифметическое переполнение)

Потеря значащих цифр при вычислении значения выражения. Нап- ример:

X = 20000h * 20000h ; результат занимает более 32 бит

Точность всех арифметических операций - 32 бита.



Ассемблирование вашей первой программы


После того, как вы сохранили файл HELLO.ASM, вы захотите за- пустить программу. Однако, перед тем, как вы сможете ее запус- тить, потребуется преобразовать программу в выполняемый вид. Как показано на Рис. 1.1, где изображен полный цикл создания програм- мы (редактирование, ассемблирование, компоновка и выполнение), это потребует двух дополнительных шагов - ассемблирования и ком- поновки.

На этапе ассемблирования ваш исходный код (текст программы) превращается в промежуточную форму, которая называется объектным модулем, а на этапе компоновки один или несколько модулей комби- нируются в выполняемую программу. Ассемблирование и компоновку вы можете выполнять с помощью командной строки.

Для ассемблирования файла HELLO.ASM наберите:

TASM hello

Создание новой программы ¦ --------------------------------¦ ¦ ¦ ¦ Редактирование ¦ ¦ ¦ ¦ -----------------------------------------------¬ ¦ ¦ Исходный файл Ассемблера HELLO.ASM ¦ ¦ L---------------------T------------------------- ¦ ¦ ¦ Ассемблирование ¦ ¦ ¦ ¦ ----------------------------------------------¬ ¦ ¦ Объектный файл HELLO.OBJ ¦ ¦ L---------------------T------------------------ ¦ ¦ ¦ Компоновка ¦ ¦ ¦ ¦ ----------------------------------------------¬ ¦ ¦ Выполняемый файл HELLO.EXE ¦ ¦ L---------------------T------------------------ ¦ ¦ ¦ Выполнение ¦ -----------------------¬ ¦ L---+ Если нужны изменения ¦----- L-----------------------

Рис. 1.1 Редактирование, ассемблирование, компоновка и вы- полнение.

и нажмите клавишу Enter. Если вы не задали другое имя, файл HELLO.ASM будет ассемблирован в файл HELLO.OBJ. (Заметим, что расширение имени файла вводить не требуется. Турбо Ассемблер под- разумевает в этом случае, что файл имеет расширение .ASM.) На эк- ране вы увидите следующее:

Turbo Assembler Version 3.0 Copyright (C) 1988,1991 (1) by Borland International Inc. Assembling file: HELLO.ASM (2) Error messages: None (3) Warning messages: None (4) Passes: 1 (5) Remaining memory: 266K (6)

1 - Турбо Ассемблер, версия 3.0; авторские права фирмы Borland, 1991 г.; 2 - ассемблирован файл HELLO.ASM; 3 - сообщения об ошибках: нет; 4 - предупреждающие сообщения: нет; 5 - число проходов: 1; 6 - остается памяти: 266К

Если вы введете файл HELLO.ASM в точности так, как показано, то вы не получите никаких предупреждающих сообщений или сообщений об ошибках. Если вы получаете такие сообщения, они появляются на экране наряду с номерами строк, указывающими строки, где содер- жатся ошибки. При получении сообщений об ошибках проверьте исход- ный код (текст) программы и убедитесь, что он выглядит точно так, как исходный код в нашем примере, а затем снова ассемблируйте программу.



ASSUME must be segment register


(В директиве ASSUME должен быть указан сегментный регистр)

В директиве ASSUME можно указывать только сегментные регист- ры, во всех остальных случаях выводится данное сообщение об ошиб- ке. Например, ошибочной является директива:

ASSUME ax:CODE



Атрибут доступа к сегменту


В защищенном режиме для любого сегмента вы можете управлять доступом к определенным операциям с памятью, запрещая их. (Заме- тим, что данное средство поддерживается в настоящее время только компоновщиком Phar Lap. Если требуется использовать атрибут дос- тупа к сегменту, вы должны компилировать совместимый с ним объек- тный код с помощью параметра командной строки /op.) Атрибут дос- тупа к сегменту сообщает компоновщику, что к сегменту нужно применить специальные ограничения доступа.

Допустимые значения данного атрибута приведены в следующей таблице:

Значения атрибута доступа к сегменту Таблица 7.9 ----------------T-----------------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +---------------+-----------------------------------------------+ ¦ EXECONLY ¦ Сегмент доступен только для выполнения. ¦ ¦ ¦ ¦ ¦ EXECREAD ¦ Сегмент доступен только для чтения и выполне- ¦ ¦ ¦ ния. ¦ ¦ ¦ ¦ ¦ READONLY ¦ Сегмент доступен только для чтения. ¦ ¦ ¦ ¦ ¦ READWRITE ¦ Сегмент доступен только для чтения и записи. ¦ L---------------+------------------------------------------------

Если вы выбираете один из этих атрибутов или используете USE32, компоновщик Phar Lap предполагает, что сегмент предназна- чен для выполнения в защищенном режиме. Если вы выбираете USE32, но не задаете одно из этих значений, Турбо Ассемблер предполагает использование атрибута READONLY.



Атрибут класса сегмента


Атрибут класса сегмента - это заключенная в кавычки строка, которая помогает компоновщику определить соответствующий порядок сегментов при собирании их в программу из модулей. Компоновщик объединяет вместе в памяти все сегменты с одним и тем же именем класса. Типичным примером использования имени класса является объединение в группу всех сегментов кода программы (обычно для этого используется класс CODE). С помощью механизма класса груп- пируются также данные и неинициализированные данные.



Атрибут комбинирования сегментов


Атрибут комбинирования сегментов сообщает компоновщику, как нужно комбинировать сегменты различных модулей, имеющих одно и то же имя. Допустимые значения атрибута комбинирования сегмента пе- речисляются в следующем списке. Заметим, что если вы не указывае- те этот атрибут, Турбо Ассемблер предполагает PRIVATE.

Атрибут комбинирования сегмента Таблица 7.6 --------------------T-------------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +-------------------+-------------------------------------------+ ¦ PRIVATE ¦ Сегмент не будет комбинироваться с други- ¦ ¦ ¦ ми сегментами с тем же именем вне данного ¦ ¦ ¦ модуля. Будет выполняться конкатенация ¦ ¦ ¦ сегмента с сегментами с тем же именем вне ¦ ¦ ¦ данного модуля для образования одного ¦ ¦ ¦ непрерывного сегмента. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ MEMORY ¦ То же, что PUBLIC. Будет выполняться кон- ¦ ¦ ¦ катенация сегмента с другими сегментами ¦ ¦ ¦ с тем же именем вне данного модуля для ¦ ¦ ¦ образования одного непрерывного сегмента, ¦ ¦ ¦ используемого как сегмент стека. Компо- ¦ ¦ ¦ новщик инициализирует регистры SS SP на- ¦ ¦ ¦ чальными значениями, так что они указы- ¦ ¦ ¦ вают на конец данного сегмента. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ COMMON ¦ Располагает данный сегмент и все другие ¦ ¦ ¦ сегменты с тем же именем по одному адре- ¦ ¦ ¦ су. Все сегменты с данным именем будут ¦ ¦ ¦ перекрываться и совместно использовать ¦ ¦ ¦ общую память. Размер полученного в ре- ¦ ¦ ¦ зультате сегмента будет равен размеру са- ¦ ¦ ¦ мого большого сегмента модуля. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ VIRTUAL ¦ Определяет специальный вид сегмента, ко- ¦ ¦ ¦ торый должен описываться внутри охватыва- ¦ ¦ ¦ ющего сегмента. Компоновщик интерпретиру- ¦ ¦ ¦ ет его как общую область и присоединяет ¦ ¦ ¦ его к охватывающему сегменту. Виртуальный ¦ ¦ ¦ сегмент наследует свои атрибуты из охва- ¦ ¦ ¦ тывающего сегмента. Директива ASSUME ¦ ¦ ¦ рассматривает виртуальный сегмент как ¦ ¦ ¦ часть порождающего сегмента. Во всех дру- ¦ ¦ ¦ гих отношениях виртуальный сегмент предс- ¦ ¦ ¦ тавляет собой общую область памяти, кото- ¦ ¦ ¦ рая используется разными сегментами. Это ¦ ¦ ¦ позволяет организовать совместное исполь- ¦ ¦ ¦ зование статических данных, которые бе- ¦ ¦ ¦ рутся различными модулями из включаемых ¦ ¦ ¦ файлов. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ AT xxx ¦ Располагает сегмент по абсолютному адресу ¦ ¦ ¦ параграфа. Адрес задается параметром xxx. ¦ ¦ ¦ Компоновщик для сегмента AT не порождает ¦ ¦ ¦ никаких данных или кода. Используйте ди- ¦ ¦ ¦ рективу AT для организации доступа по ¦ ¦ ¦ идентификатору к фиксированным адресам ¦ ¦ ¦ памяти (например, экран дисплея или об- ¦ ¦ ¦ ласти ПЗУ). ¦ L-------------------+--------------------------------------------



Атрибут размера сегмента


Если текущим выбранным процессором является процессор 80386, то сегменты могут быть 16- или 32-разрядными. Размер атри- бута сегмента сообщает компоновщику, какой размер вы хотите за- дать для конкретного сегмента. Допустимые значения атрибута при- ведены в следующей таблице:

Значения атрибута размера сегмента Таблица 7.8 ----------------T-----------------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +---------------+-----------------------------------------------+ ¦ USE16 ¦ Сегмент будет 16-разрядным. Такой сегмент мо- ¦ ¦ ¦ жет содержать до 64К кода или данных. ¦ ¦ ¦ ¦ ¦ USE32 ¦ Сегмент будет 32-разрядным. Такой сегмент мо- ¦ ¦ ¦ жет содержать до 4 гигабайт кода или данных. ¦ L---------------+------------------------------------------------

Если в режиме MASM вы выбираете процессор 80386, то Турбо Ассемблер предполагает использование USE32. В режиме Ideal Турбо Ассемблер по умолчанию предполагает использование USE32.



Атрибут выравнивания сегмента


Атрибут выравнивания сегмента сообщает компоновщику, что нужно обеспечить размещение начала сегмента на заданной границе. Это важно, поскольку при правильном выравнивании доступ к данным в процессорах 80х86 выполняется быстрее. Допустимые значения это- го атрибута приведены в следующей таблице:

Атрибут выравнивания сегмента Таблица 7.7 -----------------------T----------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +----------------------+----------------------------------------+ ¦ BYTE ¦ Выравнивание не выполняется. Сегмент ¦ ¦ ¦ начинается с границы следующего байта. ¦ ¦ ¦ ¦ ¦ WORD ¦ Начинает сегмент на границе следующего ¦ ¦ ¦ слова. ¦ ¦ ¦ ¦ ¦ DWORD ¦ Начинает сегмент на границе следующего ¦ ¦ ¦ двойного слова. ¦ ¦ ¦ ¦ ¦ PARA ¦ Начинает сегмент на границе следующего ¦ ¦ ¦ параграфа (выравнивание на 16 байт). ¦ ¦ ¦ ¦ ¦ PAGE ¦ Начинает сегмент на границе следующей ¦ ¦ ¦ страницы (выравнивание на 256 байт). ¦ ¦ ¦ ¦ ¦ MEMPAGE ¦ Начинает сегмент на границе следующей ¦ ¦ ¦ страницы памяти (выравнивание на 4 ки- ¦ ¦ ¦ лобайта). ¦ L----------------------+-----------------------------------------

Если вы не задаете тип выравнивания, Турбо Ассемблер подра- зумевает PARA.



Bad keyword in SEGMENT statement


(Неверное ключевое слово в операторе SEGMENT)

Один из параметров директивы SEGMENT: тип выравнивания, тип объединения или тип сегмента имеет недопустимое значение. Напри- мер:

DATA SEGMENT PAFA PUBLIC ; вместо PARA указано PAFA



Bad switch


(Неверный параметр-переключатель командной строки)

В командной строке указан неверный параметр. См. Главу 2, где дается подробное описание параметров командной строки.



Безусловные директивы генерации сообщений об ошибке


Безусловными директивами генерации сообщений об ошибке явля- ются директивы ERR и .ERR. Эти директивы всегда генерируют ошибку и не требуют аргументов, хотя могут содержать необязательное со- общение. Директиву .ERR можно использовать только в режиме MASM.



Can't add relative quantities


(Нельзя складывать относительные адреса)

Выражение содержит операцию сложения двух адресов, что явля- ется бессмысленной операцией. Например:

ABC DB ? DEF = ABC + ABC ; ошибка: нельзя складывать ; два относительные адреса

Можно вычитать относительные адреса. Можно добавить констан- ту к относительному адресу, например:

XYZ DB 5 DUP(0) XYZEND EQU $ XYZLEN = SYZEND - XYZ ; совершенно верно XYZ2 = XYZ + 2 ; тоже верно



Can't address with currently ASSUMEd segment registers


(Невозможна адресация из текущих, установленных директивой ASSUME, сегментных регистров)

В выражении содержится ссылка на переменную, для доступа к которой не специфицирован сегментный регистр. Например:

DSEG SEGMENT ASSUME ds:DSEG mov si,MPTR ; не определен сегментный регистр, который ; обеспечил бы доступ к сегменту XSEG DSEG ENDS XSEG SEGMENT MPTR DW ? XSEG ENDS



Can't convert to pointer


(Невозможно преобразование в указатель)

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

mov cl,[BYTE PTR al] ; AL нельзя преобразовать ; в указатель



Can't emulate 8087 instruction


(Невозможна эмуляция команд сопроцессора 8087)

В Турбо Ассемблере параметром командной строки /E либо с по- мощью директивы EMUL установлен режим генерации эмулированных ко- манд арифметики с плавающей точкой, однако текущая команда не мо- жет быть эмулирована. Например:

EMUL FNSAVE [WPTR] ; эта команда не может быть эмулирована

Некоторые команды не поддерживаются эмуляторами арифметики с плавающей точкой. Это команды FNSAVE, FNSTCW, FNSTENV и FNSTSW.



Can't find @file __


(Не найден файл подсказок __)

В командной строке указано имя несуществующего файла подска- зок. Следует проверить, указано ли полное имя файла. В Турбо Ас- семблере отсутствует умолчание для расширения имени файла подска- зок. Вероятной причиной данного сообщения может быть отсутствие места на диске при записи на этот диск файла, содержащего перек- рестные ссылки.



Can't make variable public


(Переменная не может быть объявлена как PUBLIC)

Переменная была уже ранее объявлена таким образом, что уже не может быть определена как общая (PUBLIC). Например:

EXTRN ABC:NEAR PUBLIC ABC ; ошибка: ABC уже ранее объявлена ; с атрибутом EXTRN



Can't override ES segment


(Нельзя переопределить сегмент ES)

В текущем операторе указан регистр, использование которого в данной команде недопустимо. Например:

STOS DS:BYTE PTR[di]

В команде STOS для определения целевого адреса допускается использовать только регистр ES.



Can't subtract dissimilar relative quantities


(Недопустимое вычитание относительных адресов)

Выражение содержит операцию вычитания двух адресов, которая для данных адресов является недопустимой. Данное сообщение выда- ется, например, в том случае, если адреса находятся в разных сег- ментах. Например:

SEG1 SEGMENT A: SEG1 ENDS SEG2 SEGMENT B: mov ax,B-A ; недопустимо, поскольку A и В находятся ; в разных сегментах SEG2 ENDS



Can't use macro name in expression


(Недопустимо использование имени макрокоманды в качестве операнда выражения)

Имя макрокоманды указано в качестве операнда выражения. Нап- ример:

MyMac MACRO ENDM mov ax,MyMac ; ошибка!



Can't use this outside macro


(Использование данного оператора недопустимо вне макроопре- деления)

Вне макроопределения указана директива, которую допускается использовать только внутри макроопределений. К таким директивам относятся, например, ENDM и EXITM. Например:

DATA SEGMENT ENDM ; ошибка: вне макроопределения недопустимо



Числовые константы


Числовые константы в Турбо Ассемблере всегда начинаются с цифры (0-9) и содержат произвольное число алфавитно-цифровых символов. Фактическое значение константы зависит от основания, которое вы выбираете для ее интерпретации. В Турбо Ассемблере можно использовать двоичное, восьмеричное, десятичное или шест- надцатиричное основание, что показано в приведенной ниже таблице:

Основания Таблица 5.1 ------------------------T---------------------------------------¬ ¦ Основание ¦ Допустимые цифры ¦ +-----------------------+---------------------------------------+ ¦двоичное ¦ 0 1 ¦ ¦восьмеричное ¦ 0 1 2 3 4 5 6 7 ¦ ¦десятичное ¦ 0 1 2 3 4 5 6 7 8 9 ¦ ¦шестнадцатиричное ¦ 0 1 2 3 4 5 6 7 8 9 A B C D E F ¦ L-----------------------+----------------------------------------

Заметим, что в шестнадцатиричных константах вы можете ис- пользовать буквы как в верхнем, так и в нижнем регистре.

Турбо Ассемблер определяет основание числовой константы, проверяя сначала последний ее символ. Символы, используемые для задания основания при интерпретации константы, приведены в следу- ющей таблице:

Символы, определяющие основания Таблица 5.2 ---------------------T------------------------------------------¬ ¦ Символ ¦ Основание ¦ +--------------------+------------------------------------------+ ¦ B ¦ двоичное ¦ ¦ O ¦ восьмеричное ¦ ¦ Q ¦ восьмеричное ¦ ¦ D ¦ десятичное ¦ ¦ H ¦ шестнадцатиричное ¦ L--------------------+-------------------------------------------

Для задания основания числа можно использовать символы как верхнего, так и нижнего регистра. Последним символом числовой константы должно быть одно из этих значений. Если последним сим- волом числовой константы не является один из этих символов, Тур- бо Ассемблер будет для интерпретации константы использовать теку- щее назначенное по умолчанию основание. Доступные числовые конс- танты и их значения приведены в следующей таблице:

Числовые константы Таблица 5.3 -----------------------T----------------------------------------¬ ¦Числовая константа ¦ Значение ¦ +----------------------+----------------------------------------+ ¦ 77d ¦ 77 десятичное ¦ ¦ 77h ¦ 77 шестнадцатиричное ¦ ¦ ffffh ¦ недопустимо, не начинается с цифры ¦ ¦ 0ffffh ¦ FFFF шестнадцатиричное ¦ ¦ 88 ¦ интерпретация зависит от текущего ис- ¦ ¦ ¦ пользуемого по умолчанию основания ¦ L----------------------+-----------------------------------------



Что происходит?


Теперь, когда вы получили и выполнили программу HELLO.ASM, давайте вернемся назад и рассмотрим подробно, что происходит с момента ввода текста программы до ее выполнения.

Когда вы ассемблируете файл HELLO.ASM, Турбо Ассемблер прев- ращает текст инструкций в этом файле в их двоичный эквивалент в объектном файле HELLO.OBJ. Этот файл является промежуточным фай- лом (промежуточным звеном в процессе перехода от текстового к вы- полняемому файлу). Файл HELLO.OBJ содержит всю информацию, необ- ходимую для создания выполняемого кода из инструкций, содержащих- ся в файле HELLO.ASM, но она записана в виде, который позволяет комбинировать ее с другими объектными файлами для создания одной программы.

При компоновке файла HELLO.OBJ TLINK преобразует его в вы- полняемый файл HELLO.EXE, который вы запускаете, введя hello в ответ на подсказку DOS.

Теперь введите:

dir hello.*

При этом будет выведен список файлов HELLO на диске. Это будут файлы HELLO.ASM, HELLO.OBJ, HELLO.EXE и HELLO.MAP.



Что такое объект?


Объект состоит из структуры данных и связанных с ней проце- дур (которые называются методами), которые работают с данными, записанными в экземплярах структуры данных.

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

Примечание: Для объектно-ориентированного программиро- вания мы настоятельно рекомендуем вам использовать режим Ideal Турбо Ассемблера, поскольку область действия иденти- фикаторов в MASM является глобальной, и вы не сможете раз- личить различные расположения показанных методов.

Объект, не имеющий наследования, называется базовым объек- том. Объект, наследующий характеристики других объектов, называ- ется порожденным или производным объектом.

В Турбо Ассемблере определено несколько идентификаторов, ко- торые вы можете использовать при описании объектов. Они перечис- лены в следующей таблице:

Идентификаторы, определенные для объектов Таблица 4.2 -----------------------------T----------------------------------¬ ¦ Идентификатор ¦ Значение ¦ +----------------------------+----------------------------------¦ ¦ @Object ¦ Текстовая макрокоманда, содержа- ¦ ¦ ¦ щая имя текущего объекта (пос- ¦ ¦ ¦ леднего описанного объекта). ¦ ¦ ¦ ¦ ¦ <имя_объекта> ¦ Тип данных STRUC, описывающий ¦ ¦ ¦ структуру данных объекта. ¦ ¦ ¦ ¦ ¦ @Table_<имя_объекта> ¦ Тип данных TABLE, содержащий ¦ ¦ ¦ таблицу методов объекта. Это не ¦ ¦ ¦ то же самое, что экземпляр таб- ¦ ¦ ¦ лицы виртуальных методов. ¦ ¦ ¦ ¦ ¦ @TableAddr_<имя_объекта> ¦ Метка, описывающая адрес экземп- ¦ ¦ ¦ ляра таблицы виртуальных мето- ¦ ¦ ¦ дов объекта (если она есть). ¦ L----------------------------+-----------------------------------



Code or data emission to undeclared segment


(Не объявлен сегмент для кода или данных)

Оператор, генерирующий код или данные, не принадлежит ни од- ному из сегментов, объявленных директивами SEGMENT. Например:

; Первая строка файла inc bx ; ошибка: не определен сегмент END

Генерировать данные или код можно только внутри какого-либо сегмента.



Constant assumed to mean Immediate const


(Константа интерпретируется как непосредственная)

Это предупреждающе сообщение выдается для выражений типа [0]. В режиме MASM это выражение интерпретируется как непосредс- твенная константа, равная 0. Например:

mov ax,[0]; означает mov ax,0, а не mov ax,ds:[0]



Constant too large


(Слишком большая константа)

Константа имеет, вообще говоря, правильный формат, однако ее значение превышает допустимую для данного режима величину. Напри- мер, числа, большие 0ffffh, можно использовать, если только ди- рективой .386/.386P или .486/.486Р разрешены команды процессора 386 или i486.



CS not correctly assumed


(Некорректное значение в регистре CS)

Адрес назначения в командах ближнего вызова и ближнего пере- хода не может находиться в другом сегменте. Например:

SEG1 SEGMENT LAB1 LABEL NEAR SEG1 ENDS SEG2 SEGMENT JMP LAB1 ; ошибка: неверный сегментный адрес SEG2 ENDS

Такие ошибки возникают только в режиме MASM. В режиме Ideal такие переходы и вызовы интерпретируются корректно.



CS override in protected mode


(Переопределение регистра CS в защищенном режиме)

В защищенном режиме ассемблирования команд процессора 286, 386 или i486, установленном директивой Р286Р, P386P или Р486Р, в текущей команде требуется переопределение регистра CS. Например:

P286 .CODE CVAL DW ? mov CVAL,1 ; генерирует переопределение регистра CS

Это предупреждающее сообщение выдается, если в командной строке указан параметр /Р. В защищенном режиме команды, в которых переопределяется регистр CS, не будут выполняться без специальных подготовительных операций.



CS unreachable from current segment


(CS недостижим из текущего сегмента)

При определении метки кода с помощью двоеточия (:) или с по- мощью директив LABEL или PROC сегментный регистр не указывает на текущий кодовый сегмент или группу, содержащую текущий кодовый сегмент. Например:

PROG1 SEGMENT ASSUME CS:PROG2 START: ; ошибка: неверно установлен регистр CS

Такие ошибки возникают только в режиме MASM. В режиме Ideal такие переходы и вызовы обрабатываются корректно.



Declaration needs name


(В директиве объявления не указано имя)

Не указано имя идентификатора в директиве, для которой спе- цификация имени является обязательной. Например:

PROC ; ошибка: в директиве PROC указание имени обязательно ret ENDP

В директивах объявления, таких как SEGMENT, PROC или STRUC, обязательно должно быть указано имя идентификатора. В режиме MASM имя указывается перед именем директивы, а в режиме Ideal - после имени директивы.



Directive ignored in Turbo Pascal model


(В режиме TPASCAL директива игнорируется)

В модуле Ассемблера, предназначенном для интерфейса с Турбо Паскалем, используется недопустимая директива. Режим интерфейса с Турбо Паскалем специфицируется директивой .MODEL. Более подробно интерфейс с Турбо Паскалем обсуждается в Главе 19.



Directive not allowed inside structure definition


(Недопустимая директива внутри определения структуры)

Внутри блока определения структуры указана недопустимая ди- ректива. Например:

X STRUC MEM1 DB ? ORG $+4 ; ошибка: директиву ORG нельзя указывать ; внутри структуры MEM2 DW ? ENDS

При определении вложенных структур нельзя определять новые структуры на внутренних уровнях. Например:

F00 STRUC F002 STRUC ; ошибка: определена новая структура ENDS ENDS

Для того чтобы использовать одну структуру внутри другой структуры, нужно сначала определить первую структуру, а после этого во второй структуре можно указывать имя первой.



Директива ::


Директива :: позволяет вам определить с областью действия, выходящей за рамки процедуры, в которой она находится. Это отли- чается от директивы : тем, что метки, определенные с помощью : имеют область действия только в текущей процедуре. Заметим, что :: отличается от : только когда вы задаете язык в операторе .MODEL. Приведем пример (файл DBLCOLON.ASM):

VERSION M510 .MODEL SMALL,C .CODE

A PROC NOP ASINGLE:NOP ADOUBLE::NOP NOP A ENDP

B PROC NOP JMP ASINGLE ; приведет к ошибке JMP ADOUBLE RET B ENDP END

Назад | Содержание | Вперед



Директива ALIGN


Для выравнивания счетчика адреса на адрес, значение которо- го равно степени 2, можно использовать директиву ALIGN. Директива ALIGN имеет следующий синтаксис:

ALIGN граница

где "граница" должна быть степенью 2.

Если счетчик адреса еще не соответствует смещению, которое представляет собой произведение "границы", Турбо Ассемблер, чтобы присвоить счетчика адреса нужный адрес, вставляет в сегмент инс- трукции NOP (нет операции).

Вы не можете выполнить надежное выравнивание на границу, яв- ляющееся более строгим, чем выравнивание сегмента, в котором встречается директива ALIGN. Выравнивание сегмента задается, ког- да сегмент в первый раз начинается по директива SEGMENT.

Например, если вы определили сегмент следующим образом:

CODE SEGMENT PARA PUBLIC

затем вы можете задать ALIGN 16 (что эквивалентно PARA), но не ALIGN 32, как как это более строгое выравнивание, чем выравнива- ние, заданное в директиве SEGMENT с помощью PARA. Если выравнива- ние сегменте недостаточно строгое, то директива ALIGN генерирует предупреждающее сообщение.

Использование директивы ALIGN показано в следующем примере:

ALIGN 4 ; выравнивание на границу DWORD для 386 BignNum DD 12345678



Директива .ALPHA


Директива .ALPHA определяет упорядочивание сегментов по ал- фавиту. Данная директива сообщает Турбо Ассемблеру, что сегменты в объектном файле нужно разместить в алфавитном порядке (в соот- ветствии с именами сегментов). Она имеет синтаксис:

.ALPHA



Директива ARG


Хотя можно обращаться к параметрам через регистр BP, Турбо Ассемблер предусматривает альтернативу вычислению смещений в сте- ке и выполнению текстовых присваиваний. Это директива ARG. При использовании ее в процедуре директива ARG автоматически опреде- ляет смещения параметров относительно регистра BP. Она вычисляет также размер блока параметров и использует его в инструкции RET. Поскольку идентификаторы, создаваемые по директиве ARG, определе- ны только в соответствующей процедуре, в каждой процедуре или функции вам не требуется использовать уникальные имена парамет- ров.

Покажем, как будет выглядеть пример предыдущего раздела, если переписать его, используя директиву ARG:

CODE SEGMENT ASSUME CS:CODE MyProc PROC FAR ; procedure MyProc(i,j : integer); ; external; PUBLIC MyProc ARG j : WORD, i : WORD = RetBytes push bp ; нужно сохранить BP вызывающей ; программы mov bp,sp ; BP теперь указывает на вершину ; стека mov ax,i ; адресуемся к i через BP . . .

Директива ARG Турбо Ассемблера создает локальные идентифика- торы для параметров i и j. На время выполнения процедуры строка:

ARG j : WORD, i : WORD = RetBytes

автоматически приравнивает идентификатор i к [WORD PTR BP+6], идентификатор j к [WORD PTR BP+8], а идентификатор RetBytes - к числу 4 (размеру в байтах блока параметров). В значениях учитыва- ется и занесенное в стек значение BP, и размер адреса возврата: если бы процедура MyProc имела ближний тип, то i было бы прирав- нено к значению [BP+4], j - к [BP+6], а RetBytes также было бы равно 4 (в любом случае процедура MyProc может завершить выполне- ние с помощью инструкции RET RetBytes).

При использовании директивы ARG нужно помнить, что параметры должны перечисляться в обратном порядке. Последний параметр про- цедуры или функции Турбо Паскаля нужно размещать в директиве ARG первым и наоборот.

Относительно использования директивы ARG с Турбо Паскалем можно сделать еще одно замечание. В отличие от других языков, Турбо Паскаль всегда заносит в стек параметр-значение размером в байт, как 16-битовое слово. При этом сообщить Турбо Ассемблеру о дополнительном байте должны вы. Предположим, например, что вы на- писали функцию, описание которой в Паскале выглядит следующим об- разом:

function MyProc(i, j : char) : string; external;

Директива ARG для этой функции должна была бы выглядеть так:

ARG j: BYTE: 2, i:BYTE: 2 = RetBytes RETURN result: DWORD

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

В функции, возвращающей строковое значение (как данная функ- ция), параметр RETURNS в директиве ARG позволяет вам определить переменную, приравненную к тому месту в стеке, которое указывает на временный результат функции. Переменная в RETURNS на размер (в байтах) блока параметров.



Директива ASSUME


Если вы хотите получить доступ к данным сегмента, сегментный регистр должен загружаться корректным значением сегмента. Часто это нужно делать вам самим. Например, для загрузки в регистр DS адреса текущего сегмента данных дальнего типа вы можете использо- вать команды:

MOV AX,@fardata MOV DS,AX

Когда программа загружает в сегментный регистр значение сег- мента, вы можете использовать этот сегментный регистр для доступа к данным в сегменте. Это быстро утомляет, и вы начинаете забывать каждый раз при обработке данных в памяти задавать сегментный ре- гистр (или у вас недостаточно практики в программировании).

Чтобы указать Турбо Ассемблеру, что нужно связать сегментный регистр с именем сегмента или группы, используйте директиву ASSUME. Это позволяет Турбо Ассемблеру быть "достаточно проница- тельным" и использовать при доступе к данным конкретный сегмент.

Фактически, Турбо Ассемблер использует также информацию о связи между сегментным регистром и именем сегмента также и для других целей: в режиме MASM значение, которое подразумевается для регистра CS, используется для определения сегмента или группы, к которому принадлежит метка. Таким образом, регистр CS должен кор- ректно задаваться в директиве ASSUME, в противном случае Турбо Ассемблер при каждом определении метки или процедуры будет сооб- щать об ошибке.

Директива ASSUME имеет следующий синтаксис:

ASSUME сегм_регистр : выражение [, сегм_регистр : выражение]

или ASSUME nothing

где "сегм_регистр" - это один из регистров CS, DS, ES или SS. Ес- ли вы задаете процессор 80386 или 80486, то можете использовать регистры FS и GS. "Выражение" может быть любым выражением, при вычислении которого получается имя сегмента или группы. В против- ном случае может использоваться ключевое слово NOTHING. Это клю- чевое слово отменяет связь между сегментным регистром и любым сегментом или именем группы.

Директива ASSUME NOTHING отменяет связь между всеми сегмент- ными регистрами и сегментом или именем группы.

Вы можете использовать директиву ASSUME при модификации сег- ментного регистра или в начале процедуры для задания в этой точке предположений о сегментных регистрах. На практике ASSUME исполь- зуется обычно в начале модуля и иногда внутри него. Если вы ис- пользуете оператор MODEL, то Турбо Ассемблер назначает директиву ASSUME по умолчанию.

Если вы не задаете в директиве ASSUME значение, то ранее за- данное в ней значение не изменяется.

Например, в следующем фрагменте программы показано, как мож- но загрузить текущий инициализированный сегмент данных дальнего типа в регистр DS, обратиться через этот регистр к памяти и восс- тановить регистр DS в значение сегмента данных:

MOV AX,@fardata MOV DS,AX ASSUME DS:@fardata: MOV BX,<переменная_данных_дальнего_типа> MOV AX,@data MOV DS,AX ASSUME DS:@data



Директива CATSTR


Директива CATSTR определяет новую текстовую макрокоманду пу- тем конкатенации строк. Она имеет следующий синтаксис:

имя CATSTR строка[,строка].

Директива CATSTR выполняет конкатенацию слева-направо. Турбо Ассемблер создает новую текстовую макрокоманду с именем "имя".



Директива COMMENT


Директива COMMENT позволяет вам комментировать блок исходно- го кода. COMMENT позволяет игнорировать весь текст, начиная от первого символа-ограничителя и до строки, содержащей следующее вхождение ограничителя. В следующем примере в качестве ограничи- теля используется символ *:

COMMENT * здесь следуют замечания * Примечание: Директива COMMENT работает только в режиме MASM.



Директива DOSSEG: упорядочивание сегментов в порядке DOS


Обычно компоновщик упорядочивает сегменты в последовательном порядке - в том порядке, в котором он их обрабатывает при генера- ции программы. Если вы включаете в любой модуль программу дирек- тиву DOSSEG, то это указывает компоновщику, что вместо этого упорядочивания нужно использовать порядок сегментов, принятый в DOS. Компоновщик при этом выполняет в получаемой программе следу- ющее упорядочивание:

- сначала идут сегменты с именем класса CODE (обычно сегмен- ты кода);

- затем следуют сегменты, не имеющие имени класса CODE и не являющиеся частью DGROUP;

- сегменты, являющиеся частью DGROUP в следующем порядке:

1. сегменты, не являющиеся классами BSS и STACK (обыч- но неинициализированные данные);

2. сегменты класса BSS (обычно инициализированные дан- ные);

3. сегменты класса STACK (область стека).

Примечание: Не используйте директиву DOSSEG, в прог- раммах, не являющихся автономными программами на Ассембле- ре.

Сегменты в группе DGROUP располагаются в том порядке, в ко- тором они определены в исходных модулях. Приведем синтаксис DOSSEG:

DOSSEG



Директива END


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

END начальный_адрес:

где "начальный_адрес" - это необязательный идентификатор или вы- ражение, определяющий адрес в программе, с которого вы хотите на- чать выполнение. Если ваша программа скомпонована из нескольких исходных файлов, начальный адрес может задаваться только в одном из них. Этот адрес может представлять собой адрес в модуле. Он может быть также внешним идентификатором, определенным в другом модуле, описанном по директиве EXTRN.

Любой текст, указанный в исходном файле после директивы END, Турбо Ассемблер игнорирует.

Пример:

.MODEL small .CODE ; тело программы END START ; точка входа программы "START" THIS LINE IS IGNORED ; эта строка игнорируется SO IS THIS ONE ; эта строка тоже



Директива ENDS


Вы можете использовать директиву ENDS для закрытия сегмента, после чего данные в него больше включаться не будут. Директиву ENDS следует использовать для закрытия любого сегмента, открытого по директиве SEGMENT. Сегменты, открытые с помощью упрощенных ди- ректив определения сегментов, не требуют директивы ENDS.

Директива ENDS имеет следующий синтаксис:

ENDS [имя]

В режиме MASM вы можете использовать следующий синтаксис:

имя ENDS

где "имя" задает имя сегмента, который должен быть закрыт. Если имя не согласуется с именем текущего открытого сегмента, Турбо Ассемблер будет выводить сообщение об ошибке. Если имя не задает- ся, Турбо Ассемблер подразумевает текущий сегмент.



Директива EXITCODE


Директива EXITCODE используется для генерации кода заверше- ния, соответствующего текущей операционной системе. Вы можете использовать ее в модуле несколько раз (для каждой точки входа). Эта директива имеет следующий синтаксис:

EXITCODE [возвращаемое_значение]

В режиме MASM вы можете использовать следующий синтаксис:

.EXIT [возвращаемое_значение]

Необязательное "возвращаемое_значение" описывает число, ко- торое должно возвращаться в операционную систему. Если вы не за- даете возвращаемое значение, Турбо Ассемблер предполагает, что это значение содержится в регистре AX.



Директива EXITM


Директиву EXITM можно использовать в теле макрокоманды для принудительного завершения ассемблирования включаемого тела мак- рокоманды. Она имеет следующий синтаксис:

EXITM

Когда Турбо Ассемблер обнаруживает директиву EXITM в теле макрокоманды, которая включена в исходный код модуля, ассемблиро- вание расширенного тела макрокоманды немедленно прекращается. Вместо этого Турбо Ассемблер будет продолжать ассемблирование мо- дуля после конца макрокоманды.

Для завершения макрокоманды при определенных условиях вы мо- жете использовать оператор EXITM с директивой условного ассембли- рования.

Примечание: Директивы условного ассемблирования под- робнее рассматриваются в Главе 15.



Директива EXTRN


Модуль Турбо Ассемблера может обращаться к любой процедуре, функции, переменной или типизованной константе Турбо Паскаля, ко- торая описывается на самом внешнем уровне программы или модуля, с которым она компонуется. (Заметим, что это включает в себя пере- менные, описанные после директивы компилятора {$L} и внешние опи- сания, связанные с данным модулем.) Метки и обычные константы Турбо Паскаля языку Ассемблера недоступны.

Примечание: Эти включает в себя переменные, указанные после директивы компилятора $L и описаниях external, свя- занных с данным модулем.

Предположим, в вашем программе Турбо Паскаля описываются следующие глобальные переменные:

var a : byte; b : word; c : shortint; d : integer; e : real; f : single; g : double; h : extended; i : comp; j : pointer;

В программе на языке Ассемблера вы можете получить доступ ко всем этим переменным с помощью описаний EXTRN:

EXTRN A : BYTE ; 1 байт EXTRN B : WORD ; 2 байта EXTRN C : BYTE ; в Ассемблере значения со знаком и ; без знака интерпретируются одинаково EXTRN D : WORD ; то же самое EXTRN E : FWORD ; 6-байтовое действительное значение ; (обрабатывается программно) EXTRN F : DWORD ; 4-байтовое значение с плавающей ; точкой в формате IEEE EXTRN G : QWORD ; 8-байтовое значение с плавающей ; точкой (двойной точности) в ; формате IEEE EXTRN H : TBYTE ; 10-байтовое значение с плавающей ; точкой во временном формате EXTRN I : QWORD ; 8-байтовое целое со знаком в ; формате IEEE (сопроцессор 8087) EXTRN J : DWORD ; указатель Турбо Паскаля

Аналогичным образом можно получить доступ к процедурам и функциям Турбо Паскаля, включая библиотечные. Предположим, у вас имеется модуль Турбо Паскаля, который выглядит следующим образом:

unit Sample; { Пример модуля, в котором определяется нескольку процедур Паскаля, вызываемых из процедуры на языке Ассемблера }

interface

procedure TestSample;

procedure PublicProc; { для обращения извне должна быть дальнего типа } inplementation

var A : word;

procedure AsmProc; external; {$L ASMPROC.OBJ}


procedure PublicProc; begin { PublicProc } Writeln('В PublicProc'); end { PublicProc }

procedure NearProc; { должна быть ближнего типа } begin { NearProc } Writeln('B NearProc'); end; { NearProc }

{$F+} procedure FarProc { должна иметь дальний тип согласно директиве компилятора } begin { FarProc } Writeln('B FarProc'); end { FarProc }

{$F-}

procedure TestSample; begin { TestSample } Writeln('B TestSample'); A := 10; Writeln('Значение A перед ASMPROC = ',A); AsmProc; Writeln('Значение A после ASMPROC = ',A); end { TestSample };

end.

Процедура AsmProc вызывает процедуры PublicProc, NearProc или FarProc, используя директиву EXTRN следующим образом:

DATA SEGMENT WORD PUBLIC ASSUME DS:DATA EXTRN A:WORD ; переменная из модуля DATA ENDS

CODE SEGMENT BYTE PUBLIC ASSUME CS:CODE EXTRN PublicProc : FAR ; дальняя процедура ; (экспортируется модулем) EXTRN NearProc : NEAR ; ближняя процедура ; (локальная для модуля) EXTRN FarProc : FAR ; дальняя процедура ; (локальна, но задана, ; как дальняя) AsmProc PROC NEAR PUBLIC AsmProc CALL FAR PTR PublicProc CALL NearProc CALL FAR PTR FarProc mov cx,ds:A ; взять переменную из ; модуля sub cx,2 ; изменить ее mov ds:A,cx ; записать ее обратно RET AsmProc ENDP CODE ENDS END

Основная программа, которая проверяет эту программу на Ас- семблере и модуль Паскаля, выглядит следующим образом:

program TSample; uses Sample; begin TestSample; end.

Чтобы сформировать пример программы с помощью компилятора, работающего в режиме командной строки, и Ассемблера, используйте следующие команды (или командный файл):

TASM ASMPROC TPC /B SAMPLE TSAMPLE

Так как внешняя подпрограмма должна объявляться в программе Турбо Паскаля на самом внешнем уровне процедур, вы не можете для доступа к объектам, являющимся локальными по отношению к процеду- рам или функциям использовать описания EXTRN. Однако, ваша прог- рамма на Турбо Ассемблере при вызове из программы Турбо Паскаля может получить эти объекты, как значения параметров-переменных.


Директива GOTO и макроидентификаторы перехода


Использование директивы GOTO и макроидентификаторов перехода позволяют вам управлять последовательностью расширения строк мак- рокоманды. Вы можете поместить цель перехода в любом месте тела макрокоманды. Она занимает всю строку макрокоманды и имеет следу- ющий синтаксис:

:идентификатор_перехода

При расширении макрокоманды все макроидентификаторы перехода отбрасываются.

Директива GOTO сообщает Турбо Ассемблеру, что нужно перейти на заданную точку исходного кода, а именно - на "идентифика- тор_перехода". Это позволяет вам поместить GOTO в блоке условного ассемблирования. Например:

IF foo GOTO tag1 ENDIF DISPLAY "foo имеет значение false!" :tag ; возобновление макрокоманды. ; работает одинаково, независимо от того, ; равно foo false или true

Примечание: Будьте аккуратны и не создавайте при ис- пользовании директивы GOTO бесконечных циклов. Бесконечные циклы могут привести к тому, что Турбо Ассемблер исчерпает доступную память или даже прекратит работу.

Подробнее о директивах условного ассемблирования рассказыва- ется в Главе 15.



Директива GROUP


----------------------------------------------------------------

Директива GROUP может использоваться для присваивания сег- ментов группам. Группы позволяют вам для доступа ко всем сегмен- там группы задавать один сегмент.

В режиме Ideal директива GROUP имеет следующий синтаксис:

GROUP имя имя_сегмента [, имя_сегмента.]

В режиме MASM вы можете использовать следующий синтаксис:

имя GROUP имя_сегмента [, имя_сегмента.]

где "имя" представляет собой имя группы, а "имя_сегмента" - это имя сегмента, которое вы хотите присвоить группе.