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 
posted @ 2020-02-09 16:07  蹦蹦骑士  阅读(1575)  评论(0编辑  收藏  举报