汇编语言-课件_第1页
汇编语言-课件_第2页
汇编语言-课件_第3页
汇编语言-课件_第4页
汇编语言-课件_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

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

文档简介

汇编语言数学科学学院计算机应用技术专业

第10章结构和宏结构结构(structure)是逻辑上相互关联的一组变量的模板和模式,结构中的单个变量称为域(field)。程序语句可以将结构作为单个实体进行访问,也可以对单个域进行访问。结构是程序过程之间传递大量数据的基本工具。例子:Windows程序库使用COORD结构来确定屏幕坐标X和Y。在该结构中,域X相对结构开始的偏移是0,域Y的偏移是2。

COORDSTRUCT XWORD? YWORD? COORDENDS结构的使用包含三个按顺序的步骤:

1、定义结构; 2、声明一个或多个该结构类型的变量,称为结构变量(structurevariables); 3、写运行时指令访问结构的域。定义结构可以使用STRUCT和ENDS伪指令来定义结构。在结构内部,使用与定义普通变量一样的格式来定义域。基本格式如下所示:

名字STRUCT 域的声明 名字ENDS结构中可包含任意数量的域。域的初始化如果为结构的域提供初始化值,在定义结构变量时这些初始化值就成了域的默认值,结构中可使用多种类型的初始化值:未定义:使用问号(?)表示域内容未定义。字符串:用引号(“”,’’)引起的字符初始化字符串域。整数:使用整数常量或整数表达式初始化整数域。数组:当域是一个数组时,使用DUP操作符初始化数组元素。EmployeeSTRUCT IdNum BYTE“000000000” LastName BYTE30DUP(0) Years WORD0 SalaryHistoryDWORD0,0,0,0EmployeeENDS可以插入逗号作为占位符以忽略掉对结构中某些域的初始化。例如,下面的语句忽略了IdNum域并初始化LastName域:

person3Employee<,”Jones”>如果某个域包含一个数组,可以使用DUP操作符初始化某些或全部数组元素,如果初始化值比域短,那么剩余位置将用0填充。例如,下面的语句初始化SalaryHistory的前两个值并将其余设为0:

person4Employee<,,,2DUP(20000)>可以像下例一样声明结构数组,其中AllPoints的每个元素都被初始化为<0,0>: NumPoints=3 AllPointsCOORDNumPointsDUP(<0,0>)循环遍历数组使用间接寻址或变址寻址来操纵结构数组时通常要使用循环。例子:AllPoints.asm。例子:显式系统时间(ShowTime.asm)。结构的嵌套当要在一个结构中包含其他结构时,我们可以创建嵌套结构定义(nestedstructuredefinitions)。例如一个Rectangle结构可以由屏幕左上角和右下角的坐标来定义,这二者都是COORD对象:RectangleSTRUCT UpperLeftCOORD<> LowerRightCOOED<>RectangleENDS Rectangle变量声明的时候可以没有初始化值,也可以重写单个COORD域,下面是几种可选的格式:rect1Rectangle<>rect4Rectangle<<10,10>,<50,20>>下面是对嵌套结构域的直接引用: movrect1.UpperLeft.x,10也可以使用间接操作数来访问嵌套域。下例中,我们将结构中左上角的Y坐标赋值为40,该结构由ESI寻址:movesi,OFFSETrect1mov(RectanglePTR[esi]).UpperLeft.Y,10OFFSET操作符可用于返回指向单个结构域的指针,其中包括嵌套域:

movedi,OFFSETrect2.LowerRight mov(COORDPTR[edi]).x,50 movedi,OFFSETrect2.LowerRight.x movWORDPTR[edi],50例子:醉汉走路(Drunkard’sWalk)。联合的声明和使用结构的每个域都有一个相对于结构第一个字节的偏移值,但联合的情况有所不同,联合(union)中的所有域都从同一偏移地址开始。联合的大小等于其中最长的域的长度。当联合不是某个结构的成员时,它的格式是使用下面的UNION和ENDS伪指令来声明的:unionnameUNION union-fieldsunionnameENDS如果联合嵌套在结构中,则格式稍有不同:structnameSTRUCT structure-fields UNIONunionname union-fields ENDSstructnameENDS除了只能有一个初始化值这一点之外,联合域的声明方法与结构域的声明方法完全相同。例如,Integer联合为同一数据定义了三种不同的尺寸属性:IntegerUNION DDWORD 0 WWORD 0 BBYTE 0IntegerENDS通过在结构声明中使用联合名可将联合嵌套在结构内,可以直接在结构内声明联合。FileInfoSTRUCT FileIDInteger<> FileNameBYTE64DUP(?)FileInfoENDSFileInfoSTRUCT UNIONFileID DDWORD 0 WWORD 0 BBYTE 0 ENDS FileNameBYTE64DUP(?)FileInfoENDS声明和使用联合变量联合变量的声明和初始化与结构变量大致相同,只有一点重要的区别:联合只允许一个初始化值。下面是Integer类型的变量的例子:val1Integer<12345678h>val2Integer<100h>val3Integer<>在执行指令中使用联合时必须提供多个不同域名字中的一个。下面例子将寄存器值赋给Integer联合的域,注意由于可以使用不同大小的操作数而获得的灵活性:movval3.B,almovval3.W,axmovval3.D,eax联合中也可以包含结构。例如:INPUT_REC_STRUCT。宏宏过程(macroprocedure)是一个命名的汇编语句块。一旦被定义之后,宏过程就可以在程序中被调用任意多次。调用宏过程的时候,汇编语句块的一份拷贝被直接插入到程序中。我们要么直接在程序中编写宏(通常在最开始),要么将它放在单独的文本文件中,对于后者要使用INCLUDE伪指令使之在编译时被插入源程序。编译器在试图编译任何调用宏的语句前必须首先找到宏的定义,编译器的预处理器扫描宏并将它们放在一个缓冲区中,当发现对宏的调用时,就将宏调用替换成宏的一份拷贝。一般地,宏执行得比过程快,因为过程有额外执行CALL和RET指令的开销。但使用宏也有一个缺点:大量使用宏会增大程序的体积,因为对宏的每次调用都要在程序中插入宏的一份新的拷贝。下面的NewLine宏只包含一条调用Crlf库过程的语句:NemLineMACRO callCrlfENDM 这个定义一般放在数据段之前,在接下来的代码段中,我们调用该宏:.codeNewLine 当预处理器扫描程序并发现对NewLine的调用时,就把宏调用替换成下面的语句:callCrlf 其中发生的一切只不过是文本的替换。就这个特殊的例子而言,我们也可以使用TEXTEQU伪指令完成同样的功能,但是后面很快将讲述如何向宏传递参数,这就使得宏比TEXTEQU伪指令药强大得多。宏的定义可以使用MACRO和ENDM伪指令在源程序的任意位置定义宏,定义格式为:macronameMACROparameter1,parameter2…ENDM statement-listMACRO和ENDM伪指令之间的语句直到宏被调用时才会被编译。宏的定义中可以有任意多的参数,参数之间用逗号分隔。必需参数可以使用REQ修饰符来指定一个宏参数是必需的,如果调用宏的时候没有参数与之匹配,编译器将显示一个错误。宏注释宏内的注释行通常以双分号(;;)开始。宏注释在定义宏时出现,但是在宏展开的时候并不出现。使用ECHO伪指令ECHO伪指令使程序被编译时在控制台上显示一条消息。下面版本的mPutchar中,编译过程中控制台上会显示“ExpandingThemPutcharmacro”消息:

mPutcharMACROchar:REQ ECHOExpandingthemPutcharmacro pucheax moval,char callWriteChar popeax ENDM宏的调用宏是通过将其名字插入到程序源代码中被调用的,宏名字后面可以跟必要的参数。调用宏的格式如下:宏名称参数1,参数2…宏名称(macroname)必须是在源代码调用之前就已经定义好的宏的名字,宏语句中引用的参数将被用参数1,参数2等指定的文本替换,实际参数的顺序必须与宏定义中的参数顺序相同,但实际参数的数目不一定非要与宏定义中参数的个数完全一致。如果传递的参数个数多于定义中的参数个数,编译器会发出一个警告;如果传递地参数个数少于宏定义中的个数,那么未传递的参数会被留为空白。调用mPutChar:mPutChar‘A’pusheax1 moval,’A’callWriteChar1 popeax左边的“1”表示宏展开的层次。LOCAL伪指令指示预处理器在mWrite宏每次展开时创建惟一的标号名,这避免了在同一文件内mWrite宏被调用两次展开时导致的名字冲突,下面的语句调用了两次mWrite宏,每次都传递了一个不同的字符串:mWrite“Pleaseenteryourfirstname”mWrite“Pleaseenteryourlastname”下面编译器对这两条语句的展开显示了每个字符串是如何使用不同的标号声明的:宏的嵌套有时使用模块化的方法来创建是很有益的,将每个宏保持短而简单,并用它们作为基本模块来构造更复杂的宏,这样可以(希望会)减少编写重复的代码。当一个宏中又调用了另一个宏时,我们称之为嵌套宏(nestedmacro)。使用嵌套宏真的没有任何缺点,因为预处理器会展开所有内层的宏,就像所有的语句都属于同一个宏一样。传给外层宏的参数可直接传递给内层的宏。例子程序:Wraps.asm。条件汇编伪指令将条件汇编伪指令和宏联合使用可以使宏的使用更加灵活,条件汇编伪指令的一般格式是:IFconditionstatement[ELSEstatements]ENDIF下表列出了一些常用的条件汇编伪指令,当说明中提到一条伪指令“允许汇编”的时候,就意味着其后直到下一个相邻的ENDIF之间的所有语句都会被编译,这里必须强调的是表中列出的伪指令是在编译时而不是在运行时求值的。条件汇编伪指令伪指令说明IF表达式如果表达式值为真(非0)则允许汇编。可以使用的相关操作符有LT,GT,EQ,NE,LE和GEIFB<参数>如果参数为空则允许汇编,参数名必须用尖括号(<>)括起来IFNB<参数>如果参数不为空则允许汇编,参数名必须用尖括号(<>)括起来IFIDN<参数1>,<参数2>如果两个参数相同则允许汇编,参数比较是大小写敏感的IFIDNI<参数1>,<参数2>如果两个参数相同则允许汇编,参数比较是不区分大小写IFDIF<参数1>,<参数2>如果两个参数不同则允许汇编,参数比较是大小写敏感的IFDIFI<参数1>,<参数2>如果两个参数不同则允许汇编,参数比较是不区分大小写IFDEF名字如果名字已经定义则允许汇编IFNDEF名字如果名字未定义则允许汇编ENDIF结束一个条件汇编伪指令开始的语句块ELSE如果前面的条件汇编伪指令的条件均为假,则汇编该伪指令至ENDIF伪指令之间的语句EXITM立即退出宏,阻止其后任何语句的展开检查缺少的参数宏可以检查其任何一个参数是否为空。通常,如果一个宏接收了空参数,预处理器展开宏的时候就会导致无效指令。为防止缺少参数产生的错误,可使用IFB(ifblank)伪指令,该伪指令在宏参数为空时返回真;也可以使用IFNB(ifnotblank)伪指令,它在宏参数非空时返回真。EXITM伪指令告诉预处理器退出宏,不要再展开宏中其后的语句。默认的参数初始化值宏可以有默认的参数初始化值。如果调用宏时缺少参数,则使用默认参数。格式如下所示:paramname:=<argument>例如为mWriteLn宏提供一个空格作为默认的参数,如果调用时不带参数,那么仍然会打印一个空格并在后面跟一个换行符。mWriteLnMACROtext:=<“”>mWritetextcallCrlfENDM如果使用空字符串(“”)作为参数,那么编译器会发出一个错误提示,所以至少要在两个引号之间插入一个空格。布尔表达式编译器允许在常量布尔表达式中使用下面的关系运算符:LT 小于GT 大于EQ 等于NE 不等于LE 小于等于GB 大于等于

IF,ELSE和ENDIF伪指令IF伪指令后面必须跟一个常量布尔表达式。表达式可包含整数常量、符号常量或宏参数常量,但是不能包含寄存器或变量名。其中的一种格式是只使用IF和ENDM:IFexpression statement-listENDIF 另一种格式是使用IF,ELSE和ENDIF:IFexpression statement-listELSE statement-listENDIF例子:mGotoxyConst宏。IFIDN和IFIDNI伪指令IFIDN伪指令也比较两个符号是否相等,但是要区分大小写。IFIDNI伪指令以大小写不敏感的方式比较两个符号(包括宏参数)是否相等,如果相等的话则返回TRUE。当要确保调用宏时传递的宏参数不和宏内使用的寄存器冲突时,IFIDNI是很有用的,它的使用格式是:IFIDNI<symbol>,<symbol>statementsENDIFIFIDN的格式与IFIDNI的格式相同。例子:mReadBuf宏。特殊操作符有4个特殊的汇编操作符可使宏的使用更加灵活:&替换操作符%展开操作符<>文本操作符!特殊字符操作符替换操作符(&)替换操作符(&)将宏的内部对宏参数的引用替换为调用时的实际值。展开操作符(%)展开操作符(%)展开文本宏或把常量表达式转换成文本表示形式。在与用TEXTEQU联合使用时,%操作符对常量表达式求值并将结果转化成整数。当展开操作符(%)作为源代码行的第一个字符的时候,就指示预处理器展开在该行发现的所有文本宏和宏函数。文本操作符(<>)文本操作符(<>)允许将多个字符或符号作为一个字符串进行传递,以阻止预处理器将<>内的参数解释为单独的参数。该操作符在字符串包含逗号(,)、百分号(%)、连接符(\)或分号(;)的时候特别有用,如果不使用该操作符,这些字符就会被解释成分隔符或其他操作符。特殊字符操作符(!)特殊字符操作符(!)的目的和文本操作符的目的几乎是一样的:强制预处理器将预定义的操作符作为原始字符传递。宏函数宏函数与宏过程相似,它们都为一块汇编语句赋予一个名字,所不同的是,宏函数总是用EXITM伪指令返回一个常量(整数或字符串)。下面的例子中,如果符号symbol已定义则IsDefined宏返回真(-1),否则返回假(0):

IsDefinedMACROsymbol IFDEFsymbol EXITM<-1> ;;True ELSE EXITM<0> ;;False ENDIF ENDM调用宏函数时参数列表必须用圆括号(())括起。例子:HelloNew程序。定义重复块MASM中有一些

温馨提示

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

最新文档

评论

0/150

提交评论