资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第,4,章 汇编语言程序设计,通过例子说明,8086,汇编语言的格式,先看以下程序。,MY_DATASEGMENT,;,定义数据段,SUMDB,?;,为符号,SUM,保留一个字节,MY_DATAENDS,;,定义数据段结束,MY_CODESEGMENT,;,定义码段,ASSUME CS,:,MY_CODE,,;,规定,CS,和,DS,的内容,DS,:,MY_DATAPORT_VALEQU 3,;,端口的符号名,GO,:,MOV AX,,,MY_DATA,;,DS,初始化为,MY_DATAMOV DS,,,AXMOV SUM,,,0,;,清,SUM,单元,CYCLE,:,CMP SUM,,,100,;,SUM,单元与100相比较,JNA NOT_DONE,;,若未超过,转至,NOT_DONEMOV AL,,,SUM,;,若超过,把,SUM,单元的内容,OUT PORT_VAL,,,AL,;,通过,AL,输出,HLT,;,然后停机,NOT DONE,:,IN AL,,,PORT_VAL,;,未超过时,输入下一个字节,ADD SUM,,,AL,;,与以前的结果累加,JMP CYCLE,;,转至,CYCLEMY CODEENDS,;,码段结束,END GO,;,整个程序结束,可以看出:,1.,源程序是由若干个段组成的。,NAME1SEGMENT,语句,NAME1ENDSNAME2SEGMENT,语句语句,NAME2ENDS END ,源程序的一般格式如下:,2.,每一个段由若干语句行组成。,3.,语句分为指令语句和指示语句,(,伪指令语句,),。,(1),指令语句:,与机器指令一一对应,在程序运行期间由机器执行。,指令语句的格式如下:,标号:,前缀,(,指令助记符,),操作数,;注释,(2),伪指令语句:,在汇编程序汇编源程序期间由汇编程序处理,本身并不产生机器码,仅仅是告诉汇编程序如何对源程序进行正确的汇编。,指令语句的格式如下:,标号,(,伪指令助记符,),操作数,;注释,在,IBM,宏汇编中有以下几种指示性语句,(Directive statements),:,(1),符号定义语句,(Symbol definition),;,(2),数据定义语句,(Data definition),;,(3),段定义语句,(Segmentation definition),;,(4),过程定义语句,(Procedure definition),;,(5),结束语句,(Termination),。,段定义语句,8086,的存储器是分段的,所以,8086,必须按段来组织程序和利用存储器,这就需要有段定义语句。段定义的主要命令有:,(1)SEGMENT,,,(2)ENDS,,,(3)ASSUME,,,(4)ORG,。,SEGMENT,和,ENDS,语句把汇编语言源程序分成段,这些段就相应于存储器段,在这些存储器段中,存放相应段的目标码。,汇编程序必须知道程序的段结构,并知道在各种指令执行时将访问哪一个段由段寄存器所指向。这个信息是由,ASSUME,语句提供的。,通常在汇编语言的源程序中,至少要定义码段,(,指令段,),、堆栈段和数据段,有时还要定义附加段。每一个段必须有一个名称,如,MY_DATA,、,MY_CODE,等。一个段由命令,SEGMENT,开始,由命令,ENDS,结束,它们必须成对出现,而且它们的语句中必须有名称,名称必须相同。最后用语句,END,来结束整个源程序。,ASSUME,语句,只是使汇编程序知道在程序执行时各个段寄存器的值,而这些段寄存器的实际值,(,除了码段寄存器,CS,以外,),,还必须在程序执行时,用,MOV,指令来赋给。,一般来说,存储器段具体在哪儿是不重要的,可由汇编程序来选择。但是,在有些情况下,可能要给汇编程序一些约束,例如:“不要使这个段与别的段搭接”,保证这个段所用的第一个字节在偶数地址,这样对于一个字的访问可以在一个存储器读写周期完成。或“在下列地址开始这个段”。可以把这些约束写入到源程序中。,另一个语句,ORG(origin,),,它规定了段内的起始地址。伪指令,ORG,的一般格式为:,ORG,表达式,此语句指定了段内在它以后的程序或数据块存放的起始地址,即以语句中的表达式的值作为起始地址,连续存放,除非遇到一个新的,ORG,语句。,4.2,汇编源程序从编写到运行的过程,编写源程序,用编辑程序将源程序输入计算机,调用汇编程序对源程序进行汇编,是否有错误?,调用连接程序对汇编后生成的目标文件,(,OBJ,),进行连续,连接是否有错误?,运行连接后生成的可执行文件,结果是否有错误?,调用调试文件进行调试,运行是否成功?,结束,修改已输入的源程序,Y,Y,N,N,Y,Y,N,N,4.2,语句行的构成,语句行是由标记,(Token),及分隔符按照一定的规则组织起来的,标记是,IBM,宏汇编源程序的最小的、有意义的单位。,4.2.1,标记,IBM,宏汇编的字符集,IBM,宏汇编中所使用的字符集仅是,ASCII,和,EBCDIC(,扩展的,BCD,码,),字符集的一个子集。它由以下几部分组成:,(1),字母,包含大写的英文字母:,ABCDXYZ,;,小写的英文字母:,abc,xyz,。,(2),数字,阿拉伯数字:,0123456789,。,(3),特殊字符,可打印字符如图,4-1,中所示。,非打印字符有:空格、制表符,(TAB,键,),、回车和换行。,若在源程序中包含任何不属于上列字符集中的字符,则汇编程序就把它们作为空格处理。虽然字符“,&”,是字符集中的一个字符,但紧跟在回车换行之后的符号“,&”,是代表一个连续行,所以,汇编程序也把它当做空格处理。,2.,界符,(Delimiters),界符是一些特殊字符,利用它们可以表明某个标记的结束,它们本身也有一定的意义,这一点就与分隔符,(,空格,),不同。例子中的冒号,(,:,),、逗号,(,,,),都是一种界符。,IBM,宏汇编中的界符集如图,4-2,所示。,3.,常量,(Constants),凡是出现在,8086,源程序中的固定值,(,它在程序运行期间不会变化,),,就称为常量。例子中的数,0,、,3,、,100,等都是常量,而且是数字常量。,IBM,宏汇编中允许的常量为:,(1),数字,(,整数,),常量,二进制常量,以字母,B,结尾的由一串“,0”,和“,1”,组成的序列。例如,,00101100B,。,十进制常量,由若干个,0,9,的数字组成的序列,可以以字母,D,作结尾,或没有任何字母作结尾。例如,,1234D,或,1234,。,八进制常量,以字母,Q(,或字母,O),结尾,由若干个,0,7,的数字组成的序列。例如,255Q,,,377Q,等。,十六进制常量,以字母,H,结尾,由若干个,0,9,的数字或,A,F,的字母所组成的序列。,为了避免与标识符相混淆,十六进制数在语句中必须以数字打头。所以,,凡是以字母,A,F,开始的十六进制数,必须在前面加上数字,0,。例如,56H,,,0BA3FH,等。,(2),字符串常量,字符串常量是由包含在单引号内的,1,至,2,个,ASCII,字符构成的。汇编程序把它们表示成一个字节序列,一个字节对应一个字符,,把引号中的字符翻译成它的,ASCII,码值。,例如字符“,A”,等价于,41H,,字符“,AB”,等价于,4142H,。在可以使用单字节立即数的地方,就可以使用单个字符组成的字符串常量;在可以使用字立即数的地方,就可以使用两个字符组成的字符串常量。,只有在初始化存储器时才可以使用多于两个字符的字符串常量。,4.,标识符,(Identifiers),标识符是由程序员自由建立起来的、有特定意义的字符序列,如例子中的,SUM,、,CYCLE,和,PORT_VAL,等等。,一个标识符是由最多为,31,个字母、数字及规定的特殊字符,(?_,),等组成的,而且不能用数字打头,(,以免与十六进制数相混淆,),。,5.,保留字,(Reserved words),保留字看上去像标识符,但是它们在语言中有特殊的意义,而且不能用它们作为标识符。如例子中的,SEGMENT,、,MOV,、,EQU,、,AL,等都是保留字。实际上凡是,8086,的指令助记符,汇编语言中的命令,(,伪指令,),,寄存器名等都是保留字。,6.,注释,(Comment),为了使汇编语言的源程序更便于阅读和理解,常在源程序中加上注释。注释是在分号,(,;,),后面的任意的字符序列,直到行的结尾。在汇编时,汇编程序对它们并不进行处理。在可打印的文件中,注释和源程序一起打印。,4.2.2,符号,在汇编语言源程序中,为了使程序更具有普遍性,也便于程序的修改,用户常用符号等代替存储单元、数据、表达式等等,如例中的存储单元,SUM,、输入输出端口,PROT_VAL,等就是。符号,(Symbol),是一种标识符,它要符合标识符的组成规则。,在实际使用中的符号可以分成五类,即寄存器、变量、标号、数、其他。,每个符号都具有一定的属性,以允许汇编程序使用它来代表所需的信息。,1.,寄存器,(Registers),8086,的寄存器常在操作数场出现,代表某一个操作数。每个寄存器都有一种类型特性,由这些类型可以确定它是一个字节寄存器还是一个字寄存器。,8086,的标志位被看作是一位寄存器。,2.,变量,(Variable),存放在存储单元中的操作数是变量,因为它们的值是可以改变的。,在程序中出现的是存储单元地址的符号,即它们的名称。,所有的变量都具有三种属性:,(1),段值,(SEGMENT),,即变量单元所在段的段地址,(,段的起始地址,),的高,16,位,低,4,位始终为,0;,(2),偏移量,(OFFSET),,即变量单元地址与段的起始地址之间的偏移量,(16,位,);,(3),类型,(TYPE),,变量有三种类型:字节,(BYTE),、字,(WORD),和双字,(DOUBLE WORD),。,变量通常是用存储器初始化命令定义的。,3.,标号,(Label),标号是某条指令所存放单元的符号地址,它是转移,(,条件转移或无条件转移,),指令或调用,(CALL),指令的目标操作数。,对于汇编程序来说,标号与变量是类似的,都是存储单元的符号地址。只是标号对应的存储单元中存放的是指令;而变量所对应的存储单元中存放的是数据。,所以,标号也有三种属性:,(1),段值,,(2),偏移量,,(3),类型。,标号的类型与变量不同,它的类型是,NEAR,或是,FAR,。,NEAR,是指转移到此标号所指的语句,或调用此子程序或过程,只需要改变,IP,值,而不改变,CS,值。也即转移指令或调用指令与此标号所指的语句或过程在同一段内。,FAR,与,NEAR,不同,要转移到标号所指的语句,或调用此子程序或过程,不仅需要改变,IP,的值,而且需要改变,CS,,即是段交叉转移或调用。,若没有对标号进行类型说明,就假定它为,NEAR,。,4.,数,在汇编语言源程序中的常数也常以符号的形式出现,这样就更具有通用性,更便于修改。,如上例中的就是把端口地址,3,定义为一个符号,PORT_VAL,。,5.,其他符号,除了上述,4,种符号以外,在汇编语言中还经常出现一些其他符号,把它们用作汇编程序中的伪指令名字。,4.2.3,表达式,表达式,(Expressions),是由上面讨论过的标记,(Token),、符号,(Symbol),通过运算符组合起来的。粗略地说,一个表达式是一个由操作数和运算符组合的序列,在汇编时它能产生一个值。,1.,操作数,(Operands),一个操作数可以是一个寄存器名、一个常量,(,数字常量或字符串常量,),或一个存储器操作数。,(1),常量操作数,具有数字值的操作数是常量或是表示常量的标识符,(,符号,),。,(2),存储器操作数,存储器操作数,通常是标识符,可以分成标号,(Label),和变量,(Variable),两种。,标号是可执行的指令语句的符号地址,通常是作为转移指令,JMP,和调用指令,CALL,的目标操作数。,变量通常是指存放在一些存储单元中的值,这些值在程序运行过程中是可变的。,变量可以具有以下几种寻址方式:,直接寻址,16,位地址偏移量包含在指令中;,基址寻址由一个基址寄存器,(BX,或,BP),的内容,加上一个在指令中指定的,8,位或,16,位位移量,决定变量的地址;,变址寻址由一个变址寄存器,(SI,或,DI),的内容,加上一个在指令中指定的,8,位或,16,位位移量,决定变量的地址;,基址变址寻址由一个基址寄存器,(BX,或,BP),的内容,加上一个变址寄存器,(SI,或,DI),的内容,再加上一个在指令中指定的,8,位或,16,位位移量,决定变量的地址。,作为存储器操作数的标号和变量都有三种属性:段值、段内地址偏移量、类型。,一个运算符取一个或多个操作数的值,以形成一个新值。在,IBM,宏汇编中有五种运算符。,2.,运算符,(Operators),IBM,宏汇编通常有以下几种运算符:,算术运算符,(Arithmetic Operators),;,逻辑运算符,(Logical Operators),;,关系运算符,(Relational Operators),;,分析运算符,(Analytic Operators),;,合成运算符,(Synthetic Operators),。,(1),算术运算符,这是读者十分熟悉的运算符,-+(,加,),、,-(,减,),、*,(,乘,),、,/(,除,),运算符。另一个算术运算符是,MOD(,求余,),,它产生除法以后的余数。因此,19/7,是,2(,商是,2),,而,19MOD7,是,5(,余数是,5),。,算术运算符应用于数字操作数,结果也是数字的。,当算术运算符应用于存储器即地址操作数时其规则就更加严格:只有当结果有明确的、有意义的物理解释时,这些运算才是有效的。,(2),逻辑运算符,按位操作的逻辑运算符有:,AND(,与,),、,OR(,或,),、,XOR(,异或,),和,NOT(,非,),。,逻辑运算的操作数只能是数字的,而且结果是数字的。存储器地址操作数不能进行逻辑运算。,注意:,AND,、,OR,、,XOR,和,NOT,,也是,8086,指令的助记符。但是,作为,IBM,宏汇编的运算符是在程序汇编时计算的。而作为指令的助记符,则是在程序执行时计算的。,(3),关系运算符,在,IBM,宏汇编中有以下关系运算符:,相等,EQ(Equal,),;,不等,NE(Not,Equal),;,小于,LT(Less,Than),;,大于,GT(Greater,Than),;,小于或等于,LE(Less,Than or Equal),;,大于或等于,GE(Greater,Than or Equal),。,关系运算的两个操作数,或者都是数字的,或者是同一个段的存储器地址。结果始终是一个数字值。,若关系是假,则结果为,0,;若关系是真,则结果为,0FFFFH,。,(4),分析运算符,分析运算符可以把存储器操作数分解为它的组成部分,如它的段值、段内偏移量和类型。,(5),合成运算符,合成运算符可以由已经存在的存储器操作数生成一个段值与偏移量相同、而类型不同的新的存储器操作数。,4.2.4,语句,如前所述,一个汇编语言的源程序是由一条条语句组成的,语句,(Statements),就是完成一个何种动作的说明。源程序中的语句可分成两类:,指令语句,,汇编程序把它们翻译成机器代码,这些代码命令,8086,执行某些操作。如,MOV,、,ADD,、,JMP,等。,指示性语句,(,伪指令,),,,汇编程序并不把它们,(,也不可能,),翻译成机器代码,只是用来指示、引导汇编程序在汇编时进行一些操作,如定义符号、分配存储单元、初始化存储器等等,所以伪指令本身不占用存储单元。,两种语句的格式是类似的。指令语句的格式为:,标号:助记符 参数,,,参数 ;注释,指示性语句的格式为:,名称 命令 参数,,,参数 ;注释,在一个指令语句中的标号后面跟有冒号,(,:,),,而在一个指示性语句中的名字后面没有冒号,这就是这两种语句在格式上的主要区别。,一个标号与一条指令的地址符号名相联系,标号可以作为,JMP,指令和,CALL,指令的目标操作数。,指示性语句中的名字与指令的地址毫无关系,绝不能转向它。,在指令语句中的标号,总是任选的;但在指示性语句中的名字,可能是强制的、任选的或禁止的,这取决于实际的命令。,4.3,指示性语句,在,IBM,宏汇编中有以下几种指示性语句,(Directive statements),:,(1),符号定义语句,(Symbol definition),;,(2),数据定义语句,(Data definition),;,(3),段定义语句,(Segmentation definition),;,(4),过程定义语句,(Procedure definition),;,(5),结束语句,(Termination),。,4.3.1,符号定义语句,等值语句,EQU,EQU,语句给符号名定义一个值,或定义为别的符号名,甚至可定义为一条可以执行的指令等。,EQU,语句的格式为:,NAME EQU EXPRESSION,EQU,语句在未解除前,不能重新定义。,2.,等号,(Equal sign),语句,=,此语句的功能与,EQU,语句类似,最大特点是能对符号进行再定义。,3.,解除语句,PURGE,已经用,EQU,命令定义的符号,若以后不再用了就可以用,PURGE,语句来解除。,PURGE,语句的格式为,:,PURCE,符号,1,,符号,2,,,,符号,n,注意:,PURGE,语句本身不能有名字。用,PURGE,语句解除后的符号可以重新定义。,4.3.2,数据定义语句,数据定义语句,为一个数据项分配存储单元,用一个符号名与这个存储单元相联系,且为这个数据提供一个任选的初始值。,与数据项相联系的符号名称为变量。数据定义语句的例子如下:,THINGDB?,;定义一个字节,BIGGER_THINGDW?,;定义一个字,BIGGEST_THINGDD?,;定义一个双字,THING,是一个符号名,它与在存储器中的一个字节相联系,即它是一个字节变量。,BIGGER_THING,也是一个符号名,它与在存储器中的一个字相联系,即它是一个字变量。,BIGGEST_THING,也是一个符号名,它与在存储器中的一个双字相联系,即它是一个双字变量。,由汇编程序产生的目标码,产生指令和放指令的地址。在目标码产生以后,指令已经存放在存储器中,可以执行了。,在指令送至存储器的时候,数据项的初始值也可以送到存储器中。这意味着目标码除了包含指令和它们的地址以外,也可以包括数据项的起始值和它们的地址。这些初始值是由数据定义语句所规定的。,例如:,THINGDB25,不仅使,THING,这个符号与一个字节的存储单元相联系,而且在汇编时会把,25,放入与,THING,相联系的存储单元中。所以,THING,是一个字节变量,它的初始值为,25,。,同样,以下语句:,BIGGERDW4142H,在汇编时就会把,41H,与,42H,分别放至与,BIGGER_THING,相联系的两个连续的字节单元中。,下面的语句:,BIGGESTDD12345678H,在汇编时就会初始化,如图,4-3,所示。它定义了一个双字变量,且给了初始值。,当汇编程序汇编时遇到“,?”,号,则它仍然为数据项分配相应的存储单元,(DB,分配一个字节、,DW,分配一个字、,DD,分配一个双字,),,但并不产生一个目标码来初始化这些存储单元。即“,?”,号是为了保留若干个存储单元,以便存放指令执行的中间结果。,通常初始值能用一个表达式来规定,因为表达式是在汇编时计算的。,同样,在存储单元中可以存放存储器地址值。存放内存单元的段内偏移量需用一个字;存放全地址,则需用两个字,一个字放段地址,另一个字放段内偏移量。,在实际应用中,还经常会用到由字节、字或双字构成的表。,这可由在数据定义语句的参数部分,引入若干个用逗号分隔的参数就可以建立一个表。下列语句定义了一个包含,2,的权的字节的表:,POWERS_2DB1,,,2,,,4,,,8,,,16,可以用,DUP,来缩写若干相同的值。因而,,DUP,利用给出的一个初值,(,或一组初值,),以及这些值应该重复的次数来初始化存储器。,DB100 DUP(0),;,100,个字节全初始化为,0,DW100 DUP(0),;,100,个字全初始化为,0,DW10 DUP(?),;保留,10,个字,可以用,DB,数据定义语句在内存中定义一个字符串。字符串中的每一个字符用它的,ASCII,码表示,为一个字节,故字符串的定义必须用,DB,命令。,有两种定义字符串的方法:一种是字符串中的每一个字符分别定义,每一个字符之间用逗号分隔;另一种方法是在整个字符串的前后都加单引号,例如:,EXAM1DBTHIS IS AN EXAMPLE,IBM,宏汇编对在程序中涉及的每一个存储单元与一种类型联系起来,这样能对访问存储器的指令产生正确的目标码。例如,数据定义语句:,SUMDB?,告诉汇编程序,,SUM,是字节类型的,以后当遇到如下的指令语句:,INCSUM,汇编程序就产生一个字节增量指令,而不是一个字增量指令。,一个存储单元的类型如下:,(1),数据字节。如,SUMDB?,;定义一个字节,(2),数据字,(,两个连续的字节,),。如,BIGGERDW?,;定义一个字,(3),数据双字,(,四个连续的字节,),。如,BIGGESTDD?,;定义一个双字,(4)NEAR,指令单元。如,CYCLE:CMP SUM,100,(5)FAR,指令单元。,一个指令单元能出现在一条,JMP,或,CALL,语句中,若这个指令单元的类型是,NEAR,,汇编程序将产生一个段内,JMP,或,CALL,指令;若指令单元的类型是,FAR,,则产生一个段交叉,JMP,或,CALL,指令。,一个,NEAR,指令单元规定了一个长度为两个字节的指针,即此指令单元在段内的地址偏移量。获得了此地址偏移量,就可以采用段内的转移或调用。,一个,FAR,指令单元,规定了一个长度为四个字节的指针,即此指令单元所在段的段地址和段内的地址偏移量。只有获取了这四个字节,才能得到一个,FAR,指令单元的全地址,实现交叉的段调用或转移。,一个存储单元地址加或减一个数字值而形成的新的存储单元与初始的存储单元有着相同的类型。例如,,SUM+2,是字节型,,BIGGER-3,是字型,而,CYCLE+1,是一个,NEAR,型指令单元。,分析运算符把存储器地址操作数分解为它们的各个组成部分。这些运算符是:,(1)SEG,,,(2)OFFSET,,,(3)TYPE,,,(4)SIZE,,,(5)LENGTH,。,若在一个程序中,对它的数据段有如下定义,DATA_TABLESEGMENT,BUFFER1DB100 DUP(0),BUFFER2DW200 DUP(20H),BUFFER3DD100 DUP(13),DATA_TABLESENDS,其中的每一个存储单元都有一些属性,(,或组成部分,),。分析运算符,SEG,,返回的是一个存储单元的段地址,(,即它所在段的起始地址,),;,OFFSET,运算符返回的是每一个存储单元地址的段内偏移量,即它与段地址之间的偏差。,故语句:,SEG BUFFER1,SEGBUFFER2,是相同的,它们返回的地址都是,DATA_TABLES,的地址。所以,若要对数据段寄存器初始化,则可以采用指令:,MOVAX,,,SEG BUFFER1,MOVDS,,,AX,而,OFFSET,是各不相同的。若要向这些缓冲区填入新的数据,可以用一些地址指针,则可以用以下指令来初始化地址指针:,MOVBX,OFFSET BUFFER1,MOVSI,OFFSET BUFFER2,然后,就可以用这些指针来间接寻址这些缓冲区。,TYPE,运算符返回一个数字值,它表示存储器操作数的类型部分。字节、字和双字的类型部分,分别是它们所占有的字节数。而指令单元的类型部分的值,没有实际的物理意义。,LENGTH,运算符返回一个与存储器地址操作数相联系的单元数,(,所定义的基本单元的个数,),。注意:要用,LENGTH,返回的存储区必须用,DUP(),来定义,否则返回值为,1,。故可以利用,LENGTH,运算符对计数器进行初始化。分析运算符,SIZE,返回一个为存储器地址操作数所分配的字节数。,一般来说,若一个存储单元操作数,X,,则,size X=(length,X)(type,X),IBM,宏汇编中的合成运算符为,PTR,和,THIS,,它们能建立起一些新的存储器地址操作数。,PTR,运算符能产生一个新的存储器地址操作数,(,一个变量或标号,),。新的操作数的段地址和段内偏移量与,PTR,运算符右边的操作数的对应分量相同,而类型由,PTR,的左边的操作数指定。不像一个数据定义语句,,PTR,操作数并不分配存储器,它可以给已分配的存储器一个另外的定义。,段交叉转移合成运算符,THIS,与,PTR,类似,也可以建立一个新的存储器地址操作数,并且不分配存储器。用运算符,THIS,建立起来的新的存储器地址操作数的类型在,THIS,中指定,而它的段地址和段内偏移量就是汇编时的当前值。,4.3.3,段定义语句,8086,的存储器是分段的,所以,8086,必须按段来组织程序和利用存储器,这就需要有段定义语句。段定义的主要命令有:,(1)SEGMENT,,,(2)ENDS,,,(3)ASSUME,,,(4)ORG,。,SEGMENT,和,ENDS,语句把汇编语言源程序分成段,这些段就相应于存储器段,在这些存储器段中,存放相应段的目标码。,汇编程序必须知道程序的段结构,并知道在各种指令执行时将访问哪一个段由段寄存器所指向。这个信息是由,ASSUME,语句提供的。,通常在汇编语言的源程序中,至少要定义码段,(,指令段,),、堆栈段和数据段,有时还要定义附加段。每一个段必须有一个名称,如,MY_DATA,、,MY_CODE,等。一个段由命令,SEGMENT,开始,由命令,ENDS,结束,它们必须成对出现,而且它们的语句中必须有名称,名称必须相同。最后用语句,END,来结束整个源程序。,ASSUME,语句,只是使汇编程序知道在程序执行时各个段寄存器的值,而这些段寄存器的实际值,(,除了码段寄存器,CS,以外,),,还必须在程序执行时,用,MOV,指令来赋给。,一般来说,存储器段具体在哪儿是不重要的,可由汇编程序来选择。但是,在有些情况下,可能要给汇编程序一些约束,例如:“不要使这个段与别的段搭接”,保证这个段所用的第一个字节在偶数地址,这样对于一个字的访问可以在一个存储器读写周期完成。或“在下列地址开始这个段”。可以把这些约束写入到源程序中。,另一个语句,ORG(origin,),,它规定了段内的起始地址。伪指令,ORG,的一般格式为:,ORG,表达式,此语句指定了段内在它以后的程序或数据块存放的起始地址,即以语句中的表达式的值作为起始地址,连续存放,除非遇到一个新的,ORG,语句。,4.3.4,过程定义语句,过程是程序的一部分,它们可被程序调用。每次可以调用一个过程。当过程中的指令执行完后,控制返回调用它的地方。,在,8086,中调用过程和从过程返回的指令是,CALL,和,RET,。这些指令可以有两种情况:段内的和段交叉的。,段交叉指令把过程应该返回处的段地址和段内偏移量这两者都入栈保护,(CALL,指令,),和退栈,(RET,指令,),。,段内的调用与返回指令只入栈和退栈段内的地址偏移量。,过程定义语句的格式为:,PROCEDURE_NAMEPROCNEAR,或,PROCEDURE_NAMEPROCFAR,RET,PROCEDURE_NAMEENDP,伪指令,PROC,与,ENDP,都必须有名称,两者必须成对出现,名称必须相同。利用过程调用语句可以把程序分段,以便于阅读、理解、调试和修改。,若整个程序由主程序和若干个子程序组成,则主程序和这些子程序必须一起包含在码段中,(,除非用段交叉调用,),。主程序和各个子程序都作为一个过程,用上述的过程定义语句来定义。,用段内,CALL,指令调用的过程,必须用段内的,RET,指令返回,这样的过程是,NEAR,过程;用段交叉,CALL,指令调用的过程,必须用段交叉,RET,指令返回,这样的过程是,FAR,过程。,过程定义语句,PROC,和,ENDP(End,Procedure),限定了一个过程且指出它是一个,NEAR,或,FAR,过程。这在两方面帮助了汇编程序。,4.3.5,结束语句,除了一个例外,(END,结束语句,),以外,每一个结束语句,(Termination Statements),都与某个开始语句成对出现。例如,,SEGMENT,和,ENDS,,,PROC,和,ENDP,。,惟一的例外就是,END,语句,它标志着整个源程序的结束,它告诉汇编程序,没有更多的指令要汇编了。,END,语句的格式是:,END,表达式,其中,表达式必须产生一个存储器地址值,这个地址是当程序执行时,第一条要执行的指令的地址。,4.4,指 令 语 句,每一条指令语句,使汇编程序产生一条,8086,指令。一条,8086,指令是由一个操作码字段和一些由操作数寻址方式所指定的字段组成的。,所以在,IBM,宏汇编的指令语句,必须包括一个指令助记符,以及充分的寻址信息以允许汇编程序产生一条指令。,4.4.1,指令助记符,大多数指令助记符,(Instruction Mnemonics),与,8086,指令的符号操作码名相同。某些附加的指令助记符,如,NIL,和,NOP,使得汇编语言更加通用。,1.,NOP(No,Operation),指令助记符,NOP,,使汇编程序产生一字节指令,它使寄存器,AX,的内容自行交换。除了不做任何事以外,,NOP,并不浪费任何不做的时间,因为它并不做任何的存储器访问。,NOP,可以保留一些单元为以后填入指令用。另外,当需要精确的时间关系时,这也可以使程序的一部分放慢。,2.,保留空格,(Place Holder),NIL,是使汇编程序不产生任何指令的惟一的指令助记符。与,NOP,指令相比较,,NOP,使汇编程序产生一条不做任何操作的指令;而,NIL,甚至连指令都不产生。,NIL,在汇编语言程序中是为标号保留空格的。如:,CYCLE:NIL,INCAX,虽然它与以下语句等效:,CYCLE INCAX,但有了,NIL,,若以后需要的话,便于在,INC,指令前插入其他指令。,4.4.2,指令前缀,8086,指令系统允许指令用一个或多个指令前缀,(Instruction Prefixes),开始。有三种可能的前缀:,(1),段超越,(Segment override),,,(2),重复,(Repeat),,,(3),锁定,(Lock),。,IBM,宏汇编中允许的作为前缀的助记符如下:,LOCK,REP(Repeat,,重复,),REPE(,当相等时重复,),REPNE(,当不相等时重复,),REPZ(,当标志,Z=1,时重复,),REPNZ(,当标志,Z=0,时重复,),段超越前缀是当汇编程序在汇编时认识到一个存储器访问需要这样一个前缀时,由汇编程序自动产生的。,首先,它选择一个能使程序正常执行的段寄存器。汇编程序是基于前面的,ASSUME,语句所提供的信息来选择段寄存器的。我们也可以用包含有段寄存器的指令,来迫使选择一个实际的段寄存器。如其次,汇编程序决定在用所选择的段寄存器执行指令时,是否需要一个段超越前缀。,4.4.3,操作数寻址方式,8086 CPU,提供了各种操作数寻址方式,,IBM,宏汇编在写指令语句时,必须为每一种寻址方式表示一种表达式。,立即寻址,(Immediate Addressing),寄存器寻址,(Register Addressing),直接寻址,(Direct Addressing),4.,通过基址寄存器间接寻址,(Indirect through Base Register Addressing),5.,通过变址寄存器间接寻址,(Indirect Through Index Register Addressing),6.,通过基址寄存器加变址寄存器间接寻址,(Indirect through Base Register Plus Index Register Addressing),7.,通过基址或位移量间接寻址,8.,通过基址寄存器加变址寄存器加位移量间接寻址,汇编程序在产生一条指令要涉及一个存储单元时,要用到关于这个存储单元类型的信息。,在编写汇编语言的语句时,必须使汇编程序能确定类型。,4.4.4,串操作指令,汇编程序通常可以通过一个操作数自己的说明,来确定一个操作数的类型,从而帮助汇编程序确定当访问此操作数时应产生什么样的码。,然而,当用一个间接寻址方式时,可能需要向汇编程序提供附加的信息,以帮助确定类型。,串操作指令,(String Instructions),也需要这样的附加信息。,考虑串操作指令,MOVS,。这条指令是把在数据段中的地址偏移量在,SI,中的存储单元的内容,传送给在附加段中的地址偏移量在,DI,中的存储单元。对于这样的指令,不需要规定任何操作数,因为这条指令对从哪儿传送到哪儿没有选择的可能。然而,这条指令可以传送一个字节也可以传送一个字,汇编程序就必须确定它的类型,才能产生正确的指令。为此,,IBM,宏汇编必须规定已经传送至,SI,和,DI,的项的类型。,与,MOVS,指令类似,别的四个基本的串操作指令也包括有操作数。,MOVS,和,CMPS,有两个操作数,而,SCAS,、,LODS,和,STOS,有一个操作数。也需要确定操作数的类型。,一个完整的用汇编语言编写的源程序,应该是由可执行指令组成的指令性语句和由对符号定义、分配存储单元、分段等指示性语句组成。而且,一个完整的程序至少应该包含三种段:由源程序行组成的码段,堆栈操作所需要的堆栈段以及存放数据的数据段。,汇编语言程序上机操作过程,5.4.1,汇编语言程序上机调试步骤,1,编写源程序,在弄清问题的要求,确定方案后,汇编语言程序设计者便可依据前面的指令系统和汇,编语言的规定,逐个模块地编写汇编语言源程序。,2,源程序输入微型机,在编辑软件,EDIT.EXE,或其他编辑软件的支持下,将源程序输入到计算机中。通常,汇编语言源程序的扩展名为,ASM,。,3,汇编,利用汇编程序(或宏汇编程序)(,ASM,或,MASM,),对汇编语言源程序进行汇编,产生扩展名为,OBJ,的可重定位的目的代码。,4,连接,利用连接程序(,LINK,),可将一个或多个扩展名为,OBJ,文件进行连接,生成扩展名为扩展名为,EXE,的可执行文件。,5,调试,对于稍大一些的程序来说,经过上述步骤所获得的,EXE,可执行文件,在运行过程中难免无错。,调试汇编程序最常用的工具是动态调试程序,DEBUG,。,汇编语言源程序的上机调试过程,5.4.2,汇编语言源程序的建立,当启动系统后,进入,DOS,状态,输入,EDIT,命令,就可以进入,EDIT,屏幕编辑软件,然后输入汇编语言源程序。,C:,EDIT,下面是将,ASC,码转换成二进制数的程序。设定源程序的文件名为,ABC,。,DATASEGMENT,ASCDB 5,A,6,1,BINDB 2DUP(0),DATAENDS,STACKSEGMNTSTACK STACK,DB 100DUP(?),STACKENDS,CODESEGMENT,ASSUMECS:CODE,DS:DATA,SS:STACK,START:MOVAX,DATA,MOVDS,AX,MOVCL,4,MOVCH,CL,MOVSI,OFFSET ASC,CLD,XOR AX,AX,XORDX,DX,B1:LODSASC
展开阅读全文