52第一讲第四章汇编语言程序设计-语句特点、伪指令回顾:8086/8088的内部结构、寄存器功能和工作过程,指令格式、寻址方式和功能。重点和纲要:汇编语言程序设计-语句特点、伪指令(了解汇编的概念及其方法,掌握汇编程序的基本格式,常用运算符的使用方法,汇编的步骤。了解伪指令的功能,掌握定义数据、符号、段、过程等伪指令的使用方法,能编写格式正确的汇编程序)。讲授内容:4.1汇编语言的基本元素一、汇编语言的语句格式由汇编语言编写的源程序是由许多语句(也可称为汇编指令)组成的。每个语句由1~4个部分组成,其格式是:[标号]指令助记符[操作数][;注解]其中用方括号括起来的部分,可以有也可以没有。每部分之间用空格(至少一个)分开,一行最多可有132个字符。1.标识符是给指令或某一存储单元地址所起的名字。可由下列字符组成:字母:A~z;数字:0~9;特殊字符:?、·、@、一、$。数字不能作标识符的第一个字符,而圆点仅能用作第一个字符。标识符最长为31个字符。当标识符后跟冒号时,表示是标号。它代表该行指令的起始地址;当标识符后不带冒号时,表示变量;伪指令前的标识符不加冒号。2.指令助记符表示不同操作的指令,可以是8088的指令助记符,也可以是伪指令。3.操作数是指令执行的对象。依指令的要求,可能有一个、两个或者没有,53例如:RET;无操作数COUNT:INCCX;一个操作数如果是伪指令,则可能有多个操作数,例如:COSTDB3,4,5,6,7;5个操作数MOVAX,[BP十4];第二个操作数为表达式4.注解该项可有可无,是为源程序所加的注解,用于提高程序的可读性。二、汇编语言的运算符1.算术运算符、逻辑运算符和关系运算符①算术运算符可以应用于数字操作数,结果也是数字。而应用于存储器操作数时,只有+、-运算符有意义。2.取值运算符SEG、OFFSET、TYPE、SIZE和LENGTH·SEG和OFFSET分别给出一个变量或标号的段地址和偏移量。例如,定义:SLOTDW25则:MOVAX,SLOT;从SLOT地址中取一个字送入AXMOVAX,SEGSLOT;将SLOT所在段的段地址送入AXMOVAX,OFFSETSLOT;将SLOT所在段的段内偏移地址送AX·TYPE操作符返回一个表示存储器操作数类型的数值。各种存储器地址操作数类型部分的值如表3-1所示。·LENGTH和SIZE操作符只应用于数据存储器操作数。(用DB/DW/DD等定义的操作数)LENGTH返回一个与存储器地址操作数相联系的单元数,SIZE操作数返回一个为存储器操作数分配的字节数。例如:若MULT-WORDDW50DUP(0)则LENGTH(MULT-WORD)=50SIZE(MULT-WORD)=100注意:SIZE(X)=(LENGTHX)*(TYPEX)表3-1存储器操作数的类型属性及返回值字节1字2双字4NEAR-1FAR-2543.属性运算符属性运算符用来给指令中的操作数指定一个临时属性,而暂时忽略当前的属性。常用的有:(1)合成运算符PTR它作用于操作数时,则忽略了操作数当前的类型(字节或字)及属性(NEAR或FAR),而给出一个临时的类型或属性,一般格式:类型PTR表达式功能:建立一个存储器地址操作数,它与其后的存储器地址操作数有相同的段地址偏移量,但有不同的类型。例如:SLOTDW25此时SLOT已定义成字单元。若我们想取出它的第一个字节内容,则可用PTR对其作用,使它暂时改变为字节单元,即MOVAL,BYTEPTRSLOT三、表达式是由运算符和操作数组成的序列,在汇编时产生一个确定的值。这个值可以仅表示一个常量,也可以表示一个存储单元的偏移地址,相应的表达式称为常量表达式和地址表达式。1.常数汇编语言语句中出现的常数可以有7种:①二进制数后跟字母B,如01000001B。②八进制数后跟字母Q或O,如202Q或202O。③十进制数后跟D或不跟字母,如85D或85。④十六进制数后跟H,如56H,0FFH。注意,当数字的第一个字符是A~F时,在字符前应添加一个数字0,以示和变量的区别。另有,十进制浮点数、十六进制实数、字符和字符串2.常量操作数常量操作数是一个数值操作数,一般是常量或者是表示常量的标识符。可以为数字常量操作数或字符串常量操作数。前者可采用二进制、八进制、十进制或十六进制等计数形式;而后者则为相应字符的ASCII码。3.存储器操作数55存储器操作数是一个地址操作数,代表一个存储单元的地址,通常以标识符的形式出现。存储器操作数可以分为变量及标号两者类型,如果存储器操作数所代表的是某个数据在数据段、附加段或堆栈段中的地址,那么这个存储器操作数就称为变量;如果存储器操作数所代表的是某条指令代码在码段中的地址,那么这个存储器操作数称为标号。变量所对应的存储单元内容在程序的运行过程中是可以改变的,标号通常作为转移指令或调用指令的目标操作数,在程序运行过程中不能改变。存储器操作数有三个方面的属性。(1)段地址:即存储器操作数所对应的存储单元所在段的段地址;(2)偏移地址:即存储器操作数所对应的存储单元在所在段内的偏移地址;(3)类型:变量的类型是相应存储单元所存放的数据项的字节数;而标号的类型则反映了相应存储单元地址在作为转移或调用指令的目标操作数时的寻址方式,可有两种情况,即NEAR和FAR。具体值可见表3-14.常量表达式由常量操作数及运算符构成,在汇编时产生一个常量。如PORT、VAL十1、OFFSETSUM、SEGSUM、TYPECYCLE等。5.地址表达式由存储器操作数与运算符构成,必须有明确的物理意义。例如SUM+2、CYCLE-5表达式SUM+2、CYCLE-5的值仍然是一个存储器操作数,该存储器操作数的段地址与类型属性分别与存储器操作数SUM及CYCLE相同,但偏移地址分别比SUM及CYCLE大2或小5。表达式是在汇编时计算的,而变量单元的内容在程序的运行过程中可以改变。四、汇编语言程序汇编步骤汇编语言程序要能在机器上运行,还必需将汇编源程序汇编成可执行程序。为此必须完成以下几个步骤。过程如图3-1所示。1.编辑源程序2.调用宏汇编对源程序进行汇编3.对目标程序进行连接564.运行可执行程序并调试4.2伪指令伪指令用来对汇编程序进行控制,对程序中的数据实现条件转移、列表、存储空间分配等处理,其格式和汇编指令一样,但一般不产生目的代码,即不直接命令CPU去执行什么操作。一、定义数据伪指令该类伪指令用来定义存储空间及其所存数据的长度。·DB:定义字节,即每个数据是1个字节。·DW:定义字,即每个数据占1个字(2个字节)。·DD:定义双字,即每个数据占2个字。低字部分在低地址,高字部分在高地址。·DQ:定义4字长,即每个数据占4个字。·DT:定义10个字节长,用于压缩式十进制数,例如:DATA1DB5,6,8,100DATA2DW7,287TABLEDB?;表示在TABLE单元中存放的内容是随机的当一个定义的存储区内的每个单元要放置同样的数据时,可用DUP操作符。一般格式:COUNTDUP(?),COUNT为重复的次数,“()”中为要重复的数据。如:BUFFERDB100DUP(0);表示以BUFFER为首地址的100个字节中存放00H数据BUFFER1DB100DUP(3,5,2DUP(10),35),24,‘NUM’)想一想存储区的情况?二、符号定义伪指令EQU、=、及PURGE·EQU伪指令给符号定义一个值。在程序中,凡是出现该符号的地方,汇编时均用其值代替,如:TIMESEQU50DATADBTIMESDUP(?)上述两个语句实际等效于如下一条语句:57DATADB50DUP(?)·“=”伪指令可给初始变量赋值。如:COUNT=100;COUNT=100TIME=50;TIME=50·PURGE伪指令用于释放由EQU伪指令定义的变量,使这些变量可以被重新定义。PURGETIMES;释放TIMES变量TIMESEQU2;重新定义三、段定义伪指令SEGMENT和ENDS一般来说,一个完整的汇编源程序由3个段组成,即堆栈段、数据段和代码段。段定义伪指令可将源程序划分成若干段,以便生成目的代码和连接时将各同名段进行组合。段定义伪指令一般格式为:段名SEGMENT[定位类型][组合类型][类别]段名ENDSSEGMENT和END5应成对使用,缺—不可。其中段名是不可省略的。其它是可选项,是赋予段名的属性,可以省略。例如:DATASEGMENTDW20DUP(?)DATAENDS四、设定段寄存器伪指令ASSUME一般格式:ASSUME段寄存器:段名[,段寄存器:段名,……]功能:通知汇编程序,哪一个段寄存器是该段的段寄存器,以便对使用变量或标号的指令汇编出正确的目的代码。在段名中,CODE表示代码段,DATA表示数据段,STACK表示堆栈段。由于ASSUME伪指令只指明某一个段地址应存于哪一个段寄存器中,并没有包含将段地址送入该寄存器的操作。因此要将真实段地址装入段寄存器还需用汇编指令来实现。这一步是不可缺少的。例如,CODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK58MOVAX,DATA;DATA段值送AXMOVDS,AX;AX内容送DS,DS才有实际段值CODEENDS当程序运行时,由于DOS的装入程序负责把CS初始化成正确的代码段地址,SS初始化为正确的堆栈段地址,因此用户在程序中就不必设置。但是,在装入程序中DS寄存器由于被用作其它用途,因此,在用户程序中必须用两条指令对DS进行初始化,以装入用户的数据段地址。当使用附加段时,也要用MOV指令给ES赋段地址。五、定义过程的伪指令PROC和ENDP在程序设计中,可将具有一定功能的程序段看成为一个过程(相当于一个子程序),它可以被别的程序调用。一个过程由伪指令PROC和ENDP来定义,其格式为:过程名PROC[类型]过程体RET过程名ENDP其中过程名是为过程所起的名称,不能省略,过程的类型由FAR(远过程,为段间调用)和NEAR(近过程,在本段内调用)来确定,如果缺省类型,则该过程就默认为近过程。ENDP表示过程结束。过程体内至少应有一条RET指令,以便返回被调用处。过程可以嵌套,也可以递归使用。例如一个延时100ms的子程序,其过程可定义如下,DELAYPROCPUSHBXPUSHCXMOVBL,10;延时10ms,改变BL和CX中的值,即可改变延时时间。AGAIN:MOVCX,2801;WAIT;LOOPWAITDECBLJNZAGAINPOPCXPOPBX59RETDELAYENDPCALLDELAY;调用该过程远过程调用时被调用过程必定不在本段内。例如,有两个程序段,其结构如下:CODE1SEGMENTASSUMECS:CODE1FARPROCPROCFARRETFARPROCENDPCODE1ENDSCODE2SEGMENTASSUMECS:CODE2CALLFARPROC…..CODE2ENDSCODE1段中的FARPROC过程被另一段CODE2调用,故为远过程。六、宏指令在汇编语言书写的源程序中,若有的程序段要多次使用,为了简化程序书写,该程序段可以用一条宏指令来代替,而汇编程序汇编到该宏指令时,仍会产生源程序所需的代码。宏指令的一般格式为:宏指令名MACRO[形式参量表]宏体ENDM例如:SHIFTMACROMOVCL,4SALAL,ClENDM这样定义以后,凡是要使AL中内容左移4位的操作都可用一条宏指令SHIFT来代替。宏指令与子程序有许多类似之处。它们都是一段相对独立的、完成某种功能的、可供调用的程序模块,定义后可多次调用。但在形成目的代码时,子程序只60形成一段目的代码,调用时转来执行。而宏指令是将形成的目的代码插到主程序调用的地方。因此,前者占内存少,但执行速度稍慢;后者刚好相反。七、ORG伪指令ORG伪指令规定了在某一段内,程序或数据代码存放的起始偏移地址。一般格式:ORG表达式例如:DATASEGMENTBUFF1