Chinaunix首页 | 论坛 | 博客
  • 博客访问: 226395
  • 博文数量: 45
  • 博客积分: 1850
  • 博客等级: 上尉
  • 技术积分: 473
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-11 10:21
文章分类
文章存档

2006年(17)

2005年(28)

我的朋友

分类:

2006-04-25 08:21:30

是具有宏名的一段汇编语句序列,经过定义的宏,只要写出宏名,就可以在源程序中调用它。与伪指令主要指示如何汇编不同,宏指令实际上是一段代码的序列的缩写,在汇编时,汇编程序用对应的代码序列代替宏指令。
一、宏的定义和调用
宏定义由一对汇编伪指令MACRO/ENDM来完成,格式如下:
宏名    MACRO [形参表]
        宏定义体
        ENDM
例28.1:源程序开始通常要初始化DS,可以定义一个宏。
mainbegin   MACRO            ;;定义一个名为mainbegin的宏,无参数
            mov ax,@data     ;;宏定义体
            mov ds,ax
            ENDM             ;;宏定义结束
宏定义中的注释如果使用双分号分隔,则在后面的宏展开中将不再出现该注释。
返回DOS的4cH调用,定义宏如下:
mainend    MACRO  retnum        ;;带有形参return
           mov al,retnum
           mov ah,4ch
           int 21h
           ENDM
输出信息的宏:
dispmsg   MACRO message
          lea dx,message
          mov ah,09h
          int 21h
          ENDM
宏定义后就可以使用,宏调用遵循先定义后调用的原则,格式:
宏名    [实参表]
在汇编时,宏指令被汇编程序用对应的代码序列替代,称之为宏展开。汇编后的列表文件中带有“+”或“1”等数字的语句为相应的宏定义体。宏展开的具体过程是:当汇编程序扫描源程序遇到已有定义的宏调用时,即用相应的宏定义体取代源程序的宏指令,同时用位置匹配的实参对形参进行取代。实参与形参的个数可以不等,多余的实参不予考虑,缺少的实参对相应的形参作“空”处理(以空格取代);另外汇编程序不对实参和形参进行类型检查,取代时完全是字符串的替代,至于宏展开后是否有效则由汇编程序翻译时进行语法检查。宏调用时将相应的程序段复制到宏指令的位置,嵌入源程序,即宏调用的程序体实际上未减少,故宏指令的执行速度比子程序快。
例28.2:用宏汇编实现信息显示
        ...             ;;上述三个宏定义
        .model small
        .stack 256
        .data
string  db 'Hello Everybody!',0dh,0ah,'$'
        .code
start:  mainbegin
        dispmsg string
        mainend 0
        end start
产生的列表文件如下:
Microsoft (R) Macro Assembler Version 6.11      04/25/06 08:19:25
28-1.asm           Page 1 - 1

    mainbegin   MACRO            ;;定义一个名为mainbegin的宏,无参数
                mov ax,@data     ;;宏定义体
                mov ds,ax
                ENDM             ;;宏定义结束
    mainend    MACRO  retnum        ;;带有形参return
               mov al,retnum
               mov ah,4ch
               int 21h
               ENDM
    dispmsg   MACRO message
              lea dx,message
              mov ah,09h
              int 21h
              ENDM
            .model small
            .stack 256
 0000            .data
 0000 48 65 6C 6C 6F 20  string  db 'Hello Everybody!',0dh,0ah,'$'
       45 76 65 72 79 62
       6F 64 79 21 0D 0A
       24
 0000            .code
 0000    start:  mainbegin
 0000  B8 ---- R      1             mov ax,@data    
 0003  8E D8       1             mov ds,ax
            dispmsg string
 0005  8D 16 0000 R      1           lea dx,string
 0009  B4 09       1           mov ah,09h
 000B  CD 21       1           int 21h
            mainend 0
 000D  B0 00       1            mov al,0
 000F  B4 4C       1            mov ah,4ch
 0011  CD 21       1            int 21h
            end start
Microsoft (R) Macro Assembler Version 6.11      04/25/06 08:19:25
28-1.asm           Symbols 2 - 1
 

Macros:
                N a m e                 Type
dispmsg  . . . . . . . . . . . . Proc
mainbegin  . . . . . . . . . . . Proc
mainend  . . . . . . . . . . . . Proc

Segments and Groups:
                N a m e                 Size     Length   Align   Combine Class
DGROUP . . . . . . . . . . . . . GROUP
_DATA  . . . . . . . . . . . . . 16 Bit  0013   Word   Public  'DATA' 
STACK  . . . . . . . . . . . . . 16 Bit  0100   Para   Stack   'STACK' 
_TEXT  . . . . . . . . . . . . . 16 Bit  0013   Word   Public  'CODE' 

Symbols:
                N a m e                 Type     Value    Attr
@CodeSize  . . . . . . . . . . . Number  0000h 
@DataSize  . . . . . . . . . . . Number  0000h 
@Interface . . . . . . . . . . . Number  0000h 
@Model . . . . . . . . . . . . . Number  0002h 
@code  . . . . . . . . . . . . . Text     _TEXT
@data  . . . . . . . . . . . . . Text     DGROUP
@fardata?  . . . . . . . . . . . Text     FAR_BSS
@fardata . . . . . . . . . . . . Text     FAR_DATA
@stack . . . . . . . . . . . . . Text     DGROUP
start  . . . . . . . . . . . . . L Near  0000   _TEXT 
string . . . . . . . . . . . . . Byte  0000   _DATA 
    0 Warnings
    0 Errors

宏定义中可以调用宏,只要遵循先定义后调用的原则,如:
dosint21   MACRO   function
           mov ah,function
           int 21h
           ENDM
dispmsg    MACRO message
           mov dx,offset message
           dosint21 9
           ENDM
列表文件的源文件如下:
     dispmsg   msg        ;宏调用
1    mov dx,offset msg    ;宏展开(第一层)
1    dosint21 9
2    mov ah,9             ;宏展开(第二层)
2    int 21h
二、宏的参数
宏的参数功能强大,既可以无参数,也可以一个或多个参数,参数的形式也很灵活,可以是常数、变量、存储单元、指令(操作码)或它们的一部分,也可是表达式。
例28.3:具有多个参数的宏定义。
使用8086的一位移位指令,当移位次数大于1时,必须利用CL寄存器,不方便,用宏指令shlext扩展逻辑左移SHL的功能:
shlext   MACRO shloprand,shlnum
         push cx
         mov cl,shlnum
         shl shloprand,cl
         pop cx
         endm
当要AX左移6位时,采用如下宏指令:
shlext AX,6
例28.4:用做操作码的宏定义参数。
8086的移位指令有4条:shl/shr/sal/sar,我们用宏指令shift代替,这时需要用参数表示助记符:
shift    MACRO soprand,snum,sopcode
         push cx
         mov cl,snum
         s&sopcode& soprand,cl
         pop cx
         endm
宏定义中的一对“&”伪操作符括起sopcode,表示它是一个参数;这里用于分隔前面的字符S,表示是指令助记符的一部分,由于后面一个“&”后是空格,所以它可以省略。这样,将AX左移6位时,用如下宏指令:
shift ax,6,hl
进一步,将移位和循环移位共8条指令统一起来,定义一个宏指令:
shrot   MACRO sroprand,snum,sropcode
        push cx
        mov cl,snum
        sropcode sroprand,cl
        pop cx
        endm
例28.4:字符串用作宏定义参数
宏定义体中不仅可以是硬指令序列,还可以是伪指令语句序列。如为了方便09h号DOS功能调用,字符串的定义可以采用如下宏:
dstring   macro  string
          db '&string&',0dh,0ah,'$'
          endm
例如,要定义字符串'This is example.',可以采用如下的宏调用:
dstring  
它产生的宏展开为:
1   db  'this is example.',0dh,0ah,'$'
因为字符串中有空格,所以必须采用一对<>伪指令将字符串括起来。如果字符串中包含<>或其他特殊意义的符号,则应该使用转义伪指令“!”,例如定义字符串‘0dstring  <0!
1   db '0几个宏操作符的统一解释:
&——替换操作符,用于将参数与其他字符分开。如果参数紧接在其他字符之前或之后,或者参数出现在带引号的字符串中,就必须使用改伪操作符。
<>——字符串传递操作符,用于括起字符串。在宏调用中,如果传递的字符串实参数含有逗号、空格等间隔符号,则必须使用这对操作符,以保证字符串的完整。
!——转义操作符,用于指示其后的一个字符作为一般字符,而不含有特殊意义。
%——表达式操作符,用在宏调用中,表示将后跟的一个表达式的值作为实参,而不是表达式本身作为参数。例如,对于上一个宏定义:
dstring   %(1024-1)       ;宏调用
1   db '1023',0dh,0ah,'$' ;宏展开
;;——宏注释符
宏定义中还可以使用“: REQ ”说明设定不可缺参数,用“:=缺省值”设定参数缺省值。
三、与宏有关的伪指令
1、局部标号伪指令LOCAL
宏定义可以被多次调用,每次调用实际上是把替代参数后的宏定义体复制到宏调用的位置,但是当宏定义中使用了标号,同一源程序对他的多次调用就会造成标号的重复定义。如果宏定义体采用了标号,可以使用局部标号伪指令LOCAL加以说明,其格式:
LOCAL 标号列表
其中,标号列表由宏定义体中使用的标号组成,用逗号分隔。这样每次宏展开时汇编程序将对其中的标号自动产生一个唯一的标识符(形式为“??0000”到“??FFFF”),避免了标号的重复。
LOCAL伪指令只能在宏定义体内使用,而且是宏定义MACRO语句后的第一条语句,两者间也不允许有注释和分号。
例28.5:具有标号的宏定义
absol    macro oprd
         local next
         cmp oprd,0
         jge next
         neg oprd
next:
         endm
这是一个求绝对值的宏定义,具有分支结构采用了标号,如下宏调用:
absol   word ptr [bx]
absol   bx
宏展开将形成以下代码:
1    cmp word ptr [bx],0
1    jge ??0000
1    neg word ptr [bx]
1    ??0000:
1    cmp bx,0
1    jge ??0001
1    neg bx
1    ??0001:
2、宏定义删除伪指令PURGE
当我们不需要宏定义时,可以把它删除,格式为:
PURGE  宏名表
宏名表是由逗号分隔的需要删除的宏名,MASM汇编语言中,允许宏名与其他指令包括伪指令同名,此时宏名优先级最高,当不再使用这个宏定义时,及时用PURGE删除即恢复原指令功能。
3、宏定义退出伪指令EXITM
伪指令EXITM表示结束当前宏的展开,它的格式:
EXITM
它可用于宏定义体、重复汇编的重复块以及条件汇编的分支代码序列中,汇编程序执行到EXITM指令后立即停止他后面部分宏的展开。
四、宏与子程序
子程序能实现的功能,用宏也可以实现,但宏与子程序有本质上的不同,主要反映在调用方式,另外在传递参数和使用细节上也有很多不同。
1、宏调用在汇编时进行程序语句的展开,不需要返回;它仅仅是源程序级的简化,并不减少目标程序,执行速度没有改变。子程序调用在执行时由CALL指令转向子程序体,子程序需要执行RET指令返回,他还是目标程序级的简化,形成的目标代码短。但是子程序需要利用堆栈保存和恢复转移地址、寄存器,要占用一定的时空开销,特别是当子程序较短时,这种额外开销所占比例较大。
2、宏调用的参数通过形参、实参结合实现传递,简捷直观、灵活多变,子程序利用寄存器、存储单元或堆栈等传递参数。对宏来说,参数传递错误通常是语法错误,会由汇编程序发现,子程序参数传递错误通常反映为逻辑错误或运行错误,不易排除.
阅读(2422) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~