Руководство по препроцессору FASM - страница 3

стр.

или >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 (правда, занимают побольше места, чем реальные инструкции:). Всё же, переопределение инструкций не всегда хорошая идея — кто-нибудь читая Ваш код может быть введён в заблуждение, если он не знает, что инструкция переопределена.

Также, возможно переопределять директивы ассемблера:

>macro use32

>{

> align 4

> use32

>}

>macro use16

>{

> align 2

> use16

>}

5. Макросы с фиксированным количеством аргументов

5.1. Макросы с одним аргументом

Макросы могут иметь аргумент. Аргумент представляет собой какой-либо идентификатор, который будет повсюду заменён в теле макроса тем, что будет указанно при использовании.

Синтаксис:

>macro name argument { тело макроса }

Например:

>macro add5 where

>{

> add where, 5

>}

>add5 ax

>add5 [variable]

>add5 ds

>add5 ds+2

получим:

>add ax, 5

>add [variable], 5

>add ds, 5  ;такой инструкции не существует

>           ;но препроцессор это не волнует.

>           ;ошибка появится на стадии ассемблирования.

>add ds+2,5 ;ошибка синтаксиса, как и ранее

>           ;определится при анализе синтаксиса (parsing).

(разумеется, комментарии в результате работы препроцессора не появятся:)

5.2. Макросы с несколькими аргументами

У макросов может быть несколько аргументов, разделённых запятыми,

>macro movv where, what

>{

> push what

> pop where

>}

>movv ax, bx

>movv ds, es

>movv [var1], [var2]

преобразуется в:

>push bx

>pop ax


>push es

>pop ds


>push [var2]

>pop [var1]

Если несколько аргументов имеют одно и тоже имя, то будет использован первый из них:).

Если при использовании макроса указать меньше аргументов, чем при определении, то значения неуказанных будет пустым:

>macro pupush a1, a2, a3, a4

>{

> push a1 a2 a3 a4

> pop a4 a3 a2 a1

>}

>pupush eax, dword [3]

получим:

>push eax dword [3]

>pop dword [3] eax

Если в аргументе макроса необходимо указать запятую, необходимо аргумент заключить в скобочки из символов >< и >>.

>macro safe_declare name, what

>{

> if used name

>  name what

> end if}


>safe_declare var1, db 5

>safe_declare array5,

>safe_declare string,

получим:

>if used var1

> var1 db 5

>end if


>if used array5

> array5 dd 1,2,3,4,5

>end if


>if used string

> string db "привет, я просто строка",0

>end if

Конечно же, можно использовать символы >< и >> и внутри тела макроса:

>macro a arg {db arg}

>macro b arg1,arg2 {a }

>b <1,1>,2

получим:

>db 1,1,2,3

5.3. Директива LOCAL

Возможно, появится необходимость объявить метку внутри тела макроса:

>macro pushstr string

>{

> call behind ; помещаем в стек адрес string и переходим к behind

> db string, 0

>behind:

>}

но если использовать такой макрос 2 раза, то и метка >behind будет объявлена дважды, что приведёт к ошибке. Эта проблема решается объявлением локальной метки >behind. Это и делает директива >LOCAL.

Синтаксис:

>local label_name

Директива должна применяться внутри тела макроса. Все метки label_name внутри макроса становятся локальными. Так что, если макрос используется дважды никаких проблем не появляется:

>macro pushstr string

>{

>  local behind

>  call behind

>  db string,0

> behind:

>}

>pushstr 'aaaaa'

>pushstr 'bbbbbbbb'

>call something

На самом деле, behind заменяется на >behind?XXXXXXXX, где >XXXXXXXX — какой-то шестнадцатеричный номер генерируемый препроцессором. Последний пример может быть преобразован к чему-то вроде: