1、10.3 条件汇编伪指令条件汇编伪指令条件汇编伪指令的一般格式:IF condition statements ELSE statements ENDIF 当condition为真时,允许汇编statements中的语句。条件汇编伪指令条件汇编伪指令伪指令说明IF 表达式如果表达式为真则允许汇编。IFB 如果参数为空则允许汇编,参数名必须用括起来IFNB 如果参数不为空则允许汇编,参数名必须用括起来IFIDN,如果两个参数相同则允许汇编,参数区分大小写IFIDNI,如果两个参数相同则允许汇编,参数不区分大小写IFDIF,如果两个参数不同则允许汇编,参数区分大小写IFDIFI,如果两个参数不同则
2、允许汇编,参数比区分大小写IFDEF 名字如果名字已经定义则允许汇编IFNDEF 名字如果名字未定义则允许汇编ENDIF结束一个条件汇编伪指令开始的语句块ELSE如果前面的条件均为假,则汇编该伪指令至ENDIF之间的语句EXITM立即退出宏,阻止其后任何语句的展开立即退出宏,阻止其后任何语句的展开检查缺少的参数检查缺少的参数mWriteStr MACRO string IFB ECHO-ECHO*Error:parameter missing in mWriteStr ECHO*(no code generated)ECHO-EXITM ENDIF push edx mov edx,OFFSE
3、T string call WriteString pop edxENDM 默认的参数初始化值默认的参数初始化值定义宏时可以有默认的参数初始化值,如果调用宏时未给出参数,则编译器使用默认参数值。格式为:paramname:=例如:为mWriteLn宏提供一个空格作为默认的参数:mWriteLn MACRO text:=mWrite text call Crlf ENDM 如果调用时不带参数,那么仍然会打印一个空格并在后面跟一个换行符。布尔表达式布尔表达式编译器允许在常量布尔表达式中使用以下关系运算符:LT 小于 GT 大于 EQ 等于 NE 不等于 LE 小于等于 GE 大于等于IF,ELSE
4、和ENDIF伪指令格式为:IF expression statement-list ENDIF或:IF expression statement-list ELSE statement-list ENDIF IF伪指令后面必须跟一个常量布尔表达式。表达式可以包含常量、符号常量或宏参数常量,但不能是寄存器或变量名。例子:mGotoxyConst宏 mGotoxyConst宏使用LT和GT操作符对传递给宏的参数进行范围检查,参数X和Y必须是常量。另一个常量ERRS用于统计发现的错误数。IFIDN和IFIDNI伪指令IFIDN伪指令以区分大小写的方式比较两个符号(包括宏参数)是否相等,如果相等则返回
5、TRUE。IFIDNI伪指令则不区分大小写。格式为:IFIDN,statements ENDIFmReadBuf MACRO bufferPtr,maxchars IFIDNI,ECHO Warning:second argument to mreadbuf cannot be edx ECHO*EXITM ENDIF push ecx push edx mov edx,bufferPtr mov ecx,maxchars call ReadString pop edx pop ecxENDM下面的语句将导致宏产生一条错误信息:mReadBuf OFFSET buffer,edx 例如:下面的
6、mReadBuf宏中,第二个参数不能是EDX,因为buffer的偏移被送到EDX时,参数会被覆盖。例子:对矩阵行求和例子:对矩阵行求和定义宏mCalc_row_sum mCalc_row_sum MACRO index,arrayOffset,rowSize,eltType LOCAL L1 mov eax,index mov ebx,arrayOffset mov ecx,rowSize mul ecx add ebx,eax shr ecx,(TYPE eltType/2)mov eax,0 mov esi,0L1:IFIDNI,mov edx,eltType ptrebx+esi*(TY
7、PE eltType)ELSE movzx edx,eltType ptrebx+esi*(TYPE eltType)ENDIF loop L1ENDM特殊操作符特殊操作符&替换操作符文本操作符!特殊字符操作符%展开操作符替换操作符&将宏的内部对宏参数的引用替换为调用时的实际值。ShowRegister MACRO regName LOCAL tempStr .data tempStr BYTE “®Name=”,0 .code push eax push edx mov edx,offset tempStr call WriteString mov eax,regName call W
8、riteHex pop edx pop eax ENDM当程序中出现宏调用语句:ShowRegister ECX则宏调用的输出为:ECX=00000101展开操作符%展开文本宏并把常量表达式转换成文本。在与用TEXTEQU联合使用时,%操作符对常量表达式求值并将结果转化成整数。例1:count=10 sumVal TEXTEQU%(5+count);=“15”例2:mGotoxyConst%(5*10),%(3+4)调用宏时,两个表达式分别被求值并作为参数传递行首的行首的%当%作为源代码行的第一个字符时,预处理器将展开在该行发现的所有文本宏和宏函数。例子:.data array DWORD 1
9、,2,3,4,5,6,7,8 TempStr TEXTEQU%(SIZEOF array).code%ECHO The array contains TempStr bytes 产生的输出为:The array contains 32 bytes文本操作符 将多个字符或符号作为一个字符串进行传递。例如,本章前面的宏只接收一个唯一的字符串参数,如果传递以下字符串,预处理器将解释为三个参数:mWrite “Line three”,0dh,0ah如果用文本操作符将字符串括起来,预处理器会将文本操作符里面的所有字符都作为单个宏参数进行传递:mWrite 特殊字符操作符!强制预处理器将预定义的操作符作为
10、原始字符进行传递。例如:BadYValue TEXTEQU 24操作符的结合使用操作符的结合使用BadYValue TEXTEQU 24ShowWarning MACRO message mWrite “&message”ENDM则以下的宏调用:.code ShowWarning%BadYValue将产生如下结果:Warning:Y-coordinate is 24 先替换后展开先替换后展开宏函数宏函数与宏过程类似,宏函数也是一个命名的汇编语句块,唯一的不同在于,宏函数总是用EXITM伪指令返回一个常量值(整数或字符串)。例如:IsDefined MACRO symbol IFDEF symb
11、ol EXITM ;True ELSE EXITM ;False ENDIF ENDM调用宏函数:调用宏函数时参数列表必须用圆括号括起来。例如:调用IsDefined宏,并向它传递一个已经或尚未定义的参数RealMode:IF IsDefined(RealMode)mov ax,data mov ds,ax ENDIF 如果编译器在编译该语句之前已经遇到了RealMode的定义,则编译后面两条语句。10.4 定义重复块定义重复块 WHILE伪指令 REPEAT伪指令 FOR伪指令 FORC伪指令 链表 MASM中的重复块伪指令只能用于编译期间,而且只中的重复块伪指令只能用于编译期间,而且只能使
12、用常量值作为循环条件和计数器。能使用常量值作为循环条件和计数器。WHILE伪指令根据一个布尔表达式来重复语句块 REPEAT伪指令根据一个计数器来重复语句块 FOR伪指令通过遍历一个符号列表中的每个符号来重复语句块 FORC伪指令通过遍历一个字符串中的每个字符来重复语句块WHILE伪指令伪指令格式如下:WHILE constExpression statements ENDM 只要常量表达式constExpression的值为真,WHILE伪指令就重复语句块。例如:以下代码显示了如何生成1到F0000000h之间的斐波那契数作为一系列编译时期的常量。.dataval1=1val2=1DWORD
13、 val1DWORD val2val3=val1+val2WHILE val3 LT 0F0000000h DWORD val3 val1=val2 val2=val3 val3=val1+val2ENDMREPEAT伪指令伪指令REPEAT伪指令以固定次数重复指令块。格式为:REPEAT constExpression statements ENDM constExpression是一个无符号整数常量表达式,它决定了重复次数。例如:以下的REPEAT循环创建了包含100个双字的数组并用数列10,20,30,40,1000对其进行初始化:ival=10 REPEAT 100 DWORD iva
14、l ival=ival+10 ENDMFOR伪指令伪指令FOR伪指令通过遍历一个以逗号分隔的符号列表重复语句块,符号列表中的每个符号都引发一次循环。格式如下:FOR parameter,statements ENDM 第i次循环时,参数parameter被赋值为argiFORC伪指令FORC伪指令通过遍历一个字符串中的每个字符来重复语句块,字符串中的每个字符都引发一次循环。格式如下:FORC parameter,statements ENDM 第i次循环中,参数parameter等于字符串string中的第i个字符。例如:Delimiters LABEL BYTE FOR code,#$%&*
15、!BYTE“&code”ENDM将生成以下数据:00000000 40 1 BYTE “”00000001 23 1 BYTE “#”00000002 24 1 BYTE “$”00000003 25 1 BYTE “%”00000004 5E 1 BYTE “”00000005 26 1 BYTE “&”00000006 2A 1 BYTE “*”00000007 3C 1 BYTE “”链表链表每个节点的数据区内可以使用一个或多个变量存放节点的数据。在链接区中,用一个指针包含和链表相邻的下一节点的地址。最后一个节点的链接区通常包含一个空指针。datalinddatalinddatalind
16、NULL例子:首先创建一个链表节点类型,该类型包含一个整数(数据区)和一个指向下一个相邻节点的指针(链接区):ListNode STRUCT NodeData DWORD?NextPtr DWORD?ListNode ENDS接着使用REPEAT伪指令创建ListNode对象的多个实例:TotalNodeCount=15NULL=0Counter=0.dataLinkedList LABEL DWORDREPEAT TotalNodeCount Counter=Counter+1 ListNode ENDMListNode$总是返回第一个节点的地址对于链表中节点的遍历,往往采用间接操作数,并结合PTR操作符进行:如:(ListNode PTR esi).NodeData (ListNode PTR esi).NextPtr程序清单:P318