nullnull第4章 MASM汇编语言基础4.1 汇编语言语句种类及其格式
4.2 汇编语言数据
4.3 表达式与运算符
4.4 程序的段结构
4.5 其他常用伪指令
4.6 汇编语言上机调试
null Intel8086/8088系列微机的汇编程序MASM,是美国Microsoft公司开发较早的宏汇编程序,它不仅具有ASM的全部功能(支持基本汇编语言),而且增加了指令、结构、记录等高级宏汇编功能。
语句(Statement)是汇编语言源程序的基本组成单位。一个汇编语言源程序有三种基本语句:指令语句、伪指令语句、宏指令语句。第4章 MASM汇编语言基础§4.1 汇编语言语句种类及其格式null 每一条指令语句在汇编时都要产生一个可供机器执行的目标代码,这种语句也被称为可执行语句。指令语句的格式如图4.1所示:
图4.1 指令语句的格式§4.1 汇编语言语句种类及其格式(续)§4.1.1 指令语句null一条指令语句有如下4个字段:
1.标号字段
这是一个可选字段。标号必须以“:”作为结束符。一个标号是一条指令的符号地址,它代表该指令的第一个字节的地址。
2.指令助记符字段
这是一条指令中不可缺少的主要成分。它表示这条语句要求CPU完成什么操作。
§4.1.1 指令语句(续)null3.操作数字段
按照指令助记符字段要求,指令语句可以有一个操作数、两个操作数或无操作数。
4.注释字段
这是一个可选字段,注释字段必须以分号“;”为开始,它可以方便程序设计人员对程序或指令加以注释,提高程序的的可读性。
§4.1.1 指令语句(续)null§4.1.2 伪指令语句 与指令语句不同的是,伪指令本身不产生与之对应的目标代码。它是在汇编程序对汇编语言源程序汇编期间,由汇编程序处理的操作,它们可以完成如数据定义、分配存储区、指示程序结束等功能。 §4.1 汇编语言语句种类及其格式(续)null图4.2 伪指令语句的格式一条伪指令语句也有如下4个字段:
1.符号名字段
这是一个可选字段。符号名后面不得用冒号“:”,这是它与指令语句突出的一个区别。§4.1.2 伪指令语句(续)null§4.1.2 伪指令语句(续)2.伪指令字段
这是伪指令语句中不可省略的主要成分。它们是伪指令语句要求汇编程序完成的具体操作命令。3.操作数字段
本字段是否需要,需要几个,需要什么样的操作数等都由伪指令字段中伪指令来确定。4.注释字段
这是一个任选字段,它必须以分号为开始,它的作用与指令语句的注释字段相同。null§4.2.1 常量
凡是出现在8086源程序中的固定值(即在汇编期间,它的值已经能够完全确定,在程序运行期间,它的值也不会发生任何的变化),就称为常量。 §4.2 汇编语言数据通常汇编语言能识别的数据有:常量、变量和标号。null1.十进制常量:0~9数字序列,可以用字母D结尾,也可没有结尾字母;
2.二进制常量:以字母B结尾的0和1组成的数字序列;
3.八进制常量:以字母O或Q结尾的0~7数字序列;
4.十六进制常量:以字母H结尾的0~9和A~F(或a~f)的数字字母序列。
5.字符串常量:用单引号或双引号括起来的一个或多个字符,这些字符用它的ASCII码值存储在内存中。§4.2.1 常量(续)null 变量就是用来表示程序中所用的内存操作数。1.定义
格式:[变量名] 类型助记符 操作数[,操作数,……]
其中变量名字段是可有可无的,它用于指示内存操作数的地址(符号地址);操作数字段用于指示内存操作数,汇编程序将定义的内存操作数,按其类型分配内存§4.2.2 变量nullDQ伪指令用来定义四个字,其后的每个操作数都占有四个字;§4.2.2 变量(续)常用的有以下几种:DB伪指令用来定义字节,其后的每个操作数都占有一个字节;DW伪指令用来定义字,其后的每个操作数都占有一个字(低位字节存放在低地址,高位字节存放在高地址);DD伪指令用来定义双字,其后的每个操作数都占有两个字;null(1)段属性SEG
它表示变量存放在哪一个逻辑段中。
(2)偏移量属性OFFSET
表示变量在逻辑段中离段起始点的字节距离。(3)类型属性TYPE
表示变量占用存储单元的字节数,它由类型助记符DB、DW、DD、DQ来规定。§4.2.2 变量(续)2.变量的三个属性null它们通常有以下几种情况:
(1)数值表达式:表示内存操作数的初始值,其值应在其定义的类型范围内。
如:xx DB 1,-1
yy DW 2*16,-1
(2)表达式:不带引号的?表示可预置任何
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
。3.预置初值§4.2.2 变量(续)null 对于DB伪指令,为字符串中每个字符分配一个字节单元。字符串必须是引号括起来的不超过255个字符。
对于DW伪指令,可以给两个字符组成的字符串分配两个字节的存储单元,而且这两个字符的ASCII码的存储顺序是前一个字符在高字节,后一字符在低字节。每一个数据项只能是1~2个字符。
(3)字符串表达式3.预置初值(续)null对于DD伪指令,仅可给两个字符组成的字符串分配4个字节的单元,且这两个ASCII码是存储在两个低字节(存储顺序与DW伪指令相同)中,两个高字节均存放00H。 (4)带DUP表达式:DUP是定义重复数据操作符,在操作数部分的格式为:
重复次数 DUP(重复的内容)(3)字符串表达式(续)3.预置初值(续)null(1)在指令语句中,如果要对某存储单元进行存取操作,就可直接引用它的变量名。
(2)在伪指令语句中:定义变量时引用了另一个变量,则这个变量的内容均是被引用变量的逻辑地址。如用DW,则仅有偏移量,如用DD则前两个字节存放偏移量,后两个字节存放段地址;注意不能用DB引用变量名。§4.2.2 变量(续)4.变量的使用null 2.标号的三个属性:
(1)段属性:表示这条指令的目标代码在哪个逻辑段中;
(2)偏移量属性:表示这条指令目标代码的首字节在段内离段起始点的字节距离;
(3)距离属性(或类型属性) §4.2.3 标号(Label)1.定义:
标号是一条指令目标代码的符号地址,它常作为转移指令或调用指令的操作数。null§4.3.1 算术运算符
算术运算符有+(加)、-(减)、*(乘)、/(整除)、MOD(求余),参加运算的数和运算结果均是整数。 §4.3.2 逻辑运算符
逻辑运算符有4个:AND(与)、OR(或)、NOT(非)和XOR(异或),参加运算的数和运算的结果均是整数,逻辑运算是按位进行的。
§4.3 表达式与运算符null 这6个关系运算符分别是:GT(大于)、GE(大于等于)、LT(小于)、LE(小于等于)、EQ(等于)、和NE(不等于)。它们用于比较两个表达式,表达式一定是常数或同段内的变量。若是常数,按无符号数比较;若是变量则比较它们的偏移量。比较的结果为以真,表示为全1;结果为假,表示为全0。§4.3 表达式与运算符(续)§4.3.3 关系运算符null1.SEG
格式:SEG 变量名或标号
当运算符SEG加在一个变量名或标号前面时,汇编程序回送的运算结果是这个变量或标号所在的段的段基址;§4.3 表达式与运算符(续)§4.3.4 数值返回运算符 数值返回运算符有5个,分别是:SEG、OFFSET、TYPE、LENGTH和SIZE。这种运算符的对象必须是存储器操作数,即变量名或标号,通过运算后返回的是一个数值。null3.TYPE
格式:TYPE 变量名或标号
如果是变量,则汇编程序将回送该变量的以字节数表示的类型:DB为1,DW为2,DD为4,DQ为8。如果是标号,则汇编程序将回送代表该标号类型的数值:NEAR为-1,FAR为-2。§4.3.4 数值返回运算符(续)2.OFFSET
格式:OFFSET 变量名或标号
当运算符OFFSET加在一个变量名或标号前面时,汇编程序回送的运算结果是这个变量或标号所在的段的偏移量;null5.SIZE
格式:SIZE 变量名
运算符SIZE加在变量的前面,汇编程序回送的值等于LENGTH和TYPE两个运算符返回值的乘积。§4.3.4 数值返回运算符(续)4.LENGTH
格式:LENGTH 变量名
如果变量是用重复数据操作符DUP说明的,汇编程序将回送外层DUP给定的值;如果变量没有用DUP说明,则返回的值总是1。null 这种运算符是对变量、标号或某存储器的类型属性进行修改指定,它主要有PTR、段跨越前缀、SHORT、HIGH和LOW等5种。§4.3.5 属性修改运算符1.PTR
格式:类型 PTR 地址表达式
其中,地址表达式是指要修改类型属性的标号或存储器操作数。如果它是标号,则与之对应的类型有:NEAR、FAR;如果它是存储器操作数,则与之对应的类型有:BYTE、WORD、DWORD。 null2.段跨越前缀
它是在存储器操作数之前加上段寄存器名和冒号用于强行指定此存储器操作数相对哪个段寄存器,共有4种:DS:、CS:、SS:和ES: §4.3.5 属性修改运算符(续)3.SHORT
用来修饰JMP指令中转向地址的属性,指出转向地址是在下一条指令地址的-128~+127字节范围之内。null4.HIGH/LOW
格式:HIGH 常数或地址表达式
LOW 常数或地址表达式
这两个运算符称为字节分离操作符,它接收一个常数或地址表达式,HIGH取其高位字节,LOW取其低位字节。其中地址表达式必须具有常量值,HIGH/LOW运算符用于分离出段地址或偏移量的高字节/低字节。§4.3.5 属性修改运算符(续)null由高到低,从左往右地对优先级别相同的运算符进行计算。
表4.1 算符的优先级别关系表 §4.3 表达式与运算符(续)null格式: 段名 SEGMENT
……
段名 ENDS
一个完整的汇编源程序中可以定义多个段,但同时起作用的最多只有4个。每一个段都是由伪指令SEGMENT开始,由ENDS结束,SEGMENT和ENDS必须成对出现,并且在SEGMENT和ENDS的前面都必须有同一个段名;SEGMENT和ENDS语句之间可以的省略号部分,对于代码段来说,主要是指令,也可以有伪指令;对于数据段、附加段和堆栈段来说,一般是存储单元的定义、分配等伪操作。 §4.4 程序的段结构§4.4.1 段定义伪指令null§4.4.2 段寻址伪指令
定义段与段寄存器的关系,这可用ASSUME这个段寻址伪指令来实现,其格式如下:
ASSUME 段寄存器名:段名[,段寄存器:段名,……]
其中段寄存器名为CS、DS、ES、SS中的一个;段名则必须是由SEGMENT定义过的段名;段寄存器名和段名之间必须有冒号“:”。
ASSUME伪操作的作用指示汇编程序指令中用到的标号、过程及变量所在的段。在代码段中,可以随时用ASSUME伪指令修改“段寄存器名:段名”的联系。§4.4 程序的段结构(续)null2.SS的装入
装入的办法有两个:
(1)在段定义伪指令的组合类型中选择“STACK”参数,且在段寻址伪指令(ASSUME)中,把堆栈用的这一个段指派给段寄存器SS。
(2)可用类似DS,ES的装入办法。§4.4.3 段寄存器的装入§4.4 程序的段结构(续)1.DS和ES的装入
在程序中,引用段名就是以立即数形式获取该段的段基址,所以一个段的段基址要经过通用寄存器传送给DS,ES。 null 用DS、ES的装入的办法,那么为装入CS、IP的新值需要执行几条指令。
对CS、IP的装入通常是:按照END结束伪指令指定的地址装入CS、IP。任何一个源程序都是以END伪指令来结束。
格式:END 起始地址
起始地址可以是一个标号或表达式;END伪指令的作用是指示源程序到此结束和指定程序运行时的起始地址。§4.4.3 段寄存器的装入(续)3.CS的装入null 1.等值语句
格式:符号 EQU 表达式
其中EQU是等值伪指令,把表达式的值或符号赋给EQU左边的符号,表达式可以是:
常量表达式,
地址表达式,
变量、标号或指令助记符,§4.5 其它常用伪指令§4.5.1 符号定义语句null① 等值语句仅在汇编源程序时,作为替代符号用,不产生任何的目标代码,也不占有存储单元。
② 在同一源程序中,同一符号在EQU语句未解除之前不能用EQU伪指令重新定义。
③ 已经用EQU定义的符号,若以后不再用了就可以用PURGE语句来解除。PURGE语句的格式如下:
PURGE 符号1,符号2,……,符号n注意事项:§4.5.1 符号定义语句(续)null 2、等号语句
格式:符号=表达式
此语句的功能与EQU等值语句类似,其最大的特点是能对符号进行重定义。 §4.5 其它常用伪指令(续)§4.5.2 程序开始和结束伪指令
1.开始伪指令
NAME的格式:NAME module_name
汇编程序将以给出的module_name作为模块的名字。如果程序中没有NAME伪指令,则可使用TITLE伪指令,其格式:
TITLE textnull2.程序结束伪指令
表示源程序结束的伪指令的格式: END [起始标号]§4.5.2 程序开始和结束伪指令(续) §4.5.3 定位伪指令(ORG)和当前位置计数器($)
符号“$”代表当前位置计数器的现行值。
定位伪指令的ORG的格式:ORG 表达式
它表示把表达式的值赋给当前位置计数器:ORG语句后的指令或数据以表达式给定的值作起始偏移量。null 在程序设计中,通常把具有一定功能的程序段设计成一个子程序。过程定义伪指令格式如下:
过程名 PROC (NEAR/FAR)
……
RET
……
过程名 ENDP§4.5.4 过程定义伪指令§4.5 其它常用伪指令(续)null 过程名不能省,且过程的开始PROC和结束ENDP应使用同一个过程名;它就是过程调用指令CALL的目标操作数。它类同于标号的的作用,同样具有三个属性。当没有定义它的距离属性,隐含为NEAR。
任何一个过程,一定含有返回指令RET,它可以在过程中任何位置,不一定非要放在最后。若一个过程有多个出口,它可能有多个返回指令。但一个过程执行的最后一条指令必定是RET。§4.5.4 过程定义伪指令(续)null§4.6.1 上机步骤
程序设计人员还需要对已编写好的程序进行调试和测试,使它能正确运行。 §4.6 汇编语言上机调试null 2.汇编
汇编就是用宏汇编程序MASM.EXE把汇编语言源程序翻译(汇编)成机器语言的目标程序。宏汇编程序主要有以下功能:
检查源程序中语法错误,给出错误信息;
展开宏指令;
生目标程序(.OBJ),列表文件(.LST)和交叉引用文件(.CRF)。§4.6 汇编语言上机调试(续)1.编辑
调用编辑程序EDIT.EXE,WS.EXE等,用键盘敲入源程序,退出编辑系统时,保存编辑完成的文件,且扩展名为.ASM。null接着屏幕上显示:
宏汇编程序询问汇编产生的目标程序文件(目标程序文件是一个纯二进制代码文件,不能直接在屏幕上显示观察)的文件名是否为方括号中的默认值(即目标程序与源程序同名)。若是,直接按一回车键,否则需自己输入另一文件名。在回答完这一询问后,宏汇编程序接着依次询问产生列表文件(列表文件.LST是一个很有用的文件,文件中包含了源程序中各语句及其对应的目标代码。给出了源程序中各语句所属段内的偏移量,并且把源程序中所用的标号、变量和符号,列出它们的名字、类型和值,便于查阅)和交叉引用文件(交叉引用文件中给出了源程序中定义的符号如标号、变量等以及程序中引用这些符号的情况,且是按字母顺序排列的。若要查看这个符号表,必须使用CREF软件,它根据.CRF文件建立一个扩展名为.REF的文件。然后再显示.REF文件的内容就可以看到这个符号表)的文件名,屏幕上显示:§4.6 汇编语言上机调试(续)null 这两个文件是否建立由操作人员确定:若要建立其中一个或两个,操作人员便可输入所需建立的文件名,否则直接送入回车键。待完成上述人机对话后,宏汇编程序便对源程序进行扫描,检查源程序中各语句是否有语法错误,同时把各语句汇编成对应的机器目标代码。在汇编过程中,若发现源程序有语法错误,便随时给出出错信息。屏幕上显示:§4.6 汇编语言上机调试(续)null 如果警告错误和严重错误总数都等于零,那么这次源程序的汇编获得通过,可以进行连接。否则,返回编辑程序,修改源程序,然后再次进行汇编,直到源程序汇编正确无误。
如果汇编时,无须产生列表文件和交叉引用文件,则在启动宏汇编程序时可用分号结尾,比如:
C:>MASM TEST;↙
如果需要后面的列表文件和交叉引用文件,且它们的文件名与源文件名相同,这时启动宏汇编程序时,可用逗号指明,比如:
C:>MASM TEST,,;↙ §4.6 汇编语言上机调试(续)3.连接
源程序经过汇编后产生的目标程序,必须经过连接程序LINK.EXE连接后才能运行。 null 连接程序把一个或多个独立的目标程序模块连接装配成一个可重定位的可执行文件(扩展名为.EXE)。连接程序LINK除产生一个可执行文件外,还可产生一个内存映象文件(扩展名为.MAP)。LINK连接的一定是扩展名为.OBJ的目标程序。
在操作系统状态下,直接启动连接程序LINK.EXE。
例如:
C:>LINK TEST↙
接着屏幕上显示: §4.6 汇编语言上机调试(续)null 连接程序询问连接时产生的可执行文件名是否用方括号中的默认值(即可执行文件与目标程序文件同名)。若是,可直接按一回车键,否则需要重新输入一文件名。接着依次询问,屏幕上显示: 其中MAP文件(MAP文件列出各段的起点,终点及长度。)是否建立,由操作人员确定。若要,则输入一文件名,否则直接送一回车键。后一个是询问在连接时是否要用库文件。对于来自宏汇编语言程序的目标程序文件,通常是直接送一回车键。
与启动宏汇编程序一样,可以在启动连接程序时,用分号结束后续询问。如:
C:>LINK TEST;↙
若要产生MAP文件,且使用目标程序文件名,可用一逗号表示。如:
C:>LINK TEST,;↙
§4.6 汇编语言上机调试(续)null 若需要连接多模块的目标程序时,可用“+”把它们连接起来。例如连接三个目标程序文件P1.OBJ、P2.OBJ、P3.OBJ,其操作如下:
C:>LINK P1+P2+P3;↙
这样产生的一个可执行文件是约定取用第一个目标程序文件名,当然操作人员也可重新用另外的文件名。§4.6 汇编语言上机调试(续)4.调试运行
在建立好可执行文件后,就可以直接从DOS执行程序,如下所示:
C:>TEST.EXE↙
C:>
程序运行结束后返回DOS。如果用户程序已直接把结果在终端上显示出来,那么程序已经运行结束,结果也已经得到了。null1.DEBUG程序的调用
在DOS的提示符下,可键入命令:
C:\DEBUG [D:][PATH][FILENAME[.EXT]][PARM1][PARM2]
其中,文件名是被调试文件的名字。如用户键入文件,则DEBUG将指定的文件装入存储器中,用户可对其进行调试。如果未键入文件名,则用户可以用当前存储器的内容工作,或者用DEBUG命令N和L把需要的文件装入存储器后再进行调试。命令中的D指定指定驱动器PATH为路径,PARM1和PARM2则为运行被调试文件时所需要的命令参数。§4.6.2 DEBUG主要命令
DEBUG是为汇编语言设计的一种高度工具,它通过单步、设置断点等方式为汇编语言程序员提供了非常有效的调试手段。§4.6 汇编语言上机调试(续)null2.DEBUG的主要命令
(1)显示存储单元的命令D(DUMP),格式为:
_D[address]或
_D[range]
例如,D命令的使用情况如下:§4.6 汇编语言上机调试(续)null(2)修改存储单元内容的命令有两种。
·输入命令E(ENTER),有两种格式如下:
第一种格式可以用给定的内容表来替代指定范围的存储单元内容。命令格式为:
-E address [list]
例如,-E DS:100 F3'XYZ'8D
第二种格式则是采用逐个单元相继修改的方法。命令格式为:
-E address§4.6 汇编语言上机调试(续)null(3)检查和修改寄存器内容的命令R(register),它有三种格式如下:
·显示CPU内所有寄存器内容和标志位状态,其格式为:
-R
·显示和修改某个寄存器内容,其格式为:
-R register name
·显示和修改标志位状态,命令格式为:
-RF(4)运行命令G,其格式为:
-G[=address1][address2[address3…]]
其中,地址1指定了运行的起始地址,如不指定则从当前的CS:IP开始运行。后面的地址均为断点地址,当指令执行到断点时,就停止执行并显示当前所有寄存器及标志位的内容,和下一条将要执行的指令。
§4.6 汇编语言上机调试(续)null(5)跟踪命令T(Trace),有两种格式:
·逐条指令跟踪
-T[=address]
从指定地址起执行一条指令后停下来,显示所有寄存器内容及标志位的值。如未指定地址则从当前的CS:IP开始执行。
·多条指令跟踪
-T[=address][value]
从指定地址起执行n条指令后停下来,n由value指定。
(6)汇编命令A(Assemble),其格式为:
-A[address]
该命令允许键入汇编语言语句,并能把它们汇编成机器代码,相继地存放在从指定地址开始的存储区中。必须注意:DEBUG把键入的数字均看成十六进制数,所以如要键入十进制数,则其后应加以说明,如120D。§4.6 汇编语言上机调试(续)null(7)反汇编命令U(Unassemble)有两种格式。
·从指定地址开始,反汇编32个字节,其格式为:
-U[address]
如果地址被省略,则从上一个U命令的最后一条指令的下一个单元开始显示32个字节。
·对指定范围内的存储单元进行反汇编,格式为:
-U[range]
(8)命名命令N(Name),其格式为:
-N filespecs [filespecs]
命令把两个文件标识符格式化在CS:5CH和CS:6CH的两个文件控制块中,以便在其后用L或W命令把文件装入存盘。filespecs的格式可以是:
[d:][path] filename[.ext]
§4.6 汇编语言上机调试(续)null (9)装入命令(Load),有两种功能。
·把磁盘上指定扇区范围的内容装入到存储器指定地址开始的区域中。其格式为:
-L[address[drive sector sector]
·装入指定文件,其格式为:
-L[address]
此命令装入已在CS:5CH中格式化了文件控制块所指定的文件。如未指定地址,则装入CS:0100开始的存储区中。
(10)写命令W(Write),有两种功能。
·把数据写入磁盘的指定扇区。其格式为:
-W address drive sector sector
·把数据写入指定的文件中。其格式为:
-W[address]§4.6 汇编语言上机调试(续)null(11)退出DEBUG命令Q(Quit),其格式为:
-Q
它退出DEBUG,返回DOS。本命令并无存盘功能,如需存盘应先使用W命令。 §4.6 汇编语言上机调试(续)null小 结4.1 汇编语言语句种类及其格式
4.2 汇编语言数据
4.3 表达式与运算符
4.4 程序的段结构
4.5 其他常用伪指令
4.6 汇编语言上机调试