NASM手册阅读笔记(3) - 预处理器之宏定义
简要说明
所谓预处理器,就是在编译阶段由编译器解释执行的代码,所以代码的结果应该是在编译阶段就能确定,否则就会报错。
强大的预处理器可以简化和增强汇编代码的能力。
单行宏
%define / %idefine
基本格式:
%define a mov ax,1
%define a(p1,p2) mov p1,p2
%define a(p1,p2,p3) P3 p1,p2
说明:
宏可以重载,也就是说可以定义米子相同参数不同的宏,使用的时候编译器会根据参数类确定用哪一个,但是如果定义了不带参数的,那么就不能重载了
%define 是区分大小写的所以
%define Foo 和 %define foo 是不一样的
%idefine 是忽略大小写的版本
%xdefine/%ixdefine
说明:
与%define的区别是展开的时机不同
%define 是在使用的时候展开
%xdefine 是在定义的时候被展开,其中的区别可以用如下代码演示
举例1:
#define a 1 ; A=1
#define b a ; 因为是调用时展开,所以具体的内容得调用的时候确定A的内容后才能展开
#define a 0 ; A被重定义 = 0
mov ax, b
此时展开b
step1. mov ax, a
step2. mov ax, 0
举例2
使用%xdefine 在定义是展开
#xdefine a 1 ; A=1
#xdefine b a ; 定义时展开,所以实际上就是 #xdefine b 1
#xdefine a 0 ; A被重定义 = 0
mov ax, b
此时展开b
step1. mov ax, b
step2. mov ax, 1
%+
说明:
字符连接,相当于MASM和C中的 & 的作用
举例
#define a(b) student. %+ b
a(id) => student.id
%undef
说明:
取消宏定义
%assign/%iassign
说明:
定义常数的专用的%define
区别就在于%assign只能用于定义常数,同时定义形式可以是可以是表达式,
比如
%assign x 1 ; x=1
%assign x x+1 ;他会计算表达式的值所以 x=2 不是 1+1
多行宏
%macro / %imacro
基本格式:
%macro 宏名称 参数数量
push ebp
mov ebp,esp
sub esp,%1
%endmacro
说明:
参数数量是一个数字,表示这个宏接收几个参数
在宏定义中用 %数字来表示 第几个参数,比如
%1 表示第一个参数 %2 表示第二个参数,索引从1 开始,%0表示的是参数的个数
可以重载带不同参数数量的宏,因为就算不带参数也是 写 0 所以这里没有不带参数的宏定义后就不能重载的限制
使用
宏名字 参数1, 参数2 ,{ 我是带, 逗号的参数,需要使用括号括起来表示一个整体}
宏中的本地标签
在MASM中宏中的本地标签用的是.label的形式,nasm中使用 %%label的形式,这里注意区别
普通代码中的本地标签: .LABEL
宏定义中的本地标签: %%LABEL
%macro a 0
jnz %%skip
ret
%%skip:
%endmacro
贪婪宏定义
在宏定义的参数数量后边加上 + 加号,就表示这是一条贪婪宏定义
其含义就是多出来的参数被当成一个整体作为最后一个参数传入
比如我如下两个宏的定义
%macro M1 2+
%macro M2 2
那么
M1 PARAM1,PARAM2,PARAM3,PARAM4
M2 PARAM1, {PARAM2,PARAM3,PARAM4}
这两个调用完全等价
指定参数范围
%macro M1 1-4 默认参数2, ,默认参数4
这表示 这个宏的参数是 1- 4 个,有点类似c++的默认参数语法: void m(x1, x2=1,x3=3,x4=4);
其完整含义如下:
第一个参数的必须的
如果没有第二个参数,就使用默认参数2,
如果没有第三个参数,就使用默认参数3,因为没有默认参数3, 就使用空
如果没有第四个参数,就使用默认参数4
注意:支持通配符* 表示任意 比如 0-* 表示随便几个参数
支持贪婪定义,比如 0 - 4+
参数的连接
就是MASN和C中& 和&& 的作用,在单行宏定义中需要使用 符号 %+来连接,多行宏就不需要了,可直接使用
比如
%1abc ,abc%1
但是如果是数字则要这样
%{1}123
123%1
.nolist
作用的在生成list文件的时候不要抱宏扩展出来,你生成list文件是希望将指令对照着2进制代码去看的,这个时候如果保留宏,而不是将宏给扩展出来的话,可读性会更好一点。
格式
%macro foo 1.nolist
%macro bar 1-5+.nolist a,b,c,d,e,f,g,h
%roate
格式:
%roate 左移个数
说明:
多行宏定义中的参数左移, 负数就是右移
比如
现在的参数是
%1 %2 %3 %4
a b c d
使用
%roate 2 结果如下
%1 %2 %3 %4
c d a b
有什么用呢?
举例
%macro multipush 1-*
%rep %0
push %1
%rotate 1
%endrep
%endmacro
那么我无论 multipush 跟几个寄存器,他都能正常push
同理
%macro multipop 1-*
%rep %0
%rotate -1
pop %1
%endrep
%endmacro