Подтипы идентификаторов описывают идентификатор, представля- ющий адрес байта, слова и т.д. Простые адресные подтипы, которые предусмотрены в Турбо Ассемблере, приведены в Таблице 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-------------------+--------------------------------------------
(Требуется явно указать тип операнда)
Требуется явно указать размер, или тип, выражения, т.к. он не может быть определен из контекста. Например, ошибочной являет- ся следующая команда:
mov [bx],1
Ошибки такого рода обычно корректируются с помощью операции PTR, позволяющей установить размер операнда:
mov WORD PTR[bx],1
(Операнд операции или команды имеет недопустимый размер)
В операции указан операнд, имеющий тип, недопустимый для данной операции. Например:
Q LABEL QWORD QNOT = NOT Q ; операнд операции отрицания не может ; иметь тип QWORD
(Арифметическое переполнение)
Потеря значащих цифр при вычислении значения выражения. Нап- ример:
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 должен быть указан сегментный регистр)
В директиве 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.
(Неверное ключевое слово в операторе SEGMENT)
Один из параметров директивы SEGMENT: тип выравнивания, тип объединения или тип сегмента имеет недопустимое значение. Напри- мер:
DATA SEGMENT PAFA PUBLIC ; вместо PARA указано PAFA
(Неверный параметр-переключатель командной строки)
В командной строке указан неверный параметр. См. Главу 2, где дается подробное описание параметров командной строки.
Безусловными директивами генерации сообщений об ошибке явля- ются директивы ERR и .ERR. Эти директивы всегда генерируют ошибку и не требуют аргументов, хотя могут содержать необязательное со- общение. Директиву .ERR можно использовать только в режиме MASM.
(Нельзя складывать относительные адреса)
Выражение содержит операцию сложения двух адресов, что явля- ется бессмысленной операцией. Например:
ABC DB ? DEF = ABC + ABC ; ошибка: нельзя складывать ; два относительные адреса
Можно вычитать относительные адреса. Можно добавить констан- ту к относительному адресу, например:
XYZ DB 5 DUP(0) XYZEND EQU $ XYZLEN = SYZEND - XYZ ; совершенно верно XYZ2 = XYZ + 2 ; тоже верно
(Невозможна адресация из текущих, установленных директивой ASSUME, сегментных регистров)
В выражении содержится ссылка на переменную, для доступа к которой не специфицирован сегментный регистр. Например:
DSEG SEGMENT ASSUME ds:DSEG mov si,MPTR ; не определен сегментный регистр, который ; обеспечил бы доступ к сегменту XSEG DSEG ENDS XSEG SEGMENT MPTR DW ? XSEG ENDS
(Невозможно преобразование в указатель)
Часть выражения не может быть преобразована в указатель на память, например, с помощью операции PTR:
mov cl,[BYTE PTR al] ; AL нельзя преобразовать ; в указатель
(Невозможна эмуляция команд сопроцессора 8087)
В Турбо Ассемблере параметром командной строки /E либо с по- мощью директивы EMUL установлен режим генерации эмулированных ко- манд арифметики с плавающей точкой, однако текущая команда не мо- жет быть эмулирована. Например:
EMUL FNSAVE [WPTR] ; эта команда не может быть эмулирована
Некоторые команды не поддерживаются эмуляторами арифметики с плавающей точкой. Это команды FNSAVE, FNSTCW, FNSTENV и FNSTSW.
(Не найден файл подсказок __)
В командной строке указано имя несуществующего файла подска- зок. Следует проверить, указано ли полное имя файла. В Турбо Ас- семблере отсутствует умолчание для расширения имени файла подска- зок. Вероятной причиной данного сообщения может быть отсутствие места на диске при записи на этот диск файла, содержащего перек- рестные ссылки.
(Переменная не может быть объявлена как PUBLIC)
Переменная была уже ранее объявлена таким образом, что уже не может быть определена как общая (PUBLIC). Например:
EXTRN ABC:NEAR PUBLIC ABC ; ошибка: ABC уже ранее объявлена ; с атрибутом EXTRN
(Нельзя переопределить сегмент ES)
В текущем операторе указан регистр, использование которого в данной команде недопустимо. Например:
STOS DS:BYTE PTR[di]
В команде STOS для определения целевого адреса допускается использовать только регистр ES.
(Недопустимое вычитание относительных адресов)
Выражение содержит операцию вычитания двух адресов, которая для данных адресов является недопустимой. Данное сообщение выда- ется, например, в том случае, если адреса находятся в разных сег- ментах. Например:
SEG1 SEGMENT A: SEG1 ENDS SEG2 SEGMENT B: mov ax,B-A ; недопустимо, поскольку A и В находятся ; в разных сегментах SEG2 ENDS
(Недопустимо использование имени макрокоманды в качестве операнда выражения)
Имя макрокоманды указано в качестве операнда выражения. Нап- ример:
MyMac MACRO ENDM mov ax,MyMac ; ошибка!
(Использование данного оператора недопустимо вне макроопре- деления)
Вне макроопределения указана директива, которую допускается использовать только внутри макроопределений. К таким директивам относятся, например, 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----------------------------+-----------------------------------
(Не объявлен сегмент для кода или данных)
Оператор, генерирующий код или данные, не принадлежит ни од- ному из сегментов, объявленных директивами SEGMENT. Например:
; Первая строка файла inc bx ; ошибка: не определен сегмент END
Генерировать данные или код можно только внутри какого-либо сегмента.
(Константа интерпретируется как непосредственная)
Это предупреждающе сообщение выдается для выражений типа [0]. В режиме MASM это выражение интерпретируется как непосредс- твенная константа, равная 0. Например:
mov ax,[0]; означает mov ax,0, а не mov ax,ds:[0]
(Слишком большая константа)
Константа имеет, вообще говоря, правильный формат, однако ее значение превышает допустимую для данного режима величину. Напри- мер, числа, большие 0ffffh, можно использовать, если только ди- рективой .386/.386P или .486/.486Р разрешены команды процессора 386 или i486.
(Некорректное значение в регистре CS)
Адрес назначения в командах ближнего вызова и ближнего пере- хода не может находиться в другом сегменте. Например:
SEG1 SEGMENT LAB1 LABEL NEAR SEG1 ENDS SEG2 SEGMENT JMP LAB1 ; ошибка: неверный сегментный адрес SEG2 ENDS
Такие ошибки возникают только в режиме MASM. В режиме Ideal такие переходы и вызовы интерпретируются корректно.
(Переопределение регистра CS в защищенном режиме)
В защищенном режиме ассемблирования команд процессора 286, 386 или i486, установленном директивой Р286Р, P386P или Р486Р, в текущей команде требуется переопределение регистра CS. Например:
P286 .CODE CVAL DW ? mov CVAL,1 ; генерирует переопределение регистра CS
Это предупреждающее сообщение выдается, если в командной строке указан параметр /Р. В защищенном режиме команды, в которых переопределяется регистр CS, не будут выполняться без специальных подготовительных операций.
(CS недостижим из текущего сегмента)
При определении метки кода с помощью двоеточия (:) или с по- мощью директив LABEL или PROC сегментный регистр не указывает на текущий кодовый сегмент или группу, содержащую текущий кодовый сегмент. Например:
PROG1 SEGMENT ASSUME CS:PROG2 START: ; ошибка: неверно установлен регистр CS
Такие ошибки возникают только в режиме MASM. В режиме Ideal такие переходы и вызовы обрабатываются корректно.
(В директиве объявления не указано имя)
Не указано имя идентификатора в директиве, для которой спе- цификация имени является обязательной. Например:
PROC ; ошибка: в директиве PROC указание имени обязательно ret ENDP
В директивах объявления, таких как SEGMENT, PROC или STRUC, обязательно должно быть указано имя идентификатора. В режиме MASM имя указывается перед именем директивы, а в режиме Ideal - после имени директивы.
(В режиме TPASCAL директива игнорируется)
В модуле Ассемблера, предназначенном для интерфейса с Турбо Паскалем, используется недопустимая директива. Режим интерфейса с Турбо Паскалем специфицируется директивой .MODEL. Более подробно интерфейс с Турбо Паскалем обсуждается в Главе 19.
(Недопустимая директива внутри определения структуры)
Внутри блока определения структуры указана недопустимая ди- ректива. Например:
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
Назад | Содержание | Вперед
Для выравнивания счетчика адреса на адрес, значение которо- го равно степени 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
Хотя можно обращаться к параметрам через регистр 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 на размер (в байтах) блока параметров.
Если вы хотите получить доступ к данным сегмента, сегментный регистр должен загружаться корректным значением сегмента. Часто это нужно делать вам самим. Например, для загрузки в регистр 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 выполняет конкатенацию слева-направо. Турбо Ассемблер создает новую текстовую макрокоманду с именем "имя".
Директива COMMENT позволяет вам комментировать блок исходно- го кода. COMMENT позволяет игнорировать весь текст, начиная от первого символа-ограничителя и до строки, содержащей следующее вхождение ограничителя. В следующем примере в качестве ограничи- теля используется символ *:
COMMENT * здесь следуют замечания * Примечание: Директива COMMENT работает только в режиме MASM.
Обычно компоновщик упорядочивает сегменты в последовательном порядке - в том порядке, в котором он их обрабатывает при генера- ции программы. Если вы включаете в любой модуль программу дирек- тиву DOSSEG, то это указывает компоновщику, что вместо этого упорядочивания нужно использовать порядок сегментов, принятый в DOS. Компоновщик при этом выполняет в получаемой программе следу- ющее упорядочивание:
- сначала идут сегменты с именем класса CODE (обычно сегмен- ты кода);
- затем следуют сегменты, не имеющие имени класса CODE и не являющиеся частью DGROUP;
- сегменты, являющиеся частью DGROUP в следующем порядке:
1. сегменты, не являющиеся классами BSS и STACK (обыч- но неинициализированные данные);
2. сегменты класса BSS (обычно инициализированные дан- ные);
3. сегменты класса STACK (область стека).
Примечание: Не используйте директиву DOSSEG, в прог- раммах, не являющихся автономными программами на Ассембле- ре.
Сегменты в группе DGROUP располагаются в том порядке, в ко- тором они определены в исходных модулях. Приведем синтаксис DOSSEG:
DOSSEG
Используйте директиву END, чтобы отметить конец исходного файла. При этом используется следующий синтаксис:
END начальный_адрес:
где "начальный_адрес" - это необязательный идентификатор или вы- ражение, определяющий адрес в программе, с которого вы хотите на- чать выполнение. Если ваша программа скомпонована из нескольких исходных файлов, начальный адрес может задаваться только в одном из них. Этот адрес может представлять собой адрес в модуле. Он может быть также внешним идентификатором, определенным в другом модуле, описанном по директиве EXTRN.
Любой текст, указанный в исходном файле после директивы END, Турбо Ассемблер игнорирует.
Пример:
.MODEL small .CODE ; тело программы END START ; точка входа программы "START" THIS LINE IS IGNORED ; эта строка игнорируется SO IS THIS ONE ; эта строка тоже
Вы можете использовать директиву ENDS для закрытия сегмента, после чего данные в него больше включаться не будут. Директиву ENDS следует использовать для закрытия любого сегмента, открытого по директиве SEGMENT. Сегменты, открытые с помощью упрощенных ди- ректив определения сегментов, не требуют директивы ENDS.
Директива ENDS имеет следующий синтаксис:
ENDS [имя]
В режиме MASM вы можете использовать следующий синтаксис:
имя ENDS
где "имя" задает имя сегмента, который должен быть закрыт. Если имя не согласуется с именем текущего открытого сегмента, Турбо Ассемблер будет выводить сообщение об ошибке. Если имя не задает- ся, Турбо Ассемблер подразумевает текущий сегмент.
Директива EXITCODE используется для генерации кода заверше- ния, соответствующего текущей операционной системе. Вы можете использовать ее в модуле несколько раз (для каждой точки входа). Эта директива имеет следующий синтаксис:
EXITCODE [возвращаемое_значение]
В режиме MASM вы можете использовать следующий синтаксис:
.EXIT [возвращаемое_значение]
Необязательное "возвращаемое_значение" описывает число, ко- торое должно возвращаться в операционную систему. Если вы не за- даете возвращаемое значение, Турбо Ассемблер предполагает, что это значение содержится в регистре AX.
Директиву EXITM можно использовать в теле макрокоманды для принудительного завершения ассемблирования включаемого тела мак- рокоманды. Она имеет следующий синтаксис:
EXITM
Когда Турбо Ассемблер обнаруживает директиву EXITM в теле макрокоманды, которая включена в исходный код модуля, ассемблиро- вание расширенного тела макрокоманды немедленно прекращается. Вместо этого Турбо Ассемблер будет продолжать ассемблирование мо- дуля после конца макрокоманды.
Для завершения макрокоманды при определенных условиях вы мо- жете использовать оператор EXITM с директивой условного ассембли- рования.
Примечание: Директивы условного ассемблирования под- робнее рассматриваются в Главе 15.
Модуль Турбо Ассемблера может обращаться к любой процедуре, функции, переменной или типизованной константе Турбо Паскаля, ко- торая описывается на самом внешнем уровне программы или модуля, с которым она компонуется. (Заметим, что это включает в себя пере- менные, описанные после директивы компилятора {$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}
Использование директивы GOTO и макроидентификаторов перехода позволяют вам управлять последовательностью расширения строк мак- рокоманды. Вы можете поместить цель перехода в любом месте тела макрокоманды. Она занимает всю строку макрокоманды и имеет следу- ющий синтаксис:
:идентификатор_перехода
При расширении макрокоманды все макроидентификаторы перехода отбрасываются.
Директива GOTO сообщает Турбо Ассемблеру, что нужно перейти на заданную точку исходного кода, а именно - на "идентифика- тор_перехода". Это позволяет вам поместить GOTO в блоке условного ассемблирования. Например:
IF foo GOTO tag1 ENDIF DISPLAY "foo имеет значение false!" :tag ; возобновление макрокоманды. ; работает одинаково, независимо от того, ; равно foo false или true
Примечание: Будьте аккуратны и не создавайте при ис- пользовании директивы GOTO бесконечных циклов. Бесконечные циклы могут привести к тому, что Турбо Ассемблер исчерпает доступную память или даже прекратит работу.
Подробнее о директивах условного ассемблирования рассказыва- ется в Главе 15.
----------------------------------------------------------------
Директива GROUP может использоваться для присваивания сег- ментов группам. Группы позволяют вам для доступа ко всем сегмен- там группы задавать один сегмент.
В режиме Ideal директива GROUP имеет следующий синтаксис:
GROUP имя имя_сегмента [, имя_сегмента.]
В режиме MASM вы можете использовать следующий синтаксис:
имя GROUP имя_сегмента [, имя_сегмента.]
где "имя" представляет собой имя группы, а "имя_сегмента" - это имя сегмента, которое вы хотите присвоить группе.