宏汇编

宏是具有宏名的一段汇编语句序列,经过定义的宏,只要写出宏名,就可以在源程序中调用它。与伪指令主要指示如何汇编不同,宏指令实际上是一段代码的序列的缩写,在汇编时,汇编程序用对应的代码序列代替宏指令。一、宏的定义和调用宏定义由一对汇编伪指令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,'$' 因为字符串中有空格,所以必须采用一对<>伪指令将字符串括起来。如果字符串中包含<>或其他特殊意义的符号,则应该使用转义伪指令“!”,例如定义字符串‘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、宏调用的参数通过形参、实参结合实现传递,简捷直观、灵活多变,子程序利用寄存器、存储单元或堆栈等传递参数。对宏来说,参数传递错误通常是语法错误,会由汇编程序发现,子程序参数传递错误通常反映为逻辑错误或运行错误,不易排除.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

supergame111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值