count equ 10
mov ecx, count
преобразуется в:
mov eax, count
mov ecx,10
потому что препроцессор заменит count
только после директивы equ
.
Даже это работает:
10 equ 11
mov ecx, 10
после обработки препроцессором, получим:
mov ecx, 11
Обратите внимание, name1
может быть любым идентификатором. Идентификатор — это всего лишь набор символов, завершаемый пробелом (space), символом табуляции (tab), концом строки (EOL), комментарием ;
, символом переноса строки \
или оператором, включая операторы ассемблера и/или специальные символы вроде ,
или }
.
name2
может быть не только единичным идентификатором, берутся все символы до конца строки. name2
может и отсутствовать, тогда name1
будет заменен на пустое место.
Например:
10 equ 11, 12, 13
db 10
получим:
db 11, 12, 13
3.2. Директива RESTORE
Можно заставить препроцессор прекратить заменять идентификаторы, определённые директивой EQU
. Это делает директива RESTORE
.
Синтаксис:
restore name1
name1
— это идентификатор определённый ранее в директиве EQU
. После этой команды name больше не будет заменяться на name2
.
Например:
mov eax, count
count equ 10
mov eax, count
restore count
mov eax, count
получим:
mov eax, count
mov eax, 10
mov eax, count
Обратите внимание, что для определений сделанных директивой 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
к несуществующему макросу, ничего не произойдёт.