Читать «Макросы и директивы компилятора 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