多行宏 %macro:
%macro foo 2
push rax
push rbx
mov rax,%1
mov rbx,%2
pop rbx
pop rax
%endmacro
宏名称后的数字代表宏参数的个数,宏主体中的%1和%2分别代表实际的参数。使用如下方式调用:
foo 0x11,0x22
如果宏参数中包含,号,可以将参数用{}包围起来。
%macro foo 2
%2:db %1
%endmacro
foo {13,10},crlf
;实际生成的代码为:
crlf: db 13,10
类似单行宏,多行宏也可以通过定义不同参数个数来重载,对于不带参数的宏也不像单行宏那样有特例了。
在宏中可以定义宏内局部标签(macro local labels),对于宏的每一次展开都会生成不同的标签,宏内标签需要用%%开头:
%macro foo 0
jnz %%skip
ret
%%skip:
%endmacro
nasm允许将宏的最后一个参数定义为贪婪参数,如果传递多余的参数,则多出来的参数连同其中的逗号都会被传给宏中定义的最后一个实参:
%macro foo 2+
%endmacro
nasm多行宏可以定义一个允许参数的个数范围,如果这样做了,可以为参数指定缺省值:
;0或1个参数,如果未传递参数则默认%1为"hello"
%macro foo 0-1 "hello"
...
%endmacro
;至少一个参数,另外2个若不指定则使用默认值eax和[eax+2]
%macro foo 1-3 eax,[eax+2]
如果在宏定义时漏掉定义缺省值,则缺省值被赋为空;而且记号%0可以让你确定有实际传递参数的个数。最大参数个数可以为无限,用*表示。
使用%rotate可以循环移动宏参数,但它和unix的shift命令略有不同,他不会丢弃移出的参数,当一个参数被移到最左边时再次移动会回到最右边,则也是rotate单词的含义。%rotate可以带一个数值参数,如果是正数表示左移的次数,如果是负数表示右移的次数。可以以此来写一个保存和恢复寄存器的宏:
%macro save 1-*
%rep %0
push %1
%rotate 1
%endrep
nop
add rax,rax
%rep %0
%rotate -1
pop %1
%endrep
%endmacro