Директива INSTR возвращает позицию одной строки внутри дру- гой. Она имеет следующий синтаксис:
имя INSTR [выражение_начала,]строка_1,строка_2
Турбо Ассемблер присваивает "имя" числовому значению, кото- рое соответствует первой позиции первого вхождения "строки_2" в "строку_1". Первый символ "строки_1" имеет позицию 1. Если "стро- ка_2" в "строке_1" не содержится, то Турбо Ассемблер возвращает значение 0. Если вы укажете "выражение_начала", то поиск начина- ется с символа, задаваемого этим выражением. Первый символ строки находится в позиции 1.
Два ключевых момента при использовании Турбо Ассемблера с Турбо Паскалем - это директива компилятора (Турбо Паскаля) {$L} и описание внешней (external) подпрограммы. Директива {$L MYFILE.OBJ} приводит к тому, что Турбо Паскаль будет искать файл объектный MYFILE.OBJ (файл в стандартном пригодном для компоновки формате MS-DOS) и компоновать его с вашей программой Турбо Паска- ля. Если у файла в директиве {$L} расширение не указывается, то подразумевается расширение .OBJ.
Каждая процедура или функция Турбо Ассемблера, которую вы хотите сделать доступной в программе Турбо Паскаля, должна объяв- ляться, как идентификатор PUBLIC, и ей должно соответствовать в программе описание external (внешняя). Синтаксис описания внешней процедуры или функции в Турбо Паскале аналогичен опережающему (forward) описанию:
procedure AsmProc(a : integer; b : real); external;
function AsmFunc(c : word; d : byte); external;
Эти описания должны соответствовать следующим описаниям в программе Турбо Ассемблера:
CODE SEGMENT BYTE PUBLIC AsmProc PROC NEAR PUBLIC AsmProc . . . AsmProc ENDP AsmFunc PROC FAR PUBLIC Bar . . . AsmFunc ENDP CODE ENDS
Описание внешней (external) процедуры Турбо Паскаля должно находиться на самом внешнем уровне программы или модуля, то есть оно не должно быть вложенным по отношению к другому описанию про- цедуры или функции. Попытка описать процедуру или функцию на лю- бом другом уровне приведет к ошибке этапа компиляции.
Турбо Паскаль не делает проверку, чтобы убедиться, что все процедуры, описанные с атрибутами NEAR или FAR, соответствуют ближним или дальним подпрограммам в программе Турбо Паскаля. Фак- тически, он даже не проверяет, являются ли метки AsmProc и AsmFunc именами процедур. Поэтому вы должны обеспечить, чтобы описания в Ассемблере и Паскале были правильными.
Директиву LABEL вы можете использовать для определения иден- тификатора заданного типа. Заметим, что синтаксис в режимах MASM и Ideal различен. В режиме Ideal задавайте:
LABEL имя сложный_тип
В режиме MASM используйте следующее:
имя LABEL сложный_тип
где "имя" - это идентификатор, который вы не определяли ранее в исходном файле. "Сложный_тип" описывает размер идентификатора и то, ссылается он на код или данные. См. Главу 5, в которой можно найти дальнейшую информацию о сложных типах.
Если вы не используете директиву PUBLIC, чтобы метка была доступна из других файлов, она доступна только в текущем исходном файле.
Вы можете использовать директиву LABEL для доступа к элемен- там различного размера, которые содержатся в структуре данных. Этот принцип иллюстрируется следующим примером:
WORDS LABEL WORD ; доступ к "BYTES" как к ; WORDS BYTES DB 64 DUP (0) mov WORDS[2],1 ; запись в WORDS 1
Директива MODEL позволяет вам задать для программы несколько стандартных моделей сегментации. Вы можете также использовать ее для задания языка для процедур программы.
Директива MODEL имеет следующий синтаксис:
MODEL [модификатор_модели] модель_памяти [имя_сегмента_кода] [,[модификатор_языка] язык] [, модификатор_модели]
В режиме MASM используется тот же синтаксис, но директива имеет вид .MODEL.
"Модель_памяти" и "модификатор_модели" определяют модель сегментации памяти, используемую в программе.
В применяемых в Турбо Ассемблере стандартных моделях можно использовать специальные сегменты для:
- кода;
- инициализированных данных;
- неинициализированных данных;
- инициализированных данных дальнего типа;
- неинициализированных данных дальнего типа;
- констант;
- стека.
Сегмент кода содержит обычно код модуля (но при необходимос- ти может также содержать данные). В целях совместимости с языками высокого уровня инициализированные данные и константы интерпрети- руются по-разному. Они содержат такие данные, как сообщения, ког- да важно начальное значение. Неинициализированные данные и стек содержат данные, начальные значения которых не существенны. Ини- циализированные данные дальнего типа (far) - это неинициализиро- ванные данные, которые не являются частью стандартного сегмента данных, и которые доступны только при изменении значения сегмент- ного регистра. Это же относится к неинициализированным данным дальнего типа, только вместо инициализированных данных здесь со- держатся неинициализированные данные.
Специальные модели памяти задают, как можно ссылаться на эти сегменты с помощью сегментных регистров, и как они объединяются в группы (если это имеет место). При написании программы вы должны хранить эти сегменты отдельно, независимо от размера программы. Затем для объединения сегментов в группы вы можете выбрать соот- ветствующую модель. Если вы храните эти сегменты раздельно, и ва- ша программа увеличивается в размере, вы можете использовать большую модель.
Используйте директиву NAME для задания имени модуля объект- ного файла. Она имеет следующий синтаксис:
NAME имя_модуля
Примечание: Данная директива работает только в режиме Ideal.
Турбо Ассемблер обычно использует в качестве имени модуля имя исходного файла с дисководом, каталогом и расширением. Если вы хотите изменить это используемое по умолчанию имя, укажите ди- рективу NAME. Новым именем модуля будет имя "имя_модуля", напри- мер:
NAME loader
Вы можете использовать директиву ORG, чтобы установить счетчик адреса в значение текущего сегмента. Директива ORG имеет следующий синтаксис:
ORG выражение
где "выражение" не может содержать никаких имен идентификаторов с опережающими ссылками. Оно может быть константой или смещением от идентификатора в текущем сегменте, либо смещением относительно текущего счетчика адреса.
Перед данными или кодом, которые уже введены в сегмент, вы можете восстановить значение счетчика адреса. Это можно использо- вать для возврата назад и заполнения записей таблицы, значения которых не были известны во время определения таблицы. Используй- те этот метод с осторожностью: вы можете непреднамеренно что-либо затереть.
Директиву ORG можно использовать для того, чтобы связать метку с конкретным адресом. Директива ORG может также использо- ваться для задания начального адреса файлов .COM. Приведем приме- ры ее использования:
PROG SEGMENT ORG 100h ; начальное смещение файла .COM start: ; ; остальная часть программы .COM PROG ENDS end start
Приведем другой пример:
PROG SEGMENT ASSUME cs:PROG, ds:PROG, ss:PROG, es:NOTHING ORG 20h EnvPtr label word ; определить метку для доступа ; к слову в PSP, которое ука- ; зывает на сегмент, содержа- ; щий блок операционной среды ; (он обычно освобождается для ; создания более компактной ; резидентной программы) ORG 80h CmdLength lebel byte ; определить метку для доступа ; к длине командной строки
ORG @1h CmdLine label byte ; определить метку для доступа ; к тексту командной строки
ORG 0100h start:
; освободить блок операционной среды
mov es, EnvPtr ; ES -> блок операционной среды mov ah, 49h ; функция 49h: освободить блок ; памяти int 21h ; вызвать MS-DOS jc error_ENV ; ошибка освобождения EnvBlock?
; анализ командной строки
mov al, CmdLength ; длина командной строки or al,al ; проверка на 0 jz no_params ; нет параметров mov cl,al ; поместить длину в cl mov ch,0 mov si,offset CmdLine ; адрес командной строки mov al,' ' ; символ для поиска repne scasb ; поиск первого пробела ; ; остальная часть файла .COM резидентной программы: PROG ENDS end start
В Турбо Паскале доступны только те метки Ассемблера, которые объявлены в модуле на языке Ассемблера, как общедоступные (PUBLIC). Метки представляют собой единственные объекты, которые могут передаваться из языка Ассемблера в Турбо Паскаль. Более того, каждой общедоступной метке должно соответствовать описание процедуры или функции в программе Турбо Паскаля, иначе компилятор выдаст сообщение об ошибке. Причем не требуется, чтобы общедос- тупная метка была частью описания PROC. Что касается Турбо Паска- ля, то для него описания:
AsmLabel PROC FAR PUBLIC Bar и
AsmLabel: PUBLIC Bar
эквивалентны.
Вы можете определять такие идентификаторы как PUBLIC только в сегменте CODE. Турбо Паскаль не разрешает определения идентифи- каторов PUBLIC в сегменте данных, поэтому создаваемые вами ас- семблерные модули для компоновки с программой на Турбо Паскале также не должны иметь в сегменте данных.
Директива SEGMENT открывает сегмент. Все последующие код или данные до директивы ENDS, которая закрывает сегмент, будут вклю- чены в этот сегмент.
В режиме Ideal директива SEGMENT имеет следующий синтаксис:
SEGMENT имя [атрибуты]
В режиме MASM директива SEGMENT имеет следующий синтаксис:
имя SEGMENT [атрибуты]
где "имя" - это имя сегмента. Назначать сегментам имена нужно в соответствии с их использованием. Примеры имен сегментов можно найти в Приложении A.
В одном сегменте вы можете несколько раз открыть и закрыть сегмент с одним и тем же именем. Турбо Ассемблер выполняет конка- тенацию всех частей сегмента. Атрибуты сегмента нужно задавать только при первом его открытии.
Атрибуты могут включать в себя все или некоторые значения атрибутов сегмента, которые определяют следующее:
- атрибут комбинирования сегмента;
- атрибут класса сегмента:
- атрибут выравнивания сегмента;
- атрибут размера сегмента;
- атрибут доступа к сегменту.
Примечание: Заметим, что Турбо Ассемблер обрабатывает значения атрибутов слева-направо.
Директива .SEQ определяет последовательное упорядочивание сегментов и сообщает Турбо Ассемблеру, что сегменты нужно поме- щать в объектный файл в том порядке, в котором они встречаются в исходном файле. Поскольку это поведение предполагается Турбо Ас- семблером по умолчанию, директиву .SEQ используют обычно только для переопределения предыдущей директивы .ALPHA. Данная директива имеет следующий синтаксис:
.SEQ
Директива SIZESTR возвращает длину текстовой макрокоманды (число символов в строке). Она имеет синтаксис:
имя SIZESTR строка
где "имя" устанавливается в числовое значение, равное длине ука- занной строки. Нулевая строка <> имеет длину 0.
Директива STARTUPCODE обеспечивает код инициализации, соот- ветствующий текущей модели и операционной системе. Она отмечает также начало программы. Эта директива имеет следующий синтаксис:
STARTUPCODE
или
.STARTUP ; (только для режима MASM)
Директива STARTUPCODE инициализирует регистры DS, SS и SP. Для моделей SMALL, MEDUIUM, COMPACT, LARGE, HUGE и TPASCAL Турбо Ассемблер устанавливает DS и SS в @data, а SP - в конец стека. Для моделей TINY и TCHUGE директива STARTUPCODE не изменяет сег- ментных регистров.
Директива SUBSTR определяет новую текстовую макрокоманду, которая является подстрокой строки. Она имеет следующий синтак- сис:
имя SUBSTR строка,выражение_позиции[,выражение_размера]
Новая текстовая макрокоманда с именем "имя" состоит из части строки , начинающейся с символа в позиции "выражение_позиции" и длины "выражение_длины". Если вы не указываете "выражение_разме- ра", новая текстовая макрокоманда содержит остаток строки, начи- ная с символа в "выражении_позиции". Турбо Ассемблер рассматрива- ет первый символ строки как позицию 1.
В концепции объектов используется таблица виртуальных мето- дов. Экземпляр этой таблицы существует для любого объекта, содер- жащего виртуальные методы. Структура данных для для любого объек- та, содержащего виртуальные методы, также должна содержать указа- тель на таблицу виртуальных методов этого объекта. Турбо Ассемблер автоматически обеспечивает в структуре данных объекта указатель таблицы виртуальных методов (если это требуется), и вам не нужно задавать его явно с помощью директивы TBLPTR.
Директиву TBLPTR следует использовать в определении структу- ры данных объекта. TBLPTR позволяет вам явно разместить указатель таблицы виртуальных методов там, где вы хотите. Она имеет следую- щий синтаксис:
TBLPTR
Размер указателя, который резервирует TBLPTR, определяется тем, задано в текущей модели USE16 или USE32, и тем, какие моди- фикаторы используются в определении объекта.
Вы можете использовать директиву условного ассемблирования IFxxx для определения блока кода, который включается в объектный файл при удовлетворении определенных условий (таких как определе- ние идентификатора или установка какого-то значения). Приведем синтаксис оператора условного ассемблирования:
IFxxx тело_условия_true EMDIF
или IFxxx тело_условия_true ELSE тело_условия_false ENDIF
где IFxxx представляет следующие директивы:
IF IF1 IF2 IFDEF IFNDEF IFB IFNB IFIDN IFIDNI IFDIF IFDIFI
Каждая директива условного ассемблирования IFxxx задает конкретное условие, при вычислении которого получается истинное (true) или ложное (false) значение. Если условие имеет значение true, то выполняется ассемблирование и помещение в объектный файл блока ассемблируемого кода "тело_условия_true". Если при вычисле- нии условия получается значение false, то Турбо Ассемблер пропус- кает "тело_условия_true" и не включает его в объектный файл. При наличие директивы ELSE, если условие имеет значение false, то ас- семблируется и выводится в объектный файл блок "тело_усло- вия_false". Если условие имеет значение true, то этот блок игно- рируется. Условный блок завершается директивой ENDIF.
Кроме особых случаев директив IF1 и IF2 (которые мы обсудим позднее) два описанных блока кода являются взаимноисключающими: в объектный файл включается либо "тело_условия_true", либо "тело_ условия_false", но не оба блока одновременно. Кроме того, если вы используете форму IFxxx.ELSE.ENDIF, один из блоков будет обя- зательно включаться в объектный файл. Если используется форма IFxxx.ENDIF, то "тело_условия_true" может включаться или не включаться в объектный файл, в зависимости от условия.
При использовании вложенных директив IF и ELSE директива ELSE всегда соответствует ближайшей директиве IF.
В следующем примере test является идентификатором, который управляет включением кода (если идентификатор не определен, то генерируется соответствующий блок кода) Идентификатор color уста- навливается в ненулевое значение, если дисплей цветной, и равен 0, если дисплей монохромный.
Использование директивы VERSION позволяет вам определить, для какой версии Турбо Ассемблера или MASM вы пишете конкретные модули. Это полезно использовать для совместимости (снизу вверх или наоборот) различных версий TASM и MASM. Директива VERSION также переводит вас в режим работы заданной версии.
Директиву VERSION вы можете указывать как в виде параметра командной строки, так и в исходном коде программы.
В исходном коде она имеет следующий синтаксис:
VERSION <идентификатор_версии>
Допускается задавать следующие идентификаторы версии:
M400 MASM 4.0 M500 MASM 5.0 M510 MASM 5.1 M520 MASM 5.2 (Quick ASM) T100 Турбо Ассемблер 1.0 T101 Турбо Ассемблер 1.01 T200 Турбо Ассемблер 2.0 T250 Турбо Ассемблер 2.5 T300 Турбо Ассемблер 3.0
При использовании данной директивы в командной строке ис- пользуется следующий синтаксис:
/U<номер_версии>
Например, если вы хотите ассемблировать программу, написан- ную для MASM 5.0, то можно не изменять исходный код и указать в командной строке параметр /uM510.
Здесь действуют следующие правила:
1. Директива VERSION по умолчанию всегда выбирает режим MASM, поскольку это начальный режим работы как для MASM, так и для Турбо Ассемблера.
2. Директива VERSION ограничивает высокоприоритетные ключе- вые слова теми словами, которые доступны для заданного компилятора и версии, В результате некоторые средства, которые были добавлены в последние версии, будут вам не- доступны.
3. Если в режиме Ideal вы выбираете версию < T300, то дирек- тива VERSION вам недоступна. В этом случае, чтобы исполь- зовать директиву VERSION, вы должны сначала переключиться в режим MASM.
В предыдущих версиях Турбо Ассемблера совместимость с MASM обеспечивалась с помощью таких директив, как MASM51, MOMASM51, QUIRKS, SMART и NOSMART. Вместо этих директив используется теперь директива VERSION. Полное описание ключевых слов, доступных в каждой предыдущей версии Турбо Ассемблера, можно найти в Приложе- нии B.
Для повторения тела макрокоманды до того момента, пока опре- деленное выражение не примет значения 0 (false), вы можете ис- пользовать макродирективу WHILE. Она имеет следующий синтаксис:
WHILE выражение тело_макрокоманды ENDM
Перед каждой итерацией тела макрокоманды Турбо Ассемблер вы- числяет "выражение". Будьте аккуратны и избегайте бесконечных циклов, которые привести к тому, что Турбо Ассемблер исчерпает доступную память или прекратит работу. Приведем пример использо- вания директивы WHILE:
WHILE 1 ;; ничего не делает ENDM
Вы можете использовать директиву EVEN для округления счетчи- ка адреса до следующего четного адреса. Директива EVEN позволяет вам выравнивать код для эффективного доступа к процессорам, ис- пользующим 16-разрядную шину данных. Производительность процессо- ров, использующих 8-разрядную шину данных, директивой EVEN не улучшается.
Директива EVENDATA выполняет выравнивание на четную границу, изменяя счетчика адреса без генерации данных, что полезно исполь- зовать для неинициализированных сегментов. Директивы EVEN и EVENDATA приводят к тому, что если выравнивание текущего сегмента выполнено недостаточно строго, Турбо Ассемблер выводит предупреж- дающее сообщение.
Если когда встречается директива EVEN счетчик адреса имеет нечетное значение, то Турбо Ассемблер помещает в сегмент один байт или инструкцию NOP, чтобы счетчик адреса стал четным. С по- мощью заполнения инструкциями NOP директиву EVEN можно в сегмен- тах кода, не вызывая на этапе работы программы выполнения невер- ных инструкций. Если счетчик адреса уже имеет четное значение, то данная директива не действует.
Аналогично, если счетчик адреса имеет нечетное значение, когда встречается директива EVENDATA, Турбо Ассемблер генерирует неинициализированный байт.
Приведем следующий пример использования директивы EVEN:
EVEN @@A: lodsb xor bl,al ; выравнивание для эффективного доступа loop @@a
Приведем пример использования директивы EVENDATA:
EVENDATA VAR1 DW 0 ; выравнивание для эффективного ; доступа 8086
Директива ERRxxx генерирует при удовлетворении определенных условий сообщения пользователя об ошибке. Она имеет следующий об- щий синтаксис:
ERRxxx [аргументы] [сообщение]
В этом случае директива ERRxxx представляет какую-либо из директив условной генерации сообщения об ошибке (такие как ERRIFB, .ERRB и т.д.).
"Аргументы" представляют аргументы, которые могут потребо- ваться в директиве для вычисления условия. Некоторые директивы требуют выражения, другие требуют символьного выражения, а неко- торые - одно или два текстовых выражений. Некоторые из директив вовсе не требуют аргументов.
Если указано "сообщение", то оно задает необязательное сооб- щение, которое выводится с ошибкой. Сообщение должно быть заклю- чено в кавычки (' или ").
Директивы генерации сообщений об ошибке генерируют пользова- тельское сообщение об ошибке, которое выводится на экран и включается в файл листинга (если он имеется) в месте расположения директивы в исходном коде. Если директива задает сообщение, оно выводится на той же строке непосредственно за ошибкой. Например, директива:
ERRIFNDEF foo "foo не определено!"
если идентификатор foo не определен при обнаружении ошибки, при- ведет к генерации ошибки:
User error: "foo не определено!"
Если вам нужны реальные инструкции с плавающей точкой, то нужно использовать сопроцессор 8087. Если у вас установлен пакет программной эмуляции инструкций с плавающей точкой, то для его использования можно указать директиву EMUL. (Директива EMUL рабо- тает аналогично параметру /e).
Примечание: Директивы EMUL и NOEMUL работают как в ре- жиме MASM, так и в режиме Ideal.
Например:
Finit ; реальные инструкции сопроцессора ; 8087 EMUL Fsave BUF ; эмулируемая инструкция
При использовании сопроцессора 8087 вы можете либо эмулиро- вать инструкции с плавающей точкой с помощью директивы EMUL, либо принудительно использовать инструкции с плавающей точкой с по- мощью директивы NOEMUL. Заметим, что вы можете использовать инс- трукции EMUL и NOEMUL, когда хотите генерировать инструкции с плавающей точкой для одной части файла и эмулируемые инструкции для другой.
Приведем пример использования инструкции NOEMUL:
NOEMUL ; ассемблировать реальные инструкции ; с плавающей точкой finit EMUL ; вернуться к эмуляции
Назад | Содержание | Вперед
В том случае, когда вы хотите вывести в файл листинга вклю- чаемые файлы, вы можете разрешить или запретить эту возможность с помощью директив %INCL и %NOINCL. По умолчанию включаемые файлы обычно включаются в файл листинга. Директива %NOINCL приостанав- ливает вывод в файл листинга всех последующих включаемых файлов, пока он снова не будет разрешен директивой %INCL. Это полезно ис- пользовать при наличии больших включаемых файлов, которые содер- жат, например, много определений EQU, которые никогда не изменя- ются.
Приведем пример:
%INCL INCLUSE DEFS.INC ; содержимое выводится в листинг %NOINCL INCLUSE DEF1.INC ; содержимое не выводится в листинг
Турбо Ассемблер использует двух символьный код, присоединяе- мый к идентификаторам в виде префикса и определяющий, что иденти- фикатор в процедуре имеет локальную область действия. Это префикс локального идентификатора обозначается как @@. Для разрешения идентификаторов, имеющих локальную область действия, можно ис- пользовать директиву LOCALS. Ее синтаксис имеет следующий вид:
LOCALS [префикс_идентификатора]
Необязательное поле "префикс_идентификатора" содержит иден- тификатор (размером в два символа), который Турбо Ассемблер будет использовать в качестве префикса локального идентификатора. Нап- ример:
LOCALS ; по умолчанию подразумевается использование ; в качестве префикса @@ foo proc @@a: jmp @@a ; этот идентификатор @@a относится к ; процедуре FOO foo endp
bar proc @@a: jmp @@a ; этот идентификатор @@a относится к про- ; цедуре BAR bar endp
Если вы хотите запретить идентификаторы с локальной областью действия, можно использовать директиву NOLOCALS. Она имеет следу- ющий синтаксис:
NOLOCALS
Заметим, что вы можете использовать идентификаторы с об- ластью действия в границах блока вне процедур. В этом случае об- ласть действия идентификатора определяется метками, заданными с помощью двоеточия, которые на являются идентификаторами с об- ластью действия в границах блока. Например:
foo: ; начало области действия @@a: ; относится к области действия, начинающейся ; FOO: @@b = 1 ; относится к области действия, начинающейся ; FOO: BAR: ; начало области действия @@a = 2 ; относится к области действия, начинающейся ; BAR:
Турбо Ассемблер обеспечивает директивы, которые могут рабо- тать с текстовыми макрокоманд. Эти директивы доступны в режиме Ideal и для версий M510, M520 и T300 (как задается директивой VERSION).
Строковые аргументы для любой из этих директив могут быть следующими:
- текстовой строкой, заключенной в скобки, например, <abc>;
- именем ранее определенной текстовой макрокоманды;
- выражением с предшествующим символом %, значение которого эквивалентно числовому представлению строки для текущего основания.
В Турбо Ассемблере предусмотрено несколько директив, уста- навливающий счетчик инструкций. Эти директивы описываются в сле- дующем разделе. Заметим, что все эти директивы работают как в ре- жиме MASM, так и в режиме Ideal.
Вы можете использовать директивы условного ассемблирования ELSEIFxxx как сокращенную форму, когда требуется использовать несколько директив IF. Директива ELSEIFxxx представляет собой эк- вивалент директивы ELSE, за которой следует вложенная директива IFxxx, но дает более компактный код. Например:
. . . IF mode EQ 0 ; кода для mode = 0 ELSEIF mode LT 5 ; код для coe = 14 ELSE ; код для mode = 5. ENDIF . . .
сравните его со следующим:
. . . IF mode EQ 0 ; кода для mode = 0 ELSE IF mode LT 5 ; код для coe = 14 ELSE ; код для mode = 5. ENDIF ENDIF . . .
Вне оператора IFxxx директиву ELSEIFxxx использовать нельзя.
Когда в исходном коде у вас содержатся блоки условного ассемблирования, может оказаться желательным включение в листинг всей информации. Вывод блоков условного ассемблирования может по- мочь в тех случаях, когда вы хотите точно видеть поведение исход- ного кода. В Турбо Ассемблере предусмотрены следующие директивы вывода блоков условного ассемблирования:
- .LFCOND ; только для режима MASM
- .SFCOND ; только для режима MASM
- ,TFCOND ; только для режима MASM
- %CONDS
- %NOCONDS
Обычно Турбо Ассемблер не включает в листинг блоки условного ассемблирования.
Директива %CONDS выводит в файл листинга все операторы ус- ловного блока. При этом в файл листинга выводятся также все блоки с условием false. Директива .LFCOND работает аналогично директиве .LFCOND. Директива %NOCONDS предотвращает вывода в файл листинга блоков условного ассемблирования с условием false. Директива .SFCONDS работает аналогично директиве %NOCOND. Если вы хотите переключить режим вывода блоков условного ассемблирования, ис- пользуйте директиву .TFCOND.
Первая директива .TFCOND, которую обнаруживает Турбо Ассемб- лер, разрешает вывод в листинг всех блоков условного ассемблиро- вания. Если вы используете параметр командной строки /X, блоки условного ассемблирования будут сначала выводиться в листинг, а первая директива .TFCOND запретит их вывод. При каждом обнаруже- нии в исходном файле директивы .TFCOND состояние вывода блоков условного ассемблирования изменяется на обратное.
Для указания любой из этих директив поместите директиву на отдельной строке исходного кода. Она будут влиять на непосредс- твенно следующие за данной директивой блоки условного ассемблиро- вания.
В таблице идентификаторов листинга ссылок обычно выводится большой объем информации о метках, группах и сегментах, но там не сообщается, где определены сегменты, группы и метки и где они ис- пользуются. Информация, выводимая в таблице перекрестных ссылок, позволяет вам легко находить метки и следить за ходом выполнения программы при ее отладке.
Существует несколько способов разрешения включения информа- ции о перекрестных ссылках в файл листинга. Для получения инфор- мации о перекрестных ссылках для всего файла вы можете использо- вать параметр командной строки /c (подробности можно найти в Главе 2), либо включить в исходный код директивы, позволяющие вам разрешать и запрещать вывод перекрестных ссылок для отдельных частей исходного кода. Это следующие директивы:
- .CREF ; только для режима MASM - .XCREF ; только для режима MASM - %CREF - %NOCREF - %CREFALL - %CREFREF - %CREFUREF
Директивы %CREF и .CREF позволяют вам собрать информацию о перекрестных ссылках для всех идентификаторах в исходном файле, начиная с данной точки. Директивы %CREF и .CREF отменяют действие директив %NOCREF или .XCREF, которые запрещают сбор информации о перекрестных ссылках.
Директивы %CREF и .CREF имеют следующий синтаксис:
%CREF или .CREF
Директивы %NOCREF и .XCREF имеют синтаксис:
%NOCREF [идентификатор, .] или .XCREF [идентификатор, .]
Если вы используете директивы %NOCREF и .XCREF без указания идентификатора, то вывод перекрестных ссылок запрещается пол- ностью. Если вы указываете одно или более имен идентификаторов, то вывод перекрестных ссылок запрещается только для данных иден- тификаторов.
Директива %CREFALL выводит в листинг перекрестные ссылки для всех идентификаторов. Директива %CREFALL изменяет действие преды- дущей директивы %CREFREF (запрещающей вывод в таблицу перекрест- ных ссылок тех идентификаторов, на которые ссылки отсутствуют) на обратное. После указания директивы %CREFALL все встречающиеся да- лее в исходном файле идентификаторы будут включаться в листинг перекрестных ссылок. Турбо Ассемблер использует это режим по умолчанию а начале ассемблирования исходного файла.
Директивы %CREFALL, %CREFREF и %CREFUREF имеют следующий синтаксис:
%CREFALL
%CREFREF
%CREFUREF
Обычно макрорасширения включаются в файлы листинга. Наличие такой информации в файле листинга может оказаться очень полезной, когда вы хотите видеть, что делается в исходном коде. В Турбо Ас- семблере предусмотрено несколько директив, которые позволяют включать и выключать данное средство. Это следующие директивы:
- .LALL ; только для режима MASM - .SALL ; только для режима MASM - .XALL ; только для режима MASM - %MACS - %NOMACS
Директива %MACS разрешает листинг всех макрорасширений. Тоже самое делает директива .LALL, но она работает только в режиме MASM. Вы можете использовать эти директивы для включения макро- расширений в файл листинга.
Директива %MACS имеет следующий синтаксис:
%MACS
Директиву .LALL вы можете задать следующим образом:
.LALL
Если вы хотите подавить вывод всех операторов макрорасшире- ния, используйте директивы %NOMACS или .SALL. Заметим, что эти директивы можно использовать для выключения вывода макрорасшире- ния в файл листинга.
Директива %NOMACS имеет следующий синтаксис:
%NOMACS
Директива .SALL задается следующим образом:
.SALL
Доступная в режиме MASM директива .XALL позволяет вам выво- дить в листинг только те макрорасширения, которые генерируют код или данные. Она имеет следующий синтаксис:
.XALL
Есть множество причин, по которым вам следует использовать режим Ideal Турбо Ассемблера. Если вы изучаете язык Ассемблера, то сможете легко строить для получения желаемого эффекта выраже- ния и операторы режима Ideal. Вам не придется ходить вокруг да около и пробовать различные варианты, пока вы не используете инс- трукцию, которая делает именно то, что вы хотите. Если у вас име- ется опыт программирования на Ассемблере, то вы можете использо- вать средства режима Ideal Турбо Ассемблера для разработки сложных программ, использующих расширения языка, такие, например, как вложенные структуры и объединения.
В результате более четкого синтаксиса режим Ideal Турбо Ас- семблера позволяет ассемблировать файлы на 30% быстрее, чем в ре- жиме MASM. Чем больше объем ваших программ и программных комплек- сов, тем больше времени вы сэкономите при ассемблировании, перейдя в режим Ideal.
Строгие правила проверки типов, налагаемые режимом Ideal, позволяют Турбо Ассемблеру выявлять ошибки, которые в противном случае вы обнаружили бы только при отладке вашей программы или ее выполнении. Это аналогично тому, каким образом компиляторы языков высокого уровня оказывают вам помощь, отмечая сомнительные конс- трукции и несоответствие размеров данных.
Хотя в режиме Ideal Турбо Ассемблера в некоторых выражениях используется другой синтаксис, вы, тем не менее, можете писать программы, которые будут одинаково хорошо ассемблироваться как в режиме MASM, так и в режиме Ideal. Вы можете также в одном и том же исходном файле переключаться из режима MASM в режим Ideal и обратно так часто, насколько это необходимо. Это особенно полезно при экспериментировании со средствами режима Ideal, или при пре- образовании имеющихся программ, написанных в синтаксисе MASM. Вы можете переключиться в режим Ideal в новых частях программы, до- бавляемых к имеющемуся исходному коду. При этом в остальных час- тях программы сохранится полная совместимость с MASM.
Большинство рассматривают язык Турбо Ассемблера, как язык низкого уровня. Однако Турбо Ассемблер обеспечивает многие средс- тва языка высокого уровня (такие как абстрактные типы данных и простой интерфейс с другими языками). Дополнение Ассемблера объ- ектно-ориентированными структурами данных дает ему возможность создавать объектно-ориентированные программы так же легко, как это делается на языках высокого уровня, с сохранением скорости и гибкости языка Ассемблера.
Для эффективной индексации массивов Турбо Ассемблер обеспе- чивает специальную операцию непосредственного умножения. Инструк- ция FASTIMUL решает типичную проблему, возникающую при создании массива структур. Для процессора 8086 инструкция непосредственно- го умножения недоступна. Даже на более развитых процессорах умно- жение с использованием сдвигов и сложений выполняется в некоторых обстоятельствах существенно быстрее, чем стандартная непосредс- твенная инструкция IMUL. На основе текущего назначения процессора инструкция Турбо Ассемблера FASTIMUL выбирает между наиболее эф- фективной доступной последовательностью сдвигов и сложений и не- посредственной операцией IMUL текущего процессора (если она име- ется). Инструкция FASTIMUL имеет следующий синтаксис::
FASTIMUL регистр_приемник, регистр/память_источник, значение
Данная инструкция очень напоминает тернарную операцию IMUL, доступную на процессорах 80186, 80286 и 80386. Регистр-приемник - это регистр размером в слово (или двойное слово при работе на процессора 80386). "Регистр/память_источник" - это регистр или адрес в памяти, который должен соответствовать размеру приемника. "Значение" - это фиксированная константа со знаком (множитель).
Инструкция FASTIMUL использует для выполнения своей функции комбинацию инструкций IMUL, MOV, NEG, SHL, ADD и SUB. При этом содержимое регистра-источника (или адреса памяти) теряется. Флаги процессора не изменяются.
При создании экземпляра объекта требуется инициализировать указатель таблицы виртуальных методом объекта (если он имеется), чтобы он указывал на корректную таблицу виртуальных методов. Ин- струкция TBLINIT позволяет вам сделать это автоматически. Эта ин- струкция имеет следующий синтаксис:
TBLINIT указатель_экземпляра_объекта
Поле "указатель_экземпляра__объекта" представляет собой ад- рес объекта, указатель таблицы виртуальных методов которого нужно инициализировать. Инструкция TBLINIT предполагает, что экземпляр объекта должен иметь тип текущего объекта (другими словами, не- посредственно предшествующее определение объекта определяет объ- ектный тип, который инициализирует TBLINIT). Например:
TBLINIT DS:ST
инициализирует указатель таблицы виртуальных методов объекта DS: SI (если она имеется).
Назад | Содержание | Вперед
Инструкции ENTER и LEAVE используются для удаления из стека кадра процедуры. В зависимости от того, является текущий сегмент кода 16-битовым или 32-битовым, стандартные инструкции ENTER и LEAVE будут модифицировать либо регистры BP и SP, либо EBP и ESP. Если сегмент кода - это 32-битовый сегмент, а сегмент стека - 16- битовый, то данные инструкции могут оказаться неподходящими.
В Турбо Ассемблере предусмотрены 4 дополнительные инструк- ции, которые всегда выбирают конкретный размер стека, независимо от размера сегмента кода. Инструкции ENTERW и LEAVEW всегда выби- рают в качестве регистров кадра стека BP и SP, a ENTERD и LEAVED - регистры EBP и ESP.
Турбо Ассемблер может генерировать специальные последова- тельности инструкций для задания значений и извлечения значений из битовых полей, заданных с помощью оператора RECORD. Это позво- ляет вам писать код, независимый от фактического расположения по- ля в записи. При использовании их в сочетании с оператором ENUM, записи на языке ассемблера могут получить очень высокий уровень модульности. Список данных инструкций приведен в следующей табли- це:
Инструкции для установки и извлечения значения Таблица 13.5 ----------------T-----------------------------------------------¬ ¦ Инструкция ¦ Функция ¦ +---------------+-----------------------------------------------+ ¦ SETFIELD ¦ Устанавливает значение поля записи. ¦ ¦ ¦ ¦ ¦ GETFIELD ¦ Извлекает значение из поля записи. ¦ L---------------+------------------------------------------------
Инструкция SETFIELD
Инструкция SETFIELD генерирует код, устанавливающий значение поля записи. Она имеет синтаксис:
SETFIELD имя_поля регистр/память_приемник, регистр_источник
где "имя_поля" - имя поля записи, "регистр/память_приемник" для SETFIELD представляет собой регистр или адрес в памяти типа BYTE или WORD (DWORD для процессора 80386). "Регистр_источник" должен быть регистром того же или меньшего размера. Если источник мень- ше, чем приемник, то регистр-источник должен быть младшей частью другого регистра, имеющего тот же размер, что и приемник. Этот полный регистр называется рабочим регистром. Используйте данный регистр для сдвига значения в регистре-источнике, благодаря чему оно выравнивается по приемнику. Например:
FOO RECORD R0:1,R1:4,R2:3,R3:1 . . . SETFIELD F1 AX,BL ; рабочим регистром является BX SETFIELD F1 AX,BH ; недопустимо!
SETFIELD сдвигает регистр-источник, чтобы эффективно выров- нять его на поле приемника, выполняет операцию OR и помещает ре- зультат в регистр-приемник.
Примечание: Операция SETFIELD уничтожает все содержи- мое рабочего регистра.
Чтобы выполнить свою функцию, инструкция SETFIELD генерирует эффективную и расширенную последовательность инструкций XOR, XCHG, ROL, ROR, OR и MOVZX.
Операция SETFIELD не пытается очистить целевое поле перед выполнением над его значением операции OR. Если это необходимо, вы можете очистить поле явным образом, используя инструкцию MASKFLAG.
Часто, чтобы улучшить эффективность и уменьшить размер кода, можно упростить инструкции работы с флагами. Например, если единственным желаемым результатом является установка конкретного бита в AX, а флаги процессора, на которые влияет данная инструк- ция, значение не имеют, инструкцию:
OR ax,1000h
можно упростить до инструкции:
OR, ah,10h
Турбо Ассемблер обеспечивает 4 дополнительных инструкции, которые обеспечивают эти функциональные возможности. Они показаны в следующей таблице:
Эффективные инструкции работы с флагами Таблица 13.4 ------------------T----------------T-----------------------------¬ ¦ Инструкция ¦ Функция ¦Соответствует инструкции ¦ +-----------------+----------------+-----------------------------+ ¦ SETFLAG ¦ Установка бит ¦ OR ¦ ¦ ¦ (бита) флага. ¦ ¦ ¦ ¦ ¦ ¦ ¦ MASKFLAG ¦ Размаскирование¦ AND ¦ ¦ ¦ бит (бита) ¦ ¦ ¦ ¦ флага. ¦ ¦ ¦ ¦ ¦ ¦ ¦ TESTFLAG ¦ Проверка бит ¦ TEST ¦ ¦ ¦ (бита) флага. ¦ ¦ ¦ ¦ ¦ ¦ ¦ FLIPFLAG ¦ Дополнение бит ¦ XOR ¦ ¦ ¦ (бита) флага. ¦ ¦ L-----------------+----------------+------------------------------
Эти инструкции можно использовать для улучшения модульности записей, например:
FOO RECORD R0:1,R1:4,R2:3,R3:1 . . . TESTFLAG AX,R0
В данном примере TESTFLAG будет генерировать наиболее эффек- тивные инструкции, независимо от того, где в записи находится R0.
Стандартная инструкция RET генерирует код, который соответс- твующим образом завершает текущую процедуру. Это включает в себя генерацию кода завершения процедуры, которая использует интер- фейсные соглашения языка высокого уровня. Даже если для процедуры используются соглашения NOLANGUAGE, инструкция RET в зависимости от описания процедуры (описана она как NEAR или FAR) будет гене- рировать различный код. Для процедуры NEAR Турбо Ассемблер гене- рирует дальнюю инструкцию возврата. Для процедуры FAR Турбо Ас- семблер генерирует ближнюю инструкцию возврата. (Вне процедуры всегда генерируется ближний возврат.)
Турбо Ассемблер включает в себя дополнительные инструкции, которые позволяют задавать генерацию нужных инструкций возврата (без кода завершения). Они перечислены в следующей таблице:
Инструкции возврата Таблица 13.2 ------------------T---------------------------------------------¬ ¦ Инструкция ¦ Функция ¦ +-----------------+---------------------------------------------+ ¦ RETN ¦ Всегда генерирует ближний возврат. ¦ ¦ ¦ ¦ ¦ RETNF ¦ Всегда генерирует дальний возврат. ¦ ¦ ¦ ¦ ¦ RETCODE ¦ Генерирует возврат, тип которого соответ- ¦ ¦ ¦ ствует текущей выбранной модели. Для модели ¦ ¦ ¦ TINY, SMALL, COMPACT и TPASCAL генерируется ¦ ¦ ¦ ближний возврат. Для модели MEDIUM, LARGE, ¦ ¦ ¦ HUGE и TCHUGE - дальний возврат. ¦ L-----------------+----------------------------------------------
В режиме Ideal любой элемент данных в сегменте, являющемся частью группы, рассматривается строго как элемент группы, а не сегмента. В Турбо Ассемблере для распознавания элемента данных, как элемента сегмента, нужно использовать явное переопределение сегмента.
В режиме MASM это интерпретируется по-другому. Иногда иден- тификаторы считается частью сегмента, а не частью группы. В част- ности, в режиме MASM идентификатор интерпретируется, как часть сегмента, когда он используется, как указатель на выделенные дан- ные. Это может вызвать путаницу, так как когда вы непосредственно обращаетесь к данным без операции OFFSET, MASM некорректно гене- рирует ссылку на сегмент вместо ссылки на группу.
Пример поможет нам пояснить, как легко можно нажить неприят- ности из-за специфики адресации в MASM. Рассмотрим следующую не- полную программу MASM, в которой описываются три сегмента данных:
dseg1 SEGMENT para public 'data'
v1 db 0 dseg1 ENDS
dseg2 SEGMENT para public 'data' v2 db 0 dseg2 ENDS
dseg3 SEGMENT para public 'data' v3 db 0 dseg3 ENDS
DGROUP GROUP dseg1,dseg2,dseg3 cseg SEGMENT para public 'code'
ASSUME cs:cseg,ds:DGROUP
start: mov ax,OFFSET v1 mov bx,OFFSET v2 mov cx,OFFSET v3 cseg ENDS END start
Три сегмента dseg1, dseg2 и dseg3 группируются под одним именем DGROUP. В результате все переменные отдельных сегментов хранятся в памяти вместе. В исходном тексте программы в каждом из отдельных сегментов описывается байтовая переменная (метки v1, v2 и v3).
В коде данной программы MASM в регистры AX, BX и CX загружа- ются смещения адресов этих переменных. В соответствии с предшест- вующей директивой ASSUME и из-за того, что сегменты данных сгруп- пированы вместе, вы можете подумать, что MASM будет вычислять смещения переменных относительно всей группы, в которой перемен- ные очевидно хранятся в памяти.
Но произойдет совсем не это! Вопреки вашим намерениям MASM вычисляет смещения переменных относительно отдельных сегментов dseg1, dseg2 и dseg3. Он делает это несмотря на то, что все три сегмента данных сгруппированы в памяти в один сегмент данных, ад- ресуемый через регистр DS. Бессмысленно определять смещения пере- менных относительно отдельных сегментов в тексте программы, ког- да эти сегменты скомбинированы в памяти в один сегмент. Единственный способ ссылки на такие переменные состоит в ссылке на их смещения относительно всей группы.
Когда получает управление ваша подпрограмма на Турбо Ассемб- лере, вершина стека будет содержать адрес возврата (два или четы- ре слова, в зависимости от того, является ли подпрограмма ближней или дальней), а далее будут находится передаваемые параметры.
Примечание: При вычислении адресов параметров нужно принимать во внимание регистры, такие как BP, содержимое которых также может быть занесено в стек.)
Существует три основных метода доступа к параметрам, переда- ваемых Турбо Паскалем вашей подпрограмме на Турбо Ассемблере. Вы можете:
- использовать для адресации к стеку регистр BP;
- для получения параметров использовать другой базовый или индексный регистр;
- извлечь из стека адрес возврата, а затем параметры.
Первый и второй методы более сложны, и мы расскажем о них в следующих двух разделах. Третий метод предусматривает извлечение из стека и сохранение адреса возврата, а затем извлечения пара- метров и записи их в регистры. Лучше всего этот метод работает, когда ваша подпрограмма не требует пространства для локальных пе- ременных.
(Недопустимо использование одинаковых имен для формальных параметров)
В директиве MACRO определено несколько формальных параметров с одинаковыми именами. Например:
XYZ MACRO A,A ; ошибка: дублируются имена ; формальных параметров DB A ENDM
Все формальные параметры макроопределения должны иметь раз- личные имена.
(ELSE или ENDIF без IF)
Для директивы ELSE или ENDIF нет парной директивы IF, обоз- начающей начало условно ассемблируемого блока. Например:
BUF DB 10 DUP(?) ENDIF ; ошибка: нет парной директивы IFxxx
(Ошибка при записи в файл листинга)
Возможно при записи файла листинга на диск было исчерпано место на этом диске.
(Ошибка при записи в объектный файл)
Возможно при записи объектного файла на диск было исчерпано место на этом диске.
(Требуется ключевое слово METHOD)
В расширенном структурном операторе для определения объектов после порождающего объекта требуется ключевое слово METHOD.
(Требуется указать смещение или указатель)
В качестве операнда выражения указано неверное значение вместо ожидаемого смещения внутри специфицированного сегмента. Например:
CODE SEGMENT mov ax,SEG CODE ; ошибка: СODE - это сегмент, ; а не адрес внутри сегмента CODE ENDS
(Требуется указать величину смещения)
В качестве операнда выражения указано неверное значение вместо ожидаемого смещения внутри сегмента. Например:
CODE SEGMENT mov ax,LOW CODE CODE ENDS
(Операнд должен быть указателем)
Операндом текущей команды должен быть адрес памяти. Напри- мер:
LES di,4 ; неверно, т.к. 4 - константа
(Требуется имя поля записи)
Вы использовали инструкцию SETFIELD или GETFIELD без после- дующего имени поля.
(Требуется идентификатор регистра)
В части USES оператору CALL.METHOD требуются имена регист- ров.
(Операнд должен быть константой)
Операндом текущей команды должна быть константа. Например:
BB DB 4 rol ax,BB ; ошибка: вторым операндом операции ROL ; должна быть константа
(Должно быть указано имя сегмента или группы)
В операторе вместо имени сегмента или группы указано имя, которое таковым не является. Например:
DATA SEGMENT ASSUME ds:F00 ; ошибка: F00 не является именем ; сегмента или группы F00 DW 0 DATA ENDS