Жанр: Учеба

Ассемблер и программирование для IBM PC

сторінка №27

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 Компоновка программ


__________________________________________________________________________

Ц е л ь: Раскрыть технологию программирования, включающую компоновку
и выполнение ассемблерных программ.

ВВЕДЕНИЕ
________________________________________________________________

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

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

Список сторінок

Поділитися у соцмережах

☏ Замовлення реклами: +3805044-68-872

© Асоціація електронних бібліотек України

☝ Усі матеріали сайту (зокрема статті, зображення, рекламні оголошення тощо) призначені лише для попереднього ознайомлення. Усі права на публікації, представлені на сайті, належать їхнім законним власникам. Просимо Вас не зберігати копії інформації.