Читать «Макросы и директивы компилятора FASM» онлайн - страница 3
Автор неизвестен
Вот пример макроса, который создаст таблицу адресов к строкам, заданных этими строками:
macro strtbl name,[string]
{
common
label name dword
forward
local label
dd label
forward
label db string,0
}
Первый аргумент, переданный этому макросу, станет меткой для таблицы адресов, следующие аргументы должны быть строками. Первый блок обрабатывается только один раз и определяет метку, второй блок для каждой строки объявляет ее локальное имя и определяет запись таблицы, содержащую адрес той строки. Третий блок определяет данные каждой строки с соответствующей меткой. Директива, начинающая блок в макросе может сопровождаться первой инструкцией этого блока на той же самой строке, как показано в следующем примере:
macro stdcall proc,[arg]
{
reverse
push arg
common
call proc
}
Этот макрос может использоваться для вызова процедур, использующих соглашение STDCALL, где аргументы сохраняются на стек в обратном порядке. Для примера stdcall foo, 1,2,3
будет собран как:
push 3
push 2
push 1
call foo
Если некоторое имя в макросе имеет множественные параметры (одним из аргументов, огороженных в квадратные скобки или локальным именем, определенным в блоке, следующем за директивой forward
или reverse
) и используется в блоке, следующем за директивой common, это имя будет заменено всеми ее величинами, отделенными запятыми. Например следующий макрос передаст все дополнительные аргументы предварительно заданному макросу stdcall
:
macro invoke proc,[arg]
{
common
stdcall [proc],arg
}
Это может использоваться, чтобы вызывать косвенно (по указателю, находящемуся в памяти) процедуру, используя соглашение STDCALL.
Внутри макроса существует также специальный оператор #
. Этот оператор связывает два имени в одно. Это может быть полезно, потому что это делается после того, как аргументы и локальные имена меняются на их настоящие значения. Следующий макрос произведет условный переход согласно аргументу cond
:
macro jif op1,cond,op2,label
{
cmp op1,op2
j#cond label
}
К примеру jif ax,ae,10h,exit
будет скомпилировано как cmp ax,10h
и jae exit
.
Чтобы сделать макрос, ведущий себя в зависимости от типа аргумента, когда аргументы — строки или нет, Вы может использовать факт, что ассемблер отличает напрямую указанные строки от указанных строк в численных выражениях, но не отличает численное выражение, которому предшествуют знак +
от того же самого выражения без знака. Так строка, которой предшествуют +
со знаком будут обрабатывать как численное выражение и не будет символически равен той же самой строке без любого знака, в то время как любая другая величина будет символически равна тому же самому выражению, которому предшествуют +
знак. Вот пример макроса, использующий эту особенность:
macro message arg
{
if arg eq +arg
mov dx,arg
else
local str
jmp @f
str db arg,0Dh,0Ah,24h
@@:
mov dx,str
end if
mov ah,9 int 21h