关于汇编语言宏相关的所有总结_第1页
关于汇编语言宏相关的所有总结_第2页
关于汇编语言宏相关的所有总结_第3页
关于汇编语言宏相关的所有总结_第4页
关于汇编语言宏相关的所有总结_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、原书笔记80X86汇编语言程序设计教程宏:1. 前言:l 宏是宏汇编语言的主要特征之一!l 若某程序片段需要多次使用,为了避免重复,可以将其定义为一条宏指令,利用宏指令代表该程序片段,汇编过程中,汇编器自动将宏指令替换为原程序片段。l (2015-9-16 20:43:44更新)关于宏的问题的探讨,远不止于这些内容,对于很多的细节问题,待到以后仔细查阅,此时,就不花太多时间在这些细节上了。2. 宏指令的定义和使用a. 宏指令在使用之前一定要先定义!b. 宏指令定义的一般格式如下:1. 宏指令名MACRO形式参数表2. 3. 程序片段4. 5. ENDM6. ;以下为示例:7. GETCHARM

2、ACRO;该宏指令无参数8. movah, 19. int21H10. ENDMl MACRO和ENDM是一对伪指令,成对出现,表示宏定义的开始和结束。l 宏定义体:MACRO与ENDM之间的部分是宏定义体,可以是由指令、伪指令、宏指令构成的程序片段l 宏指令名由用户指定,适用一般标号命名规则l 形式参数是可选的,并可以有一个或多个,多个形参之间用逗号间隔c. 宏调用:定义宏指令后,就可使用宏指令来表示对应的程序片段,这称为宏调用。一般格式如下1. 宏指令名实参列表2. ;以下为示例:3. GETCHAR4. movah, al5. ;通过调用宏指令后,将获得的字符,传送至ah中d. 宏展开(

3、宏扩展):在对源程序进行汇编时,汇编程序把源程序中的宏指令替换成对应的宏定义体,这称为宏展开或宏扩展。3. 宏指令的用途a. 缩短源代码l 将源程序中多次用到的某个程序片段(可以实现一定的功能,如换行、获得一个输入、打印一个输出等)定义成一条宏指令,在源程序中需要的地方,直接使用宏指令即可,有效的缩短了代码的长度,使得源代码可读性增强。b. 扩充指令集l CPU的指令集是确定的。l 利用宏能够在汇编语言的形式上对指令集进行扩充,扩充后的指令集是 机器指令集 与 宏指令集 的并集。l 方便了源程序的编写,也增强了源程序的可读性。c. 改变某些指令助记符的意义l 宏指令名可以与指令助记符或伪操作名

4、相同,同名的情况下,宏指令的优先级最高,而同名的指令或伪操作就失效了。l 利用以上原理,就可以实现改变指令助记符的意义了。4. 宏指令中参数的使用a. 宏指令可以不带参数,但是,带参数的宏指令往往更加灵活。b. 宏指令的参数很灵活1) 宏指令的参数可以是常数、寄存器和存储单元,还可以是表达式2) 宏指令的参数可以是操作码c. 宏调用参数个数可以与定义时不一致l 红调用时使用的实参个数应该与宏定义时的形参个数一致,但是汇编程序并不要求严格相等。l 处理办法:1) 若实参个数多于形参个数,那么多余的实参将被忽略2) 若实参个数少于形参个数,那么多余的形参将用空代替,即什么也没有3) 另外,必须保护

5、最能展开后的程序片段是正确的,有效的。5. 特殊的宏运算符a. 特殊的宏运算符运算符使用格式定义 用处&&参数强迫替换运算符 宏定义<><字符串>字符串原样传递运算符 宏调用、重复块、重复汇编、条件汇编!字符文字字符运算符 宏调用%表达式表达式运算符 宏调用;注释宏注释 宏定义l 以上宏运算符可用于宏定义、宏调用、重复块b. 强迫替换运算符&l (用于)宏定义中,如果形参出现在其他字符的紧前或紧后,或者出现在带引号的字符串中,为了使汇编器识别这是一个形参符号,就必须使用该运算符,以区分参数。以上标注黑粗体的两句话说明了使用强迫替换运算符的两种用法

6、!l 注意:1) 当在宏定义中,形参前或者形参后紧邻形参的一个(注意!只有一个不会)&符号都不会被识别为其他字符(包括在字符串中的情形),而仅用作区分形参的作用。(重要)不同的是,在字符串中,多余的&会被认为是一个普通字符,而在字符串之外,&会被认为是多余的字符而出错2) 强迫替换运算符不能用于变量或标号名!注意!c. 字符串原样传递运算符<>l 在(用于)宏调用、重复块和条件汇编中,将它括起来的内容作为一个字符串,也就是作为一个整体;1) 宏调用中,若实参包含逗号或空格等间隔符,则必须使用该运算符,以保证,实参的完整性;2) 若实参是某个有特殊意义的字符,

7、为了使它只表示字符本身,也可使用该运算符,把它括起来。3) 注意!使用字符串作为实参可以有两种情况1. 如果字符串之间没有逗号或者空格等分隔符,可以将没有双引号扩着的字符串直接作为实参,但是,由于在宏展开过程中,是文本替换,所以,要保证,替换处的两边有两个双引号或者单引号!2. 如果字符串之间有逗号或者空格等分隔符,则必须使用字符串原样传递运算符。3. 总结:实参可以有三种形式:1. 没有双引号或者单引号扩着的,并且其间没有逗号或者空格等分隔符的!2. 利用字符串原样传递运算符括起来的,没有双引号或者单引号扩着的!3. 利用字符串原样传递运算符括起来的,并且有双引号或者单引号扩着的!双引号或者

8、单引号包含在尖括号之间。4. 双引号或者单引号括起来的独立字符串对于每一种形式,对应的宏的编写是不一样的,1. 宏中形参两边必须用双引号括起来,并且,形参前必须添加强迫替换运算符!2. 同13. 宏中形参两边不必用双引号括起来!4. 同3上面的论述看起来太过复杂,我们不妨约定:当传递字符串实参时,用尖括号括起来,其中不添加引号。在宏定义中,需要在对应的字符串替换形参两边添加双引号或者单引号,并且,需要在形参前添加强迫转换运算符&。 或者: 当传递字符串实参时,用双引号或者单引号括起来,不添加尖括号。在宏定义中,没有特殊需要!d. 文字字符运算符l 用于宏调用中的实参中!l 该运算符用于

9、一般字符串中,使其后的一个字符只作为一般字符。e. 表达式运算符%l (用于)宏调用时,使用该运算符能把其后表达式的结果作为实参进行替换,而不是表达式本身。f. 宏注释;l 用于宏定义时!l 如果只用一个分号表示注释的话,那么每次宏调用,注释都会被复制一遍,为了使得宏定义中的注释不被复制,用两个分号对宏定义中的注释部分进行标记。6. 宏与子程序的区别(主要表现在宏调用时的差异)a. 宏调用是通过宏指令名进行的,多少次调用就复制多少次宏定义体;子程序在源程序中只有一份;b. 宏调用时的参数传递方式是通过文本替换的方式进行的;子程序调用传递参数的方式只能通过寄存器、堆栈或约定的内存单元进行传递c.

10、 宏调用在汇编时完成,不需要额外的时间开销,但是耗费较多的空间;子程序在程序执行时,通过调用返回指令,耗费一定的时间,但是不耗费多余的存储空间。7. 与宏有关的伪指令a. 局部变量说明伪指令LOCALl LOCAL标号表l 标号表由标号构成,标号间用逗号间隔。l 使用于(宏定义体中含有标号的宏)。l 使用于宏定义体中,必须是宏定义伪指令MACRO后的第一条语句!,MACRO与LOCAL之间不允许有注释和分号标志b. 清除宏定义的伪指令PURGEl PURGE宏名表l 宏名表由宏名构成,宏名之间用逗号间隔。l 该指令告诉汇编程序取消宏名表中的宏,不再展开它们。该命令之后的对于该宏的调用,也就被汇

11、编器无视掉了。l 该伪指令用于源程序中的任何地方!包括宏定义中和任何段之外,该伪指令不涉及机器指令,只用于汇编器。c. 中止宏扩展的伪指令EXITMl EXITMl 用在宏定义体中,常与条件伪指令一起使用,以便在规定的条件下跳过宏内的最后的语句。l 该指令通知汇编程序结束当前宏调用的扩展,退出当前宏,回到源程序或回到外层宏。d. 以上三条与宏有关的伪指令中,LOCAL与EXITM用于宏定义体中;PURGE用于其他位置或宏定义体中。8. 宏定义的嵌套(两种类型的嵌套)a. 宏定义体中调用宏l 宏汇编语言允许在宏定义体中进行宏调用;l 前提:在调用之前,被调用宏已经在之前定义过了b. 宏定义体中定

12、义宏语句l 宏定义体中允许进行宏的定义;l 调用内部宏的前提:只有调用了外部宏之后,才可以调用内部宏;因为:只有调用外部宏之后,内部宏才真正被定义l 当外部宏被调用后,外部宏中的代码部分被写入宏调用处,外部宏中的内部宏定义部分并不会被写入,可以认为,此时,内部宏定义由于外部宏的展开,才生效,所以,内部宏调用的前提是外部宏已经被调用过了。l 这里有一个小问题涉及到汇编程序的汇编过程,以后详解。(2015-9-16 20:41:19)8.3 重复汇编1. 前言l 程序中有时会需要连续的重复完全相同或者几乎完全相同的一组语句,这种情况下,可以考虑使用重复伪指令定义重复块,来简化程序。l 重复块是允许

13、建立重复语句块的宏的一种特殊形式,是一种特殊的宏。l 没有被命名的宏,因而不能被调用!;可以有参数;参数在汇编过程中可被实参替换;宏运算符、用伪指令LOCAL说明的符号 等可用于重复块;由ENDM结束2. 伪指令REPTl 一般格式如下:1. REPT表达式2. 需要重复的语句组3. ENDM4. ;实例5. CHAR=A6. dataSEGMENT7. TABLELABELBYTE;在数据段借助rept定义数据时,前面的变量名必须以这种形式(变量名+LABEL+BYTE)定义,不可以只写一个变量名,企图8. REPT26;直接可以连接到下行的定义部分9. DBCHAR10. CHAR = C

14、HAR + 111. ENDM;这是一种经典的使用方法,需要记牢,以后会有更多的更加灵活的方法等着我们去发现12. dataENDSl 汇编程序将把“需要重复的语句组”连续地重复汇编由表达式值所决定的次数;l 表达式必须可以求出数值常数(16位无符号数)l 任何有效的汇编语句均可以安排在“需要重复的汇编语句组”中l rept语句可以出现在源代码的任何部分,前提是:被重复的语句在被重复的位置处是有效的;比如说:将指令语句重复在数据段中是无效的。3. 伪指令IRPl 一般格式如下:1. IRP形式参数,<实参1, 实参2, 实参3,实参n>2. 需要重复的语句3. ENDM4. ;以下

15、为一实例5. dataSEGMENT6. quartLABELBYTE;类似与上面的用法,这是一个经典的用法7. IRPX,<0, 1, 2, 3, 4, 5, 6, 7, 8, 9>8. DBX*X9. ENDM;定义了一个名为quart的数组,数组中依次存放着09的数的平方值10. dataENDSl 参数的个数决定了重复的次数,汇编程序将把“需要复制的语句”连续地重复汇编规定的次数,并在每次汇编过程中,用相应的实参替换“需要重复的语句”中的形参。l 实参放置在一对尖括号中,与形参之间用逗号间隔,各个实参之间也用逗号进行间隔。4. 伪指令IRPCl 一般格式如下:1. IRPC

16、形式参数,字符串2. 需重复的语句组3. ENDM4. ;以下为一个示例:5. dataSEGMENT6. TABLELABELBYTE7. IRPCX, 01234567898. DW(X+1)*29. ENDM10. dataENDSl IRPC与IRP相似,除了前者的实参数列表是一个字符串以外完全一样l 字符串的长度规定了重复的次数,汇编程序将把“需要重复的语句组”连续地重复汇编指定的次数,并在每次汇编时依次使用“字符串”中的一个字符作为实参代替“需要重复的语句组”中的形式参数,l 如果字符串中含有空格,逗号等分隔符,那么字符串需用一对尖括号括起来!且一定不能使用双引号或者单引号,否则双

17、引号或者单引号也会被当做字符串的一部分,也就是当做实参替换形参。l 如果没有尖括号。1)空格之后的部分将会被忽略2)逗号之后的部分,连同逗号都会作为实参的一部分l 所以只要字符串之间没有空格字符,所有的部分都会被当做实参进行传递,如果这个实参有意义的话(一般逗号没有意义)l 如果想要将空格作为参数的话,那就按照最初的做法,将所有参数用尖括号括起来。问题描述:在一次测试过程中,我将带参数的重复汇编伪指令irp和irpc写入到一个宏中,以期,通过它们在该宏中实现将四个寄存器压入栈中的功能,如下所示:1. PUSHAMACRO2. irpR,<a,b,c,d>3. pushR&x

18、4. ENDM5. ENDM结果却不如人意,编译器提示了错误,而错误如下:1. Symbol not defined: RX *4这说明:pusha得到了展开,并且重复汇编指令也得到了展开,后者的实参并没有对形参进行替换!l 如果我们在代码中直接使用irp指令,则实参会正常替换形参。l 对于具有参数的irpc也具有这样的情形。l 但是有一种例外情况,如下所示:1. DFSQUAREMACRO2. tableLABELBYTE3. irpX,<0,1,2,3,4,5,6,7,8,9>4. DBX*X5. ENDM6. ENDMl 以上发生在irp语句中包含的是定义语句时!l 此问题待

19、定,具体原因并不知道是因为什么。以后尽量避免这样的嵌套行为。8.4 条件汇编1. 前言:a. 条件汇编提供根据某种条件决定是否汇编某段源代码的功能。b. 在源程序中使用条件汇编语句的主要目的是:1) 通过在汇编前或汇编时改变某种条件,从而方便地产生功能不同的程序;2) 增强宏定义能力,使得宏的适用范围更广;3) 改善汇编效率c. 条件汇编语句在形式上与高级语言中的条件语句相似,但本质上却是完全不同的:1) 条件汇编语句是说明性语句,由伪指令构成,功能上由汇编程序实现;2) 一般情况下,高级语言的条件语句是执行语句,由目标程序实现其功能。2. 条件汇编伪指令a. 大概:1) 一般格式如下:1.

20、IFxxxx条件表达式2. 语句组13. ELSE4. 语句组2;条件汇编语句的可选部分5. ENDIF2) 说明:l IFxxxx 是条件伪指令助记符的一般形式,xxxx表示构成条件伪指令助记符的其他字符;l 完整的条件伪指令助记符有:IFIFEIFDEFIFNDEFIF1IF2IFBIFNBIFIDNIFDIFl 每一个条件伪指令助记符都要对应一个条件结束伪指令助记符ENDIF,这个是统一的,必须的l 不同的条件指令助记符形式上可能有所不同,这里仅列出一般格式l 语句组可以包含有任意正确的语句,可以包含其他条件伪指令语句l ELSE语句组2部分是可选的l 条件汇编伪指令语句的一般意义是:如

21、果条件伪指令要求的条件满足,那么汇编“语句组1”,否则,在ELSE+语句组2存在的情况下,汇编语句组2,如果没有语句组2,且条件表达式不满足,那么不进行汇编操作;l 汇编语言允许条件语句伪指令嵌套,且允许的嵌套次数足以满足一般应用需要;l 一个嵌套的ELSE伪指令,总是与最近的但又没有ELSE相匹配的IFxxxx伪指令相匹配。b. 伪指令IF和IFE1) 一般格式:1. IF(IFE)表达式2. 语句组13. ELSE4. 语句组25. ENDIF6. ;示例如下:7. ;示例1:8. IFMFLAG;利用一个变量作为判定对象9. movah, 0;该条件汇编伪指令选择的是是否汇编 汇编指令语

22、句10. int16H11. ELSE12. movah, 113. int21H14. ENDIF15. ;示例2:16. IFPORT EQ0;利用一个关系表达式作为判定对象17. PORTADDR=3F8H;该条件汇编伪指令选择的是是否汇编 汇编伪指令语句,可以看出来,相当灵活18. IVECTN=0BH19. IMASKV=11110111B20. ENDIF21. ;示例3(更加复杂的示例,与宏与重复块相结合):22. SHIFTLMACROOP, N;定义了一个SHIFTL宏23. COUNT=024. REPTN;宏中包含了一个重复块定义语句,将操作数OP每次向右算术左移一位,直

23、到,移位的次数不小于N为止25. SHLOP, 126. COUNT=count + 127. IFCOUNT GE N;重复块定义语句中又包含了一个条件汇编语句28. EXITM29. ENDIF;退出条件汇编语句30. ENDM;退出重复块定义语句31. INCOP32. ENDM;退出宏定义语句2) 说明:l 伪指令IF:如果表达式的值不等于0,则条件满足,条件为真。非零即为真。这类似于C语言中对于条件表达式的值的判定方法。l 伪指令IFE:如果表达式的值等于0,则条件满足,条件为真。相当于IF NOT 条件表达式,与IF伪指令恰恰相反。l 上述表达式不能包含向前引用(还不能明确这个意思

24、。),其结果应为一常数值。一般为关系表达式或常数表达式c. 伪指令IFDEF和IFNDEF1) 一般格式:1. IFDEF(IFNDEF)符号2. 语句组13. ELSE4. 语句组25. ENDIF6. ;示例1:7. IFDEFMLARGE8. AXINCPROCFAR;如果MLARGE已被定义,那么将AXINC过程定义为远过程。9. ELSE10. AXINCPROCNEAR;否则,将AXINC定义为近过程11. ENDIF12. incax13. ret14. AXINCENDP2) 说明:l 伪指令IFDEF:如果符号已定义 或已被说明为外部符号(EXTRN伪指令进行说明),则条件满

25、足,即条件为真。l 伪指令IFNDEF:如果符号未定义或未被说明成外部符号,则条件满足,即条件为真。又是一对儿相反的伪指令。l 符号可以在源程序中定义,也可以在汇编命令行中定义,后者参阅汇编器使用手册。d. 伪指令IF1和IF21) 一般格式:1. IF1(IF2)2. 语句组13. ELSE4. 语句组25. ENDIF6. ;决定汇编程序在第几趟扫描时,汇编语句组。2) 说明:l 伪指令IF1:若是第一趟则为真l 伪指令IF2:若是第二趟则为真3. 条件汇编与宏结合a. 宏中使用条件汇编1) 条件汇编与宏结合,能大大扩大宏的使用范围。2) 以下为一示例:1. ADDNUMMACROREG,

26、 NUM;定义一个宏2. IF(NUM GT 2) OR (NUM LE 0);3. addREG, NUM4. ELSE5. incREG6. IFNUM EQ 27. incREG8. ENDIF9. ENDIF10. ENDM;退出宏3) 说明:l 以上示例的说明:宏ADDNUM有两个参数,在对宏调用进行扩展时,可以根据实际参数的不同扩展成不同的指令!l 宏,只有当被调用时,才会在被调用的内存空间,进行宏的展开;既然已经被调用,那么肯定已经有参数向其传递了,所以,条件汇编指令中才能根据参数进行一些判断,而决定展开后的命令!l 根据以上的道理来看,汇编语言提供了有关测试宏参数的条件汇编伪指

27、令,这更加便利了我们将宏与条件汇编语句相结合!b. 用于测试宏参数的条件汇编伪指令1) 伪指令IFB和IFNBl 以下为一般格式:1. IFB<参数>2. IFNB<参数>3. ;以下为一示例:4. PRINTMACROMSG;该宏的作用:当给定实参(偏移地址)时,显示指定的字符串,当未给定实参时,使用默认实参,打印默认信息。5. IFB<MSG>6. movsi, DEFAULTMSG7. ELSE8. movsi, MSG9. ENDIF10. CALLSHOWIT11. ENDM12. ;事实上,以上实现,并没有那么简单!以下是正确的实现方法!详情见注

28、释13. PRINT MACRO MSG14. LOCAL begin,DEFAULTMSG;所有在宏中定义的标号都必须使用LOCAL声明,如果你向多次使用该宏的话15. jmp begin16. DEFAULTMSG: DB "No Given Message!",0DH,0AH,'$'为了使得用户使用宏时,不用再自定义默认消息,我们这里才宏中定义一个默认字符串17. begin: push ds18. push dx19. push ax;要注意保护寄存器!20.21. IFB <MSG>IFB后面的形参必须用尖括号括起来,这里的尖括号并不是

29、字符串原样输出运算符!22. mov ax, cs;默认字符串的段,并非程序的数据段,而是代码段!23. mov ds, ax24. mov ah, 09H25. mov dx, OFFSET DEFAULTMSG26. ELSE27. mov ah, 09H28. mov dx, OFFSET MSG29. ENDIF30. int 21H31. pop ax32. pop dx33. pop ds34. ENDMl 这两条伪指令一般都用于宏定义体内部。l 伪指令IFB:如果在宏调用时,没有实参来代替形参,也就是没有实参,那么条件满足。l 伪指令IFNB:如果在宏调用时,有实参来代替形参,也

30、就是有实参,那么条件满足l 又是一对条件相反的指令。2) 伪指令IFIDN和IFDIFl 一般格式:1. IFIDN<参数1>,<参数2>2. IFIDNI<参数1>,<参数2>3. 4. IFDIF<参数1>,<参数2>5. IFDIFI<参数1>,<参数2>6. 7. ;以下为示例:8. ;示例1:9. RDWRMACROBUFF,RWMODE10. leadx, BUFF11. IFIDNI<RWMODE>,<READ>如果宏参数,读写模式字符与READ一致,则汇编调用

31、读功能子程序部分12. callREADIT13. ENDIF14. IFIDNI<RWMODE>,<WRITE>如果宏参数,读写模式与WRITE一致,则汇编调用写功能子程序部分。15. callWRITEIT16. ENDIF17. ENDM18. ;示例2:19. GETCHMACROCHAR20. movah, 121. int21H22. IFNB<CHAR>23. IFDIFI<CHAR>,<AL>24. movCHAR, AL25. ENDIF26. ENDIF27. ENDMl 这两条指令一般都用在宏定义体内部。l 伪指

32、令IFIDN(IFIDNI):如果字符串参数1与字符串参数2相等,则条件满足;后面添加的I是忽略大小写的意思!l 伪指令IFDIF(IFDIFI):如果字符串参数1与字符串参数2不相等,则条件满足。l 参数1和参数2:有可能是宏的形参,如果是形参,则比较之前,需先用实参进行替换后,再比较。如果不是宏的形参,则直接比较即可。l 参数一定是字符串,不需要添加引号,字符串会逐个比较大小;每一条指令都有两种格式,普通格式时,大小写有区别;+I格式时,大小写没有区别。并且该字符串一定是手动输入到源代码中的!Intel汇编语言程序设计1. 概述a. 宏过程(macro procedure):命名语句块;可

33、被调用多次;调用时,宏的副本被直接插入到程序中b. 宏过程可以必须声明在调用宏过程之前,或者声明在单独的文本文件中,通过INCLUDE包含之。c. 汇编器在预处理阶段处理宏的展开。d. 在80X86汇编语言程序设计教程一书中同样有关于宏的内容2. 宏的定义a. 方法:使用MACRO和ENDM伪指令在源程序的任意位置定义宏。b. 定义格式:1. macronameMACROparameter-1, parameter-22. statement-list3. ENDM4. ;建议对宏的名字(macroname)和ENDM之间的语句进行缩进5. ;statement-list即语句列表在宏被调用的

34、时候才会被汇编;6. ;宏的定义中可以有任意多的参数,参数之间用逗号间隔c. 宏的参数1) 宏的参数实际上是有名字的容器,以存放调用者传递给宏的文本参数。2) 说明:l 宏参数可以是整数、变量名、寄存器名等等l 预处理器把各种参数统一视为文本进行处理l 宏的参数没有类型,因此预处理器并不检查实参的类型是否与形参的类型匹配,如果不匹配,则会在汇编时由汇编器检查。3) 示例:1. mPutcharMACROchar2. pusheax3. moval, char4. callWriteChar5. popeax6. ENDM3. 宏的调用a. 宏的调用:将宏的名字插入到需要调用宏的源码中,并连接必

35、要的参数,即完成宏的调用。b. 格式:1. 宏名称参数1,参数22. ;其中宏名称必须是宏被调用前已经在源代码中定义号的宏的名字3. ;宏调用时每个实际参数都是一个文本值。4. ;实际参数的顺序必须按照宏定义时的参数顺序5. ;实际参数的数目不一定与形参的数目一致:6. ;当传递的参数多于定义中的形参个数时,汇编器产生一个警告;7. ;当传递的参数少于定义中的形参个数时,那么未传递的参数用空参数表示。c. 说明:1) 宏代码的执行速度块于过程代码执行,使用宏代码可以减少程序在时间上的开销。2) 重复使用大量的宏,会导致程序源代码和程序体积增大4. 宏的其他特性a. 必须参数1) REQ修饰符可

36、以指定宏的某个或某几个参数是必须的,如果在宏展开中没有获得与之对应的实参,则显示一条错误信息。2) 示例:1. mPutCharMACROchar:REQ;注意这样的修饰方法2. pusheax3. moval, char4. callWriteChar5. popeax6. ENDMb. 宏的注释1) 宏定义中如果有普通注释,则每次展开时都会将该注释一起展开。为了避免这样,利用双分号写宏注释,则不会展开。2) 示例:1. mPutCharMACROchar:REQ2. pusheax;注意保护寄存器3. moval, char4. callWriteChar5. popeax6. ENDMc

37、. ECHO伪指令1) 汇编器汇编源码的过程中,ECHO伪指令可以在控制台显示一条消息。2) 示例:1. mPutcharMACRO char:REQ2. ECHO“Expanding the mPutchar macro!”3. pusheax4. moval, char5. callWriteChar6. popeax7. ENDM3) 注意:l 显示消息是在汇编过程中!而不是在程序执行过程中l 显式的字符串不需要添加双引号,否则会连同双引号一同输出。d. LOCAL伪指令1) 问题:宏定义中如果使用了标号,在多次调用之后,标号在宏展开后的源代码中便会多次出现,导致符号重定义的错误!2)

38、使用LOCAL伪指令可以完美解决上述问题:3) 使用方法:1. makeStringMACROtext2. LOCALstring3. .data4. stringBYTEtext,05. ENDM6. ;另一个例子:7. AgainMACRO8. LOCALloop09. movecx, 1010. loop0:11. inceax12. looploop013. ENDM4) LOCAL后可以跟多个标号,标号之间用逗号间隔e. 包含代码和数据的宏1) 一般方法:在宏定义中,同时定义一个数据段和一个代码段,即完成了包含数据和代码的操作。2) 示例:1. mWriteMACROtext2. L

39、OCALstring3. .data4. stringBYTEtext,05. .code6. pushedx7. movedx, OFFSET string8. callWriteString9. popedx10. ENDMf. 宏的嵌套1) 在另外一个宏内被调用的宏称为嵌套宏(nested macro)2) 尽量使用模块化的方法创建宏,保持每个宏的简短,以便用于创造更复杂的宏,这样做有助于减少程序中的重复代码。3) 示例:1. mWriteLnMACROtext2. mWritetext;宏mWrite已经在上一段代码中定义过了3. callCrlf4. ENDM5. 使用本书附带的宏库

40、a. 大概1) .inc文件是文本文件,即包含文件,我们可以将很多宏定义在一个独立的文本文件中,然后在需要调用它们的源代码文件中包含该文件即可!2) 本节所罗列的所有宏:宏的名字参数描述mDumpvarName,useLabel显示一个变量,使用变量名及变量的默认属性mDumpMemaddress,itemCount,componentSize显示一块内存的内容mGotoxyx,y设置控制台缓冲区中光标的位置mShowvarName从键盘读取一个字符串mReadStringitsName,fomat以多种格式显示一个变量或寄存器mShowRegisterregName,regValue显示一个

41、32位的寄存器的名字及其内容,以十六进制格式mWritetext在控制台窗口中显示一个字符串mWriteSpacecount在控制台窗口中显示一个或多个空格mWriteStringbuffer在控制台窗口中显示一个字符变量的内容b. mDumpMem1) 功能描述:在控制台窗口显示一块内存的内容2) 参数解释:l 第一个参数包含要显示的内存偏移地址的常量、寄存器或变量l 第二个参数:要显示的项目的数量l 第三个参数:单个项目的字节数,该参数也指明了最后显示结果的形式!3) 实现1. mDumpMemMACROaddress:REQ,itemCount:REQ,componentSize:REQ

42、2. pushebx3. pushecx4. pushesi5. movesi, address6. movecx, itemCount7. movebx, componentSize8. callDumpMem9. popesi10. popecx11. popebx12. ENDMc. mDump1) 功能描述:以十六进制格式显示变量的地址和内容2) 参数解释:l 第一个参数:变量的名字l 第二个参数:(可选的)传递一个字符Y或者是N表示是否显示变量的名字3) 实现1. mDumpMACROvarName:REQ, useLabel2. callCrlf3. IFNB<useLabe

43、l4. mWrite “Variable name: &varName”5. ENDIF6. mDumpMemOFFSET varName,LENGTHOF varName,TYPE varName7. ENDMd. mGotoxy1) 功能描述:把光标定位在屏幕上指定的位置2) 参数解释:l 第一个参数:Xl 第二个参数:Y,X和Y可以是8位的立即数或内存操作数或寄存器3) 实现1. mGotoxyMACRO X:REQ,Y:REQ2. pushedx3. movdh, Y4. movdl, X5. callGotoxy6. popedx7. ENDMe. mReadString1)

44、 功能描述:从键盘上读取一个字符串并把该字符串存储在一个缓冲区中2) 参数解释:l 第一个参数:缓冲区的名字,或者是存储缓冲区偏移地址的寄存器3) 实现1. mReadStringMACROvarName:REQ2. pushecx3. pushedx4. movedx, OFFSET varName5. movecx, SIZEOF varName6. callReadString7. popedx8. popecx9. ENDMf. mShow1) 功能描述: 以调用者选定的格式显示任意寄存器或变量的名字和内容2) 参数解释:l 第一个参数:寄存器或变量名l 第二个参数:输出参数:H =

45、十六进制 D = 无符号十进制整数 I = 有符号十进制整数 B = 二进制 N = 添加一个换行符 可以组合多种输出格式,也可以指定多个换行符默认格式:HIN3) 实现该宏的实现过长,该宏定义在Macros.inc包含文件中g. mShowRegister1) 功能描述:以十六进制格式显示一个32位寄存器的内容2) 参数解释:l 第一个参数:对于该寄存器要显示的名字,被用作字符串。l 第二个参数:该寄存器的名字,被用来取值3) 实现1. mShowRegisterMACROregName,regValue2. LOCAL tempStr3. .data4. tempStrBYTE“&

46、regName=”,05. .code6. pushedx7. movedx, OFFSET tempStr8. callWriteString9. popedx10. 11. moveax, regValue12. callWriteHex13. popeax14. ENDMh. mWriteString1) 功能描述:在控制台窗口显示一个字符串的内容2) 参数解释:l 第一个参数:字符串名3) 实现1. mWriteStringMACRO buffer:REQ2. pushedx3. movedx, OFFSET buffer4. callWriteString5. popedx6. EN

47、DMi. mWriteSpace1) 功能描述:在控制台窗口显示一个或多个空格2) 参数解释:l 第一个参数:一个数字,指定空格的数量,默认个数是13) 实现1. mWriteSpaceMACROcount:=<1>默认实参的写法2. LOCAL spaces3. .data4. spacesBYTEcount DUP( ),05. .code6. pushedx7. movecx, OFFSET spaces8. callWriteString9. popedx10. ENDM6. 例子程序:封装10.3 条件汇编伪指令 与 宏0.前言a. 条件汇编伪指令和宏联合使用可以使得宏更

48、加灵活。b. 本节看似在讲述关于条件汇编伪指令的相关内容,但是无不联系了宏的应用!c. 一般格式1. IFcondition2. statement3. ELSE4. statement5. ENDIFd. 本章介绍的是:常量条件伪指令;6.7节介绍的是:运行时伪指令e. 条件汇编伪指令概况伪指令说明IF 表达式如果表达式为真(非0)则允许汇编。可以使用的相关操作符有LT,GT,NE,LE,GEIFB<参数>如果参数为空则允许汇编,参数名必须用尖括号(<>)括起来IFNB<参数>如果参数不为空则允许汇编,参数名必须用尖括号括起来IFIDN<参数1>

49、;,<参数2>如果两个参数相同则允许汇编,参数比较是大小写敏感的IFIDNI<参数1>,<参数2>如果两个参数相同则允许汇编,参数比较是不区分大小写的。IFDIF<参数1>,<参数2>如果两个参数不同则允许汇编,参数比较是大小写敏感的。IFDIFI<参数1>,<参数2>如果两个参数不同则允许汇编,参数比较是不区分大小写的。IFDEF 名字如果名字已经定义则允许汇编IFNDEF 名字如果名字未定义则允许汇编ENDIF结束一个条件汇编伪指令开始的语句块ELSE如果前面的条件汇编伪指令的条件均为假,则汇编该伪指令至E

50、NDIF伪指令之间的语句ELSEIF 表达式如果前面的条件汇编伪指令的条件均为假,则汇编该伪指令至下一条汇编伪指令之间的语句EXITM立即退出宏,组织其后任何语句的展开1. 检查缺少的参数(介绍使用了IFB条件汇编伪指令的用途!)a. 宏可以通过条件汇编伪指令检查其任何一个参数是否为空。b. 背景:当宏的用户使用宏,某个参数为空时,有可能生成错误的指令,在汇编时产生错误。为了减少宏的用户产生此类错误,需要检查缺失参数,并做防范措施。c. 示例:1. mWriteStrMACRO string2. IFB<string>当用户未提供参数时,在预处理阶段就显示出错信息,并不展开宏3. ECHO -4. ECHO * Error: parameter missing in mWriteStr5. ECHO * (no code generated)6. ECHO -7.

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论