Обратите внимание, что для определений сделанных директивой EQU
работает принцип стека. То есть, если мы два раза определим один и тот же идентификатор используя EQU
, то после однократного использования RESTORE
значение идентификатора будет соответствовать определённому первой директивой EQU
.
Например:
mov eax, count
count equ 1
mov eax, count
count equ 2
mov eax, count
count equ 3
mov eax, count
restore count
mov eax, count
restore count
mov eax,count
restore count
mov eax,count
получим:
mov eax, count
mov eax, 1
mov eax, 2
mov eax, 3
mov eax, 2
mov eax, 1
mov eax, count
Если попытаться выполнить RESTORE
большее количество раз, чем было сделано EQU
, никаких предупреждений выдано не будет. Значение идентификатора будет неопределенно.
Например:
mov eax, count
restore count
mov eax, count
получим:
mov eax, count
mov eax, count
4. Простые макросы без аргументов
4.1. Определение простых макросов
Использую EQU
можно делать наиболее простые замены в исходном тексте при обработке препроцессором. Большими возможностями обладают макросы. Командой MACRO
можно создавать собственные инструкции.
Синтаксис:
macro name
{
; тело макроса
}
Когда препроцессор находит директиву macro
, он определяет макрос с именем name
. Далее, встретив в исходном тексте строку, начинающуюся с name
, препроцессор заменит name
на тело макроса — то, что указано в определении между скобочками {
и }
. Имя макроса может быть любым допустимым идентификатором, а тело макроса — всё, что угодно, за исключением символа }
, который означает завершение тела макроса.
Например:
macro a
{
push eax
}
xor eax, eax
a
будет заменено на:
xor eax, eax
push eax
Или:
macro a
{
push eax
}
macro b
{
push ebx
}
b
a
получим:
push ebx
push eax
Разумеется, макросы не обязательно оформлять так, как выше, можно делать и так:
macro push5 {push dword 5}
push5
получим:
push dword 5
Или:
macro push5 {push dword 5
}
с тем же самым результатом. Скобочки можете размещать как хотите.
4.2. Вложенные макросы
Макросы могут быть вложенными один в другой. То есть, если мы переопределим макрос, будет использовано последнее определение. Но если в теле нового определения содержится тот же макрос, то будет использовано предыдущее определение. Посмотрите пример:
macro a {mov ax, 5}
macro a
{
a
mov bx, 5
}
macro a
{
a
mov cx, 5
}
a
в результате получим:
mov ax, 5
mov bx, 5
mov cx, 5
Или такой пример:
macro a {1}
a
macro a {
a
2 }
a
macro a {
a
3 }
a
получим:
1
1
2
1
2
3
4.3. Директива PURGE. Отмена определения макроса
Как и в случае с директивой EQU
, можно отменить определение макроса. Для этого используется директива PURGE
с указанием имени макроса.
Синтаксис:
purge name
Пример:
a
macro a {1}
a
macro a {2}
a
purge a
a
purge a
a
получим:
a
1
2
1
a
Если применить PURGE
к несуществующему макросу, ничего не произойдёт.
4.4. Поведение макросов
Имя макроса будет заменено его телом не только в том случае, если оно расположено в начале строки. Макрос может находиться в любом месте исходного текста, где допустима мнемоника инструкции (например, add
или mov
). Всё потому, что основное предназначение макросов — имитировать инструкции. Единственное исключение из этого правила — макросы недопустимы после префиксов инструкций (rep
).
Пример:
macro CheckErr
{
cmp eax, -1
jz error
}
call Something
a: CheckErr ; здесь макросу предшествует метка, всё Ок.
получим:
call Something
a: cmp eax,-1
jz error
Пример № 2:
macro stos0
{
mov al, 0
stosb
}
stos0 ;это место инструкции, будет замена.
here: stos0 ;это тоже место инструкции.
db stos0 ;здесь инструкции не место, замены не будет.
получим:
mov al, 0
stosb
here: mov al, 0
stosb
db stos0
Возможно переопределять (overload) инструкции посредством макросов. Так как препроцессор ничего об инструкциях не знает, он позволяет использовать мнемонику инструкции в качестве имени макроса:
macro pusha
{
push eax ebx ecx edx ebp esi edi
}
macro popa
{
pop edi esi ebp edx ecx ebx eax
}
эти 2 новые инструкции будут экономить по 4 байта в стеке, так как не сохраняют ESP
(правда, занимают побольше места, чем реальные инструкции:). Всё же, переопределение инструкций не всегда хорошая идея — кто-нибудь читая Ваш код может быть введён в заблуждение, если он не знает, что инструкция переопределена.