Жанр: Учеба
Ассемблер и программирование для IBM PC
... MAIN ENDP
011F CSEG ENDS
END BEGIN
__________________________________________________________________________
Рис.20.4. Использование директивы LOCAL.
ИСПОЛЬЗОВАНИЕ БИБЛИОТЕК МАКРООПРЕДЕЛЕНИЙ
________________________________________________________________
Определение таких макрокоманд, как INIT1 и INIT2 и одноразовое их
использование в программе кажется бессмысленным. Лучшим подходом здесь
является каталогизация собственных макрокоманд в библиотеке на магнитном
диске, используя любое описательное имя, например, MACRO.LIB:
INIT MACRO CSNAME,DSNAME,SSNAME
ENDM
PROMPT MACRO MESSGE
ENDM
Теперь для использования любой из каталогизированных макрокоманд вместо
MACRO определения в начале программы следует применять директиву INCLUDE:
INCLUDE C:MACRO.LIB
INIT CSEG,DATA,STACK
В этом случае ассемблер обращается к файлу MACRO.LIB (в нашем примере) на
дисководе C и включает в программу оба макроопределения INIT и PROMPT.
Хотя в нашем примере требуется только INIT. Ассемблерный листинг будет
содержать копию макроопределения, отмеченного символом C в 30 колонке
LST-файла. Следом за макрокомандой идет ее расширение с объектным кодом и
с символом плюс (+) в 31 колонке.
Так как транслятор с ассемблера является двухпроходовым, то для
обеспечения обработки директивы INCLUDE только в первом проходе (а не в
обоих) можно использовать следующую конструкцию:
IF1
INCLUDE C:MACRO.LIB
ENDIF
IF1 и ENDIF являются условными директивами. Директива IF1 указывает
ассемблеру на необходимость доступа к библиотеке только в первом проходе
трансляции. Директива ENDIF завершает IF-логику. Таким образом, копия
макроопределений не появится в листинге - будет сэкономлено и время и
память.
Программа на рис.20.5 содержит рассмотренные выше директивы IF1,
INCLUDE и ENDIF, хотя в LST-файл ассемблер выводит только директиву ENDIF.
Обе макрокоманды в кодовом сегменте INIT и PROMPT закаталогизированы в
файле MACRO.LIB, т.е. просто записаны друг за другом на дисковый файл по
имени MACRO.LIB с помощью текстового редактора.
Расположение директивы INCLUDE не критично, но она должна появиться
ранее любой макрокоманды из включаемой библиотеки.
__________________________________________________________________________
TITLE MACRO5 (EXE) Проверка директивы INCLUDE
EDIF
; -----------------------------------------------
0000 STACK SEGMENT PARA STACK 'Stack'
0000 20 [????] DW 32 DUP(?)
0040 STACK ENDS
; -----------------------------------------------
0000 DATA SEGMENT PARA 'Data'
0000 54 65 73 74 20 6F MESSGE DB 'Test of macro','$'
66 20 6D 61 63 72
6F 24
000E DATA ENDS
; -----------------------------------------------
0000 CSEG SEGMENT PARA 'Code'
0000 BEGIN PROC FAR
INIT CSEG,DATA,STACK
0000 1E + PUSH DS
0001 3B C0 + SUB AX,AX
0003 50 + PUSH AX
0004 B8 ---- R + MOV AX,DATA
0007 8E D8 + MOV DS,AX
0009 8E C0 + MOV ES,AX
PROMPT MESSGE
000B B4 09 + MOV AH,09 ;Вывод на экран
000D 8D 16 0000 R + LEA DX,MESSGE
0011 CD 21 + INT 21H
0013 CB RET
0014 BEGIN ENDP
0014 CSEG ENDS
END BEGIN
__________________________________________________________________________
Рис.20.5. Использование библиотеки макроопределений.
Директива очистки
-------------------
Директива INCLUDE указывает ассемблеру на включение всех
макроопределений из специфицированной библиотеки. Например, библиотека
содержит макросы INIT, PROMPT и DIVIDE, хотя программе требуется только
INIT. Директива PURGE позволяет "удалить" нежелательные макросы PROMPT и
DIVIDE в текущем ассемблировании:
IF1
INCLUDE MACRO.LIB ;Включить всю библиотеку
ENDIF
PURGE PROMRT,DIYIDE ;Удалить ненужные макросы
INIT CSEG,DATA,STACK ;Использование оставшейся макрокоманды
Директива PURGE действует только в процессе ассемблирования и не
оказывает никакого влияния на макрокоманды, находящиеся в библиотеке.
КОНКАТЕНАЦИЯ (&)
________________________________________________________________
Символ амперсанд (&) указывает ассемблеру на сцепление (конкатенацию)
текста или символов. Следующая макрокоманда MOVE генерирует команду MOVSB
или MOVSW:
MOVE MACRO TAG
REP MOVS&TAG
ENDM
Теперь можно кодировать макрокоманду в виде MOVE B или MOVE W. В
результате макрорасширения ассемблер сцепит параметр с командой MOVS и
получит REP MOVSB или REP MOVSW. Данный пример весьма тривиален и служит
лишь для иллюстрации.
ДИРЕКТИВЫ ПОВТОРЕНИЯ: REPT, IRP, IRPC
________________________________________________________________
Директивы повторения заставляют ассемблер повторить блок операторов,
завершаемых директивой ENDM. Эти директивы не обязательно должны находится
в макроопределении, но если они там находятся, то одна директива ENDM
требуется для завершения повторяющегося блока, а вторая ENDM - для
завершения макроопределения.
REPT: Повторение
------------------
Операция REPT приводит к повторению блока операторов до директивы
ENDM в соответствии с числом повторений, указанным в выражении:
REPT выражение
В следующем примере происходит начальная инициализация значения N=0 и
затем повторяется генерация DB N пять раз:
N = 0
REPT 5
N = N + 1
DB N
ENDM
В результате будут сгенерированы пять операторов DB от DB 1 до DB 5.
Директива REPT может использоваться таким образом для определения таблицы
или части таблицы. Другим примером может служить генерация пяти команд
MOVSB, что эквивалентно REP MOVSB при содержимом CX равном 05:
REPT 5
MOVSB
ENDM
IRP: Неопределенное повторение
--------------------------------
Операция IRP приводит к повторению блока команд до директивы ENDM.
Основной формат:
IRP dummy,"arguments"
Аргументы, содержащиеся в угловых скобках, представляют собой любое число
правильных символов, строк, числовых или арифметических констант.
Ассемблер генерирует блок кода для каждого аргумента. В следующем примере
ассемблер генерирует DB 3, DB 9, DB 17, DB 25 и DB 28:
IRP N,"3, 9, 17, 25, 28"
DB N
ENDM
IRPC: Неопределенное повторение символа
-----------------------------------------
Операция IRPC приводит к повторению блока операторов до директивы
ENDM. Основной формат:
IRPC dummy,string
Ассемблер генерирует блок кода для каждого символа в строке "string". В
следующем примере ассемблер генерирует DW 3, DW 4 ... DW 8:
IRPC N,345678
DW N
ENDM
УСЛОВНЫЕ ДИРЕКТИВЫ
________________________________________________________________
Ассемблер поддерживает ряд условных директив. Ранее нам уже
приходилось использовать директиву IF1 для включения библиотеки только в
первом проходе ассемблирования. Условные директивы наиболее полезны внутри
макроопределений, но не ограничены только этим применением. Каждая
директива IF должна иметь спаренную с ней директиву ENDIF для завершения
IF-логики и возможную директиву ELSE для альтернативного действия:
IFxx (условие)
. __________
. Условный|
ELSE (не обязательное действие) |
. блок |
. __________|
ENDIF (конец IF-логики)
Отсутствие директивы ENDIF вызывает сообщение об ошибке:
"Undeterminated conditional" (незавершенный условный блок). Если
проверяемое условие истинно, то ассемблер выполняет условный блок до
директивы ELSE или при отсутствии ELSE - до директивы ENDIF. Если условие
ложно, то ассемблер выполняет условный блок после директивы ELSE, а при
отсутствии ELSE вообще обходит условный блок.
Ниже перечислены различные условные директивы:
IF выражение Если выражение не равно нулю, ассемблер
обрабатывает операторы в условном блоке.
IFE выражение Если выражение равно нулю, ассемблер обрабатывает
операторы в условном блоке.
IF1 (нет выражения) Если осуществляется первый проход ассемблирования
то обрабатываются операторы в условном блоке.
IF2 (нет выражения) Если осуществляется второй проход операторы
ассемблирования, то обрабатываются в условном
блоке.
IFDEF идентификатор Если идентификатор определен в программе или
объявлен как EXTRN, то ассемблер обрабатывает
операторы в условном блоке.
IFNDEF идентификатор Если идентификатор не определен в программе или
не объявлен как EXTRN, то ассемблер обрабатывает
операторы в условном блоке.
IFB "аргумент" Если аргументом является пробел, ассемблер
обрабатывает операторы в условном блоке. Аргумент
должен быть в угловых скобках.
IFNB "аргумент" Если аргументом является не пробел, то ассемблер
обрабатывает операторы в условном блоке. Аргумент
должен быть в угловых скобках.
IFIDN "арг-1","арг-2" Если строка первого аргумента идентична строке
второго аргумента, то ассемблер обрабатывает
операторы в условном блоке. Аргументы должны быть
в угловых скобках.
IFDIF"арг-1","арг-2" Если строка первого аргумента отличается от
строки второго аргумента, то ассемблер
обрабатывает операторы в условном блоке.
Аргументы должны быть в угловых скобках.
Ниже приведен простой пример директивы IFNB (если не пробел). Для DOS
INT 21H все запросы требуют занесения номера функции в регистр AH, в то
время как лишь некоторые из них используют значение в регистре DX.
Следующее макроопределение учитывает эту особенность:
DOS21 MACRO DOSFUNC,DXADDRES
MOV AN,DOSFUNC
IFNB "DXADDRES"
MOV DX,OFFSET DXADDRES
ENDIF
INT 21H
ENDM
Использование DOS21 для простого ввода с клавиатуры требует установки
значения 01 в регистр AH:
DOS21 01
Ассемблер генерирует в результате команды MOV AH,01 и INT 21H. Для ввода
символьной строки требуется занести в регистр AH значение 0AH, а в регистр
DX - адрес области ввода:
DOS21 0AH,IPFIELD
Ассемблер генерирует в результате обе команды MOV и INT 21H.
ДИРЕКТИВА ВЫХОДА ИЗ МАКРОСА EXITM.
________________________________________________________________
Макроопределение может содержать условные директивы, которые
проверяют важные условия. Если условие истинно, то ассемблер должен
прекратить дальнейшее макрорасширение. Для этой цели служит директива
EXITM:
IFxx [условие]
. (неправильное условие)
EXITM
ENDIF
Как только ассемблер попадает в процессе генерации макрорасширения на
директиву EXITM, дальнейшее расширение прекращается и обработка
продолжается после директивы ENDM. Можно использовать EXITM для
прекращения повторений по директивам REPT, IRP и IRPC даже если они
находятся внутри макроопределения.
МАКРОКОМАНДЫ, ИСПОЛЬЗУЮЩИЕ IF И IFNDEF УСЛОВИЯ
________________________________________________________________
Программа на рис.20.6 содержит макроопределение DIVIDE, которая
генерирует подпрограмму для выполнения деления вычитанием. Макрокоманда
должна кодироваться с параметрами в следующей последовательности: делимое,
делитель, частное. Макрокоманда содержит директиву IFNDEF для проверки
наличия параметров. Для любого неопределенного элемента макрокоманда
увеличивает счетчик CNTR. Этот счетчик может иметь любое корректное имя и
предназначен для временного использования в макроопределении. После
проверки всех трех параметров, макрокоманда проверяет CNTR:
IF CNTR
;Макрорасширение прекращено
EXITM
Если счетчик CNTR содержит ненулевое значение, то ассемблер
генерирует комментарий и прекращает по директиве EXITM дальнейшее
макрорасширение. Заметим, что начальная команда устанавливает в счетчике
CNTR нулевое значение и, кроме того, блоки IFNDEF могут устанавливать в
CNTR единичное значение, а не увеличивать его на 1.
Если ассемблер успешно проходит все проверки, то он генерирует
макрорасширение. В кодовом сегменте первая макрокоманда DIVIDE содержит
правильные делимое и частное и, поэтому генерирует только комментарии.
Один из способов улучшения рассматриваемой макрокоманды - обеспечить
проверку на ненулевой делитель и на одинаковый знак делимого и делителя;
для этих целей лучше использовать коды ассемблера, чем условные директивы.
__________________________________________________________________________
TITLE MACRO6 (COM) Проверка директ. IF и IFNDEF
; -----------------------------------------------
DIVIDE MACRO DIVIDEND,DIVISOR,QUOTIENT
LOCAL COMP
LOCAL OUT
CNTR = 0
; AX-делимое, BX-делитель, CX-частное
IFNDEF DIVIDEND
; Делитель не определен
CNTR = CNTR +1
ENDIF
IFNDEF DIVISOR
; Делимое не определено
CNTR = CNTR +1
ENDIF
IFNDEF QUOTIENT
; Частное не определено
CNTR = CNTR +1
ENDIF
IF CNTR
; Макрорасширение отменено
EXITM
ENDIF
MOV AX,DIVIDEND ;Загрузка делимого
MOV BX,DIVISOR ;Загрузка делителя
SUB CX,CX ;Регистр для частного
COMP:
CMP AX,BX ;Делимое " делителя?
JB OUT ; да - выйти
SUB AX,BX ;Делимое - делитель
INC CX ;Частное + 1
JMP COMP
OUT:
MOV QUOTIENT,CX ;Запись результата
ENDM
; -----------------------------------------------
0000 CSEG SEGMENT PARA 'Code'
ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG
0100 ORG 100H
0100 EB 06 BEGIN: JMP SHORT MAIN
; -----------------------------------------------
0102 0096 DIVDND DW 150
0104 001B DIVSOR DW 27
0106 ???? QUOTNT DW ?
; -----------------------------------------------
0108 MAIN PROC NEAR
.LALL
DIVIDE DIVDND,DIVSOR,QUOTNT
= 0000 + CNTR = 0
+ ; AX-делимое, BX-делитель, CX-частное
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDIF
0108 A1 0102 R + MOV AX,DIVDND ;Загрузка делимого
0108 8B 1E 0104 R + MOV BX,DIVSOR ;Загрузка делителя
010F 2B C9 + SUB CX,CX ;Регистр для частного
0111 + ??0000:
0111 3B C3 + CMP AX,BX ;Делимое " делителя?
0113 72 05 + JB ??0001 ; да - выйти
0115 2B C3 + SUB AX,BX ;Делимое - делитель
0117 41 + INC CX
0118 EB F7 + JMP ??0000
011A + ??0001:
011A 89 0E 0106 R + MOV QUOTNT,CX ;Запись результата
DIVIDE DIDND,DIVSOR,QUOT
= 0000 + CNTR = 0
+ ; AX-делимое, BX-делитель, CX-частное
+ IFNDEF DIDND
+ ; Делитель не определен
= 0001 + CNTR = CNTR +1
+ ENDIF
+ ENDIF
+ IFNDEF QUOT
+ ; Частное не определено
= 0002 + CNTR = CNTR +1
+ ENDIF
+ IF CNTR
+ ; Макрорасширение отменено
+ EXITM
011E C3 RET
011F MAIN ENDP
011F CSEG ENDS
END BEGIN
__________________________________________________________________________
Рис.20.6. Использование директив IF и IFNDEF.
МАКРОС, ИСПОЛЬЗУЮЩИЙ IFIDN-УСЛОВИЕ
________________________________________________________________
Программа на рис.20.7 содержит макроопределение по имени MOVIF,
которая генерирует команды MOVSB или MOVSW в зависимости от указанного
параметра. Макрокоманду можно кодировать с параметром B (для байта) или W
(для слова) для генерации команд MOVSB или MOVSW из MOVS.
Обратите внимание на первые два оператора в макроопределении:
MOVIF MACRO TAG
IFIDN "&TAG","B"
Условная директива IFIDN сравнивает заданный параметр (предположительно B
или W) со строкой B. Если значения идентичны, то ассемблер генерирует REP
MOVSB. Обычное использование амперсанда (&) - для конкатенации, но в
данном примере операнд "TAG" без амперсанда не будет работать. Если в
макрокоманде не будет указан параметр B или W, то ассемблер сгенерирует
предупреждающий комментарий и команду MOVSB (по умолчанию).
Примеры в кодовом сегменте трижды проверяют макрокоманду MOVIF: для
параметра B, для параметра W и для неправильного параметра. Не следует
делать попыток выполнения данной программы в том виде, как она приведена
на рисунке, так как регистры CX и DX не обеспечены правильными значениями.
Предполагается, что рассматриваемая макрокоманда не является очень
полезной и ее назначение здесь - проиллюстрировать условные директивы в
простой форме. К данному моменту, однако, вы имеете достаточно информации
для составления больших полезных макроопределений.
__________________________________________________________________________
TITLE MACRO7 (COM) Проверка директивы IFIDN
; -------------------------------------------
MOVIF MACRO TAG
IFIDN "&TAG","B"
REP MOVSB
EXITM
ENDIF
IFIDN "&TAG","W"
REP MOVSW
ELSE
; Не указан параметр B или W,
; по умолчанию принято B
REP MOVSB
ENDIF
ENDM
; -------------------------------------------
0000 CSIG SEGMENT PARA 'Code'
ASSUME CS:CSEG,DS:CSEG
ASSUME SS:CSEG,ES:CSEG
0100 ORG 100H
0100 EB 00 BEGIN: JMP SHORT MAIN
; ...
0102 MAIN PROC NEAR
.LALL
MOVIF B
+ IFIDN "B","B"
0102 F3/A4 + REP MOVSB
+ EXITM
MOVIF W
+ ENDIF
+ IFIDN "W", "W"
0104 F3/A5 + REP MOVSW
+ ENDIF
MOVIF
+ ENDIF
+ ELSE
+ ;Не указан парам. B или W, по умолч.принято B
+ ;--------------------------------------------
0106 F3/A4 + REP MOVSB
+ ENDIF
0108 C3 RET
0109 MAIN ENDP
0109 CSEG ENDS
END BEGIN
__________________________________________________________________________
Рис.20.7. Использование директивы IFIDN
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________
- Макросредства возможны только для полной версии ассемблера (MASM).
- Использование макрокоманд в программах на ассемблере дает в
результате более удобочитаемые программы и более производительный код.
- Макроопределение состоит из директивы MACRO, блока из одного или
нескольких операторов, которые генерируются при макрорасширениях и
директивы ENDM для завершения определения.
- Код, который генерируется в программе по макрокоманде, представляет
собой макрорасширение.
- Директивы .SALL, .LALL и .XALL позволяют управлять распечаткой
комментариев и генерируемого объектного кода в макрорасширении.
- Директива LOCAL позволяет использовать имена внутри
макроопределений. Директива LOCAL кодируется непосредственно после
директивы MACRO.
- Использование формальных параметров в макроопределении позволяет
кодировать параметры, обеспечивающие большую гибкость макросредств.
- Библиотека макроопределений дает возможность использовать
макрокоманды для различных ассемблерных программ.
- Условные директивы позволяют контролировать параметры макрокоманд.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ
________________________________________________________________
20.1. Напишите необходимые директивы: а) для подавления всех команд,
которые генерирует макрокоманда и б) для распечатки только команд,
генерирующих объектный код.
20.2. Закодируйте два макроопределения для умножения: а) MULTBY
должна генерировать код для умножения байта на байт; б) MULTWD должна
генерировать код для умножения слова на слово. Для множителя и множимого
используйте в макроопределении формальные параметры. Проверьте выполнение
макрокоманд на небольшой программе, в которой также определены необходимые
области данных.
20.3. Запишите макроопределения из вопроса 20.2 в "макробиблиотеку".
Исправьте программу для включения элементов библиотеки по директиве
INCLUDE в первом проходе ассемблирования.
20.4. Напишите макроопределение BIPRINT, использующей BIOS INT 17H
для печати. Макроопределение должно включать проверку состояния принтера и
обеспечивать печать любых строк любой длины.
20.5. Измените макроопределение на рис.20.6 для проверки делителя на
ноль (для обхода деления).
ГЛАВА 21 Компоновка программ
__________________________________________________________________________
Ц е л ь: Раскрыть технологию программирования, включающую компоновку
и выполнение ассемблерных программ.
ВВЕДЕНИЕ
________________________________________________________________
Примеры программ в предыдущих главах состояли из одного шага
ассемблирования. Возможно, однако, выполнение программного модуля,
состоящего из нескольких ассемблированных программ. В этом случае
программу можно рассматривать, как состоящую из основной программы и одной
или более подпрограмм. Причины такой организации программ состоят в
следующем:
- бывает необходимо скомпоновать программы, написанные на разных
языках, например, для объединения мощности языка высокого уровня и
эффективности ассемблера;
- программа, написанная в виде одного модуля, может оказаться
слишком большой для ассемблирования;
- отдельные части программы могут быть написаны разными группами
программистов, ассемблирующих свои модули раздельно;
- ввиду возможно большого размера выполняемого модуля, может
появить
...Поділитися у соцмережах