Использование ДУА в макросах

Пример 1. Опишем в виде макроса операцию сдвига значения переменной x на n разрядов вправо. n – явно заданное положительное число. Макрорасширение должно содержать минимально возможное число команд. Это можно сделать так:

shift macro x, n Обращения: shift A, 5 ; x = A, n = 5

ife n – 1 ; n – 1 = 0 ? После макрогенерации:

shr x, 1 mov CL, 5

else ; n > 1 shr A, CL

mov CL, n

shr x, CL

endif

endm

Пример 2.Константное выражение в if и ife может быть любым, но так как оно вычисляется на этапе макрогенерации, в нем не должно быть ссылок на величины, которые станут известными только при выполнении программы. Например, в константных выражениях не должно быть ссылок на регистры и ячейки памяти, не должно быть ссылок вперед. Константное выражение должно быть вычислено макрогенератором при первом проходе. Константное выражение часто бывает логическим, в нем могут использоваться операторы отношения: EQ, NE, LT, LE, GT, GE и логические операторы NOT, OR, XOR. Запишем в виде макроса SET_0 x операцию x = 0, если x – переменная размером в байт, слово или двойное слово.

SET_0 macro x

if type x EQ dword

mov dword ptr x, 0

elseif type x EQ word

mov word ptr x, 0

else mov byte ptr x, 0

endif

endm

Пример 3.Напишем еще одно макроопределение для сдвига вправо на n разрядов значения байтовой переменной B. Учтем, что при n = 0 сдвига нет и макрорасширение не должно появиться в тексте программы, а при n > 7 результат сдвига – это 0, поэтому сдвиг можно заменить записью нуля в B. Set_0 macro B, n

if (n GT 0) AND (n LT 8) ;; 0 < n <8

mov CL, n

shr b, CL

else

if n GE 8 ;; n >= 8

mov B, 0

endif

endif

endm

Пример 4 использование ifidn и ifdif. Поиск max или min из двух знаковых величин, хранящихся в байтовых регистрах, т.е. вычислить R1 = T (R1, R2),где T – это max или min, причем, должно генерироваться непустое макрорасширение только если R1 и R2 – это разные регистры. Если обращение к макросу будет Max_Min R1, R2, T, то необходимо проверять несовпадение первых двух параметров. И чтобы один макрос вычислял и max и min, нужно проверять и значение третьего параметра. Макрос может быть таким:

Max_Min macro R1, R2, T

Local L

ifdif <R1>, <R2> ;; R1 и R2 – разные регистры

Cmp R1, R2

ifidn <T>, <max> ;; T = max ?

Jge L

Else

Jle L

Endif

Mov R1, R2

L: endif

Endm

Макрокоманда Max_Min AL, BH, MIN приведет к следующим действиям макрогенератора: (пусть метка L заменилась меткой вида ??0110)

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

ifdif <AL>, <BH> cmp AL, BH в исходном тексте

cmp AL, BH ifidn <MIN>, <MAX> программы

ifidn <MIN>, <MAX> jge ??0110 окажется

jge ??0110 else cmp AL, BH

else jle ??0110 jle ??0110

jle ??0110 endif mov AL, BH

endif mov AL, BH ??0110:

mov AL, BH ??0110: ----------------------

??0110: ----------------------------

endif

26) Многомодульные программы в Ассемблере, директивы для организации межмодульных связей

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

Masm p.asm, p.obj, p.list

link p.obj + ioproc.obj, p.exe

P.exe

Есть файл io.asm, содержащий описания макросов обращения к этим процедурам. Этот файл подключается на этапе ассемблирования с помощью директивы include io.asm.

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

Пусть программа состоит из двух модулей - головного и вспомогательного. Во вспомогательном описывается переменная EOT, значением которой является символ конца ввода текста, и процедура LOWLAT, заменяющую прописную на строчную.

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

; вспомогательный модуль

Public EOT, LOWLAT

D1 segment

EOT DB ‘.’ ; символ конца ввода

D1 ends

C1 segment

Assume CS: C1

LOWLAT proc far

; процедура перевода больших букв в малые,

; на входе (AL) – любой символ, на выходе (AL) – малая буква

cmp AL, ‘A’ ; AL < ‘A’ или AL > ‘Z’, то nolat

Jb nolat

cmp AL, ‘Z’

Ja nolat

add AL, - ‘A’ + ‘a’

Nolat: ret

LOWLAT endp

C1 ends

End

; головной модуль

include io.asm

extrn EOT: byte, LOWLAT: far

s segment stack

DB 256 dup (?)

s ends

d segment

txt DB 100 dup (?), ‘$’

d ends

c segment

assume SS: s, DS: d, CS: c

start: mov AX, d

mov DS, AX ; DS = d для доступа к TXT

mov AX, seg EOT

mov ES, AX ; ES = D1 для доступа к EOT

mov SI, 100

OutCH ‘>’ ; приглашение к вводу символа

inp: InCH AL ; ввод символа

cmp AL, ES:EOT ; если достигнут конец ввода

je PR ; то PR

call LOWLAT ; замена символа

dec SI

mov TXT[SI], AL

jmp inp

PR: lea DX, TXT[SI] ; вывод

OutSTR ; на экран TXT

Finish

c ends

end start

В основной программе OutCH <параметр> и InCH <параметр> - макрокоманды ввода и вывода на экран параметра OutSTR - макрокоманда вывода строки

Finish macro ; макрос окончания счета

mov AH, 4Ch

int 21h

endm

2) Передача параметров в подпрограммы по ссылке и по значению, организация рекурсивных подпрограмм

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

Например, нужно вычислить c = max (a, b) + max (7, a-1). Здесь все числа знаковые, размером в слово. Используем передачу параметров через регистры. Процедура получает параметры через регистры AX и BX, результат возвращает в регистре AX.

Процедура: AX = max (AX, BX)

max proc

cmp AX, BX

jge met1

mov AX, BX

met1: ret

max endp

Фрагмент вызывающей программы:

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

; c = max (a,b) + max (7, a-1)

mov AX, a

mov BX, b

call max ; AX = max (a,b)

mov c, AX ; c = max (a,b)

mov AX, 7

mov BX, a

Dec BX

call max ; AX = max (7, a-1)

add c, AX

Наши рекомендации