资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第四章汇编语言语法,汇编语言语句格式,()指令语句格式,标号:指令助记符操作数;注释,标号字段:是一个任选字段,性质为符号便移量,一般用于标记跳转指令的目的地址在汇编过程中标号会被替换为一个位的数值偏移量标号必须位于语句开头,结尾必须使用冒号。,指令助记符和操作数:这两个字段组成汇编指令本身,指令助记符是必不可少的,操作数则根据指令助记符来确定在汇编过程中,也只有这两个字段会被替换为确定的机器指令代码,注释字段:是一个任选字段,用于说明程序片段或指令的功能,汇编过程中不处理这样的字段,它只是用于提高源程序的可读性注释必须使用分号作为开始。,例子:教材例,.1.1,()伪指令语句格式,伪指令语句:这种语句用于指示汇编程序(翻译程序)如何汇编源程序和指令语句不同,汇编程序处理它时不会产生机器指令代码,只对伪指令提出的要求进行解释并立即完成要求的操作,伪指令的功能大致有分配存储单元、计算表达式、定义常量等等。,符号名伪指令符操作数;注释,符号名字段:一个任选字段,针对不同的伪指令符,符号名可以是常量名、变量名、子程序名称、结构名称、记录名称。都是一些抽象的名称,在最终的目标代码中不会出现,只是在汇编过程中使用。,伪指令符:伪指令语句中必不可少的字段,由它指示汇编程序所要完成的具体操作。,操作数字段:由伪指令操作符决定。操作数可以是常数、字符串、常量名、变量名、表达式等。,注释字段:任选字段,必须以分号开始,与指令语句中的注释字段相同,用于提高程序的可读性。,例子:教材,P63,例,4.1.2,(,3,)标识符,标识符是汇编语言中所有用户定义符号名称的总称,它有一定的构成规则:,(,a,)字符个数在,1,个到,31,个之间。,(,b,)第一个字符必须是字母或特殊字符(特殊字符:?, _ . $,),(,c,)除第一个字符外,其他字符可以是字母、数字、特殊字符,(,d,)不能使用保留字(汇编程序定义的符号名称),包括各种指令助记符、伪指令符、寄存器名称等等。,4.2,汇编语言中使用的数据,4.2.1,数据表示(常数),数据表示是指汇编语言所规定的用于表示各种数据的具体方式。,数据表示大体上可以分为数值表示和字符串表示两种情况。,数据表示也称为常数,因为各种数据表示的具体取值在汇编过程中已经完全确定,并且在程序执行阶段也不会发生任何变化。,(,1,)数值表示,二进制整数:由数字,0,和,1,组成的序列,以字母,B,作为结尾。例如,,10110101B,。,八进制整数:由,0 7,之间任意数字组成的数字序列,以字母,Q,或,O,结尾。例如,,35761Q,。,十进制整数:由,0 9,之间任意数字组成的数字序列,以字母,D,结尾或结尾不带任何字母。,十六进制整数:由,0 9,或,A F,之间的任意数字或字母组成的序列,以字母,H,结尾。例如,,0A845H,。,如果十六进制整数以字母作为最高位,那么前面必须添一个,0,,这是语法要求。,十进制实数:,整数部分,.,小数部分,E,指数部分,例如十进制实数,- 13835.67 * 10,-3,在汇编语言中表示为,- 13835.67E-3,除了十进制表示以外,还可以使用二进制浮点编码形式表示实数,这种表示形式和机器表示实数的方法是一致的。,在空间分配方面,定义一个实数至少需要,4,个字节,也可以使用,8,字节或,10,字节的空间。,(,2,)字符串表示,使用单引号或双引号括起来的任意字符序列称为字符串。例如:,Hello, world!,A,678,(,3,)常数在程序中的用途,1,)在指令语句中作为立即数,MOV AX,,,45F3H,MOV BL,,,C,2,)在指令语句中作为偏移量中的位移量分量,MOV AX,,,1000H,ADD 10HBX,,,AX,3,)在数据定义伪指令中,作为存储单元存放的初值,DB 10H,,,0F4H,DW 0D3E5H,DB Hello,注意,常数在程序运行阶段不改变不是指存储单元中的内容不改变。,4.2.2,变量,变量在汇编语言中的概念和在高级语言中的概念一致,是指某一个特定的内存单元或内存区域。(和教材中的描述有点差异),在汇编阶段,变量在段中的起始偏移量、所占用的空间已经完全被确定。,在程序执行阶段,变量中的数据随时可能发生变化。,在程序中引用变量相当于引用内存单元的偏移量,实际要访问的信息是变量中的数据。,(,1,)数据定义伪指令,语句格式:,变量名,DB,(,DW,、,DD,) 表达式,1,,表达式,2,,,;注释,语句中各字段含义如下:,变量名:是一个可选的字段,代表当前所定义内存单元的段内偏移量。(在定义内存单元时,可以不指定变量名),数据定义伪指令:必选字段,用于指明当前所定义变量所占用的空间大小。(,DB,:字节,,DW,:字,,DD,:双字,,DQ,:,8,字节,,DT,:,10,字节),下面是一个完整的数据段定义:,DATA1 SEGMENT,VAR1 DB 10H,VAR2 DW 3A4DH,VAR3 DD,?,DATA1 ENDS,我们用这个例子来解释变量所固有的三种属性。,1,)段属性(,SEG,),从变量定义的位置来看,,VAR1,、,VAR2,、,VAR3,都在同一个逻辑段,DATA1,中。这也就决定了访问这三个变量正确的段基值。,关于变量的段属性,需要注意指令中隐含使用的段寄存器,要保证正确的段基值是放在当前使用的段寄存器中。,MOV AL,,,VAR1,上面这条指令默认,DS,段寄存器中存放的是,DATA1,数据段的段基值。,2,)偏移量属性(,OFFSET,),偏移量属性是指变量相对于段起始地址的字节距离。,(注意,段起始地址和段基值是两个概念,在大多数段定义中,这两个值是相等的,一般也应该保证这两个值相等。),变量名称就是一个符号偏移量,汇编过程中,定义一个变量名时就是定义该名称对应的偏移量,在语句中引用变量名就是引用相应的偏移量。,变量的段属性和偏移量属性完全确定了变量的起始地址。段基值:偏移量构成一个完整的逻辑地址。,上个例子中,,VAR1,的偏移量为,0000H,,,VAR2,为,0001H,,,VAR3,为,0003H,。,3,)类型属性(,TYPE,),类型属性表示变量所占用的字节数,这一个属性由数据定义伪指令中的伪指令符决定。,DB,:单字节,DW,:字(双字节),DD,:双字(,4,字节),在汇编过程中,汇编程序会检查源程序中变量的类型,如果操作数类型不匹配,会提示语法错误。,例如:,MOV AL,,,VAR2,VAR2,是一个字单元,试图把一个字单元中的数据传送到一个字节寄存器中是不允许的,会出现语法错误。,原则上来说,通过段属性、偏移量属性、类型属性,已经完全可以把变量在内存中的确切起始地址、所占用的字节数确定下来了。,在汇编语言程序中访问的变量就是一个具体的、实在的变量,而不象高级语言中的变量那么抽象。,对于变量初值的设定通过表达式来完成。(程序装载到内存中以后,程序执行前变量的取值称为初值。),下面讨论定义变量初值时用到的各种表达式。,1,)数值表达式(使用整数来定义变量初值),参见教材,P66,的例,4.2.1,。,2,)字符串表达式(使用,ASCII,码来定义变量初值),参见教材,P66,的例,4.2.2,。,3,)问号表达式(定义变量初值为随机值),如果这样定义变量的初值,那么汇编程序在处理数据定义伪指令时仅为变量分配空间,并不会为它设置初值。,程序执行时,这种变量的初值就是相应内存单元中原来所有的随机值。,例子,参见教材,P67,例,4.2.3,4,)带,DUP,的表达式,数据定义伪指令语句格式:,变量名,DB,等 表达式,1 DUP,(表达式,2,),DUP,(,Duplication,)是指多次重复分配内存空间,并且为每次分配的空间定义相同的初值。,表达式,1,:定义重复分配空间的次数。,表达式,2,:定义每次所分配空间中所用的初值。,例子参见教材,P68,的例,4.2.4,注意,,DUP,关键字可以嵌套使用。,例子参见教材,P68,例如:,VAR1 DB 10H DUP,(,2,,,2 DUP,(,3,,,2 DUP,(,5,),三层,DUP,定义,第三层:,3,,,5,,,5,第二层:,2,,,3,,,5,,,5,,,3,,,5,,,5,第一层:把第二层数据重复定义,10H,次,总共占用,7*10H,个字节单元,(,2,)变量的使用,1,)变量在指令语句中的使用,在指令中引用变量名作为符号位移量可以实现直接寻址、基址寻址、变址寻址、基址变址寻址等寻址方式,对变量或变量数组中的数据进行读写操作。,例子见教材,P68,2,)在伪指令中引用变量,变量是通过伪指令语句来定义的,但这里指的不是定义变量,而是在伪指令语句中引用变量。,和在指令中引用变量相似,在伪指令中引用变量也是引用变量的段内偏移量或者变量完整的逻辑地址。,例子见教材,P69,ADR1 DW VAR1+3,;存放,VAR1+3,偏移量,ADR2 DD VAR1-2,;存放,VAR1-2,逻辑地址,注意,在伪指令中引用变量时不能使用,DB,伪指令。,4.2.3,标号(指令语句的第一个可选字段),变量是用于存放数据的内存单元所对应的偏移量,是一种符号地址。,标号同样是一种符号地址,用于指示特定内存单元的偏移量,但是和变量不同,标号所指示的地址是位于代码段中的。,标号就是程序中某一条特定指令的符号地址。在程序中引用某个标号(转移指令),就是在引用该指令在代码段中的偏移量或完整的逻辑地址。,标号的一般定义和引用,L1: INC SI,;在指令前定义标号,L1,JMP L1,;跳转到标号,L1,处,(,1,)标号的属性,和变量一样,标号也有三种固有属性,1,)段属性(,SEG,),标号是某一条指令的符号地址,一条具体的指令总是位于某一个特定的代码段。该代码段的段基值就是标号的段基值。,在程序执行过程中,当前代码段的段基值总是由,CS,段寄存器指出。,2,)偏移量属性(,OFFSET,),偏移量是指带标号指令在代码段中相对于段起始地址的字节距离。,通过段属性和偏移量属性的结合,就能够完全确定带标号指令在内存中的确切起始地址。,3,)类型属性(,TYPE,),变量的类型是指变量在内存中占用的字节空间大小。,标号的类型也有相同的含义,但是主要是指标号的引用类型。,NEAR,型:使用关键字,NEAR,说明过的标号只代表标号后指令在段内的偏移量,标号实质上是一个,16,位二进制数。这种标号只能在同一个代码段内引用(段内引用)。,FAR,型:使用关键字,FAR,说明过的标号代表标号后指令的完整逻辑地址,标号实质上是一个,32,位二进制数。这种标号可以在定义标号的段内引用,也可以在其他段引用(段间引用)。,标号的隐含属性为,NEAR,,当定义标号未指明其类型时,汇编程序会默认的把它作为,NEAR,型的标号处理。,如果需要定义,FAR,类型的标号,必须使用,LABEL,伪指令显式的定义它的类型。,(,2,),LABEL,伪指令,LABEL,伪指令与指令语句连用时,用于定义指令的标号;与数据定义伪指令连用时,用于定义变量。,1,)用,LABEL,伪指令定义标号,见教材:,NEXTF LABEL FAR,NEXT,:,ADD AL,,,BL,NEXT,为,NEAR,型的标号,,NEXTF,则为,LABEL,伪指令定义的,FAR,型标号;但是两个标号均指向同一条指令。,如果在段内使用转移指令,那么应该引用,NEXT,标号,因为它所占用的空间更小;如果在其它代码段使用转移指令,那么应该引用,NEXTF,标号,因为只有它才能给出目标指令所在段的段基值。,2,)用,LABEL,伪指令定义变量,见教材:,VARB LABEL BYTE,VARW DW 10H DUP,(,1122H,),注意,,VARB,和,VARW,两个变量的段属性和偏移量属性完全相同,具有相同的逻辑地址。但是,两个变量的类型却不相同,,VARB,是字节类型,,VARW,是字类型。,通过,LABEL,伪指令与数据定义伪指令连用,可以为同一个逻辑地址定义几种类型不同变量。,这样的变量定义方式可以使程序使用不同的类型来访问相同的内存单元。,4.3,符号定义伪指令,如果一个常数或者表达式会在源程序中经常使用,那么可以定义一个符号来表示它。,如果符号所对应的表达式很复杂,那么在源程序中使用符号会使程序描述更简单、清晰。,汇编语言中符号的概念和高级语言中常量的概念相似。,4.3.1,等值语句,语句格式:,符号,EQU,表达式,EQU,伪指令把语句右边的表达式赋值给左边的符号。,语句中的表达式可以为常数、数值表达式、地址表达式、变量名、标号、寄存器名称、指令助记符等。,在指令语句或伪指令语句中引用该符号就相当于引用它代表的表达式。在汇编过程中,源程序中的所有符号都会被替换为它代表的内容。,例子见教材,P71,注意:,符号仅在源程序汇编阶段是有效的,在程序执行阶段并没有符号这一概念。在目标代码中符号都已经全部被替换为相应的数值。,符号仅是语法上定义的常量,在源程序中可以方便的引用,但是符号定义本身并没有分配任何存储单元。这一点要和变量区别开来。,使用,EQU,伪指令定义符号后,不能够再次使用,EQU,伪指令对该符号进行重新定义。如果在源程序中出现这种情况,将被视为语法错误。,4.3.2,等号语句,语句格式:,符号,=,表达式,等号语句的作用和等值语句完全一致,区别是已经用等号定义过的符号可以再次使用等号修改其定义。,例子见教材,P72,4.4,表达式与运算符,汇编语言的指令和伪指令中都可以使用表达式来描述操作数,这是汇编语言比机器语言更高级的一个方面,如果没有表达式,那么描述操作数会很不方便。,表达式:由常数、变量、标号等元素通过各种运算符连接而成的算式。在汇编语言中,表达式一般分为数值表达式和地址表达式两种。,运算符:汇编语言中的运算符有五种,包括算术运算符、逻辑运算符、关系运算符、数值返回运算符、属性与分离运算符。,汇编语言中,所有运算符的分类可以参照教材,P73,的表,4-1,。,特别注意,对所有表达式的计算过程都是在汇编阶段完成的,最后生成的目标代码中,表达式都被替换为具体的数值了。,4.4.1,算术运算符,可用于数值表达式的运算符:,+,、,-,、*、,/,、,MOD,、,SHL,、,SHR,可用于地址表达式的运算符:,+,、,-,、, ,注意,这里所有算术运算都是整数运算。,例子,见教材,P73,注意,表达式的计算一定是在汇编过程中完成的,不是在程序的执行阶段来完成。看下面一个例子。,MOV AL,,,ARRY3,源操作数是用一个地址表达式给出的,汇编过程中会完成,ARRY+3,的计算,并用计算结果替换表达式。其寻址方式为直接寻址方式。,MOV AL,,,ARRYBX,源操作数的表示方式不是一个表达式,因为偏移量的计算是在指令执行阶段完成的,,ARRY,是一个符号位移量,在汇编过程中它会被替换为具体的数值,,ARRY,这一部分可以看作是一个表达式,但是,BX,这一部分决不是一个表达式,。寻址方式为基址寻址。,4.4.2,逻辑运算符,包括,AND,、,OR,、,XOR,、,NOT,四个运算符,只能用于数值表达式。,例子见教材,P74,4.4.3,关系运算符,包括,EQ,(相等)、,NE,(不等)、,LT,(小于)、,LE,(小于等于)、,GT,(大于)、,GE,(大于等于)六个运算符。,用在数值表达式中,关系运算符对左右两个表达式的值进行比较;用在地址表达式中,对左右两个变量的偏移量进行比较。注意,关系运算符左右两个表达式必须性质相同(都是数值表达式或都是变量)。,如果运算符表示的关系成立,那么运算结果为全,1,;如果不成立,运算结果为全,0,。,例子见教材,P74,4.4.4,数值返回运算符,这类运算符只能针对变量或者标号,用于返回变量或标号的段基值、偏移量、类型等固有属性。注意,和所有运算符的运算一样,返回运算同样是在程序的汇编阶段完成的,而不是在程序的执行阶段。,(,1,),SEG,运算符,加在引用的变量名或标号前面,运算结果是返回该变量或标号的段基值。,例子见教材,P75,的例,4.4.1,(,2,),OFFSET,运算符,加在引用的变量名或标号前,运算结果为返回该变量或标号的偏移量。,例子见教材,P75,(,3,),TYPE,运算符,加在引用的变量名或标号前,运算结果为返回该变量或标号占用的字节数。,例子见教材,P76,(,4,),LENGTH,运算符,只能加在引用变量名前面,返回数组中的数据个数(,注意,和每个数据占用的字节数、位数无关,)。如果定义该变量时使用了,DUP,关键字,那么返回重复的次数;如果没有使用,DUP,,那么返回,1,。,例子见教材,P76,LENGTH,运算符只有针对使用,DUP,关键字定义的变量才有实际意义。,(,5,),SIZE,运算符,只能加在引用变量名前面,返回结果相当于,LENGTH,运算符和,TYPE,运算符的乘积,即数组变量总共占用的字节数目(,数组的数据个数乘以每个数据占用的字节数,)。,例子见教材,P77,和,LENGTH,运算符一样,,SIZE,运算符也只有针对,DUP,关键字定义的数组变量才有实际意义。,4.4.5,属性与分离字节运算符,(,1,)属性运算符,这种运算符只能针对存储器寻址的内存单元。这种运算符的含义是为当前的内存操作数指定一个临时的类型属性(,TYPE,,可能和它最初定义的类型不同)。,1,),PTR,运算符,语句格式:,类型,PTR,地址,例子见教材,P77,2,),THIS,运算符,语句格式:,THIS,类型,THIS,运算符通常和,EQU,伪指令连用,定义新的变量名或标号,其段基值和偏移量和紧跟其后的变量或标号相同。在功能上和,LABEL,伪指令相似,为同一个内存地址定义不同的类型。,例子见教材,P78,(,2,)分离字节运算符,HIGH,运算符:分离,16,位数据的高,8,位。,LOW,运算符:分离,16,位数据的低,8,位。,例子见教材,P79,4.4.6,运算符的优先级,和高级语言中的运算符一样,每种运算符在表达式中有不同的优先级,可以使用圆括号来改变运算符的优先级。可以综合使用各种运算符得到复杂的表达式。,运算符的具体优先级可以参见教材,P79,的表,4-3,。,4.5,程序的段结构,前面已经讲过,8086/8088,系统中存储器的分段管理机制。一个程序至少需要一个代码段,但是一般都需要代码段、数据段、堆栈段。,这里从汇编语言语法的角度来讨论段的定义。,4.5.1,段定义伪指令,SEGMENT / ENDS,语句格式:(见教材),段名,SEGMENT,定位类型 组合类型 类别名,段名,ENDS,语句中各字段的解释如下:,(,1,)段名,是一个必选字段,具体名称由用户自己决定,需要满足标识符条件,段开始和结尾的段名必须相同。,(,2,)定位类型,是一个可选的字段,定义段起始地址。从这里可以看到段基址和段起始地址的区别。,1,),PAGE,(页):表示该段只能以页边界作为起始地址,从地址,00000H,开始,每,256,个字节单元为一个页,既然以,256,为单位,那么起始地址的低字节一定为,00H,(字节数据最大为,255,)。这样的段起始地址和段基址(低,4,位为,0,)是相等的。,2,),PARA,(节):如果没有指定定位类型字段,那么汇编程序会隐含的使用,PARA,作为该段隐含的起始地址属性。从地址,00000H,开始,每,16,个字节为一个节,那么起始地址低,4,位一定为,0H,(,4,位二进制数最大为,15,)。这种段起始地址也能和段基址保持一致。,3,),WORD,(字):表示该段起始地址以偶地址开始,起始地址的最低位一定为,0,。这种段起始地址可能不等于段基址,因为它不能保证低,4,位一定为,0,。,4,),BYTE,(字节):表示该段起始地址可以使用任意一个地址。这样的段起始地址也可能不等于段基址。,归纳起来,使用,PAGE,、,PARA,作为定位类型时,段基址一定等于段起始地址;使用,WORD,、,BYTE,作为定位类型时,段基址可能不会等于段起始地址。,为了避免不必要的麻烦,一般在程序中都使用,PARA,作为隐含的定位类型。,(,3,)组合类型,该字段是可选字段,用于定义当前段与其他各段之间的重叠、邻接关系。在多模块汇编程序的汇编过程中特别有效。,1,),NONE,:如果没有定义组合类型字段,那么,NONE,是隐含使用的组合类型。这种类型说明该段在逻辑上是一个独立的段,和其他段没有任何重叠或邻接关系。这种段对应的物理空间是相对独立的。,2,),PUBLIC,:在相同定位类型的条件下,把该段和与该段段名称相同的其他段(一般在多模块程序中出现)邻接在一起形成一个更大的段,并且相对所分配的段基值调整变量或标号对应的偏移量。,3,),COMMON,:把该段和与该段名称相同的其他段重叠在一起形成一个重叠段(多个逻辑段拥有相同的段基值),重叠段的长度取决于其中最长逻辑段的长度。,4,),STACK,:把段名和该段相同的所有段邻接在一起构成一个连续的段,并指定该段为堆栈段。操作系统准备运行该程序时根据这个连续段来设置,SS,和,SP,寄存器,从而初始化堆栈。,一般源程序中至少要有一个,STACK,段,如果没有定义这样的段,那么,SS,和,SP,寄存器的初始化不能由操作系统来完成,而必须由用户自己使用指令来实现,使用一个普通的段来作为堆栈段。,5,),MEMORY,:表示该段的起始地址位于其他所有段的后面(在程序中位于最高内存地址一端)。注意,在汇编过程中,只有第一个被解释的,MEMORY,段作为,MEMORY,组合类型,后面的,MEMORY,段全部被解释为,COMMON,段。,6,),AT,表达式,使用这种类型可以自己定义段的起始地址,但是有一定限制,表达式的取值只能是,16,位二进制数(对应地址的高,16,位),也就是说,自己定义的段起始地址低四位必须为,0,。,(,4,)类别名,是一个可选字段,必须使用单引号括起来,必须满足标识符的定义条件。类别名的含义是要求汇编程序在汇编过程中把所有类别名相同的段尽量组合为一片连续的存储空间(由于定位类型的关系,可能不会完全连续)。,例子见教材,P81,4.5.2,段寻址伪指令,ASSUME,用于指定程序中所定义的段与各段寄存器之间的对应关系,指示汇编程序在汇编过程中如何确定指令隐含使用的段寄存器。,注意,,ASSUME,语句是伪指令,它不能给段寄存器传送段基值,只能指定段与段寄存器之间的对应关系。该伪指令的作用时间也是在汇编阶段,不是在程序的执行阶段。,例子见教材,P82,可以注意到,如果不使用,ASSUME,伪指令,那么,MOV,指令大多数情况下隐含使用的段寄存器将是,DS,寄存器。,在不使用,ASSUME,伪指令的前提下,如果要使用,MOV,指令访问,ES,、,CS,等段寄存器所指示段中的变量,那么必须在指令中显示的给出段前缀。,例如:,MOV AX,,,ES,:,VAR1,ASSUME,语句的方便之处就在于它可以指示汇编程序按照语句的要求来指定指令中使用的隐含段寄存器。使程序员在多数情况下可以不在指令中显式的使用段前缀。,在程序设计中,一般,ASSUME,语句在代码段中位于所有指令语句之前。,把段基值装入段寄存器这一个过程是在程序执行阶段完成的。即便程序中使用了,ASSUME,语句,如果在程序执行阶段各段寄存器没有装入正确的段基值,那么仍然不能正确的访问内存中的数据。,4.5.3,段寄存器的装入,(,1,),CS,段寄存器的装入,CS,段寄存器和,IP,指令指针的初始化是由操作系统来完成的。,当用户向操作系统提交一个程序时,操作系统会自动把程序中第一条指令的逻辑地址装入到,CS,和,IP,中。在这之后,,CPU,就会从这条指令开始执行,并且不断修改,IP,中的内容使它指向下一条指令。,第一条指令的地址在源程序中是通过,END,伪指令来确定的。,END,伪指令一定是汇编语言源程序中的最后一条伪指令,而且一定只在源程序中出现一次。,END,语句的功能:,1,)标记源程序结束的位置:汇编程序在解释到,END,语句时,就认为源程序已经全部结束,,END,语句以后的任何语句都不会被解释。,2,)指定程序中第一条指令的逻辑地址:,END,伪指令符后面一定要带一个参数,这个参数一定是代码段中的一个标号。,该标号所指定的逻辑地址就是程序中第一条指令的地址。,汇编程序会把这个逻辑地址记载到最后生成的目标代码中,操作系统在将程序装入到内存以后,会把这个地址装入到,CS,、,IP,中。,例子见教材,P83,(,2,),DS,、,ES,段寄存器的装入,和,CS,段寄存器的装入方式不同,,DS,、,ES,的段基值装入必须由程序员使用,MOV,指令在自己的程序中来完成。,例子见教材,P84,,注意例子中的,ASSUME,语句。,对,DS,、,ES,段寄存器的初始化指令一般在代码段的最开始,因为以后的指令可能会频繁的访问数据段或附加段的数据,只有先保证段寄存器中的段基值正确,后面的数据操作才是正确的。,(,3,),SS,段寄存器的装入,SS,段寄存器的初始化过程分为两种类型,自动初始化和手动初始化。,1,)自动初始化,如果希望采用这种初始化方式,在定义堆栈段时必须使用,STACK,作为组合类型。参见教材,P84,下面。,如果使用这种方式定义堆栈段,那么在操作系统将程序装入到内存准备运行时,它会自动初始化堆栈段段寄存器,SS,和堆栈指针,SP,。,2,)手动初始化,这种初始化方式和,DS,、,ES,段寄存器的初始化过程很相似,需要在程序中使用,MOV,指令来实现。参见教材,P85,。,如果要使用组合类型不是,STACK,属性的段作为堆栈段,那么必须使用这种初始化方式。,采用手动初始化方式时,需要特别注意,,SS,和,SP,需要同时初始化。,4.6,过程(子程序)定义伪指令,PROC / ENDP,在程序设计中,经常需要把功能独立且频繁使用的代码片段组织为子程序的形式,这样可以大大提高代码重用率;也使程序结构得到很大的简化。,定义子程序的语句格式:,过程名,PROC NEAR / FAR,RET,过程名,ENDP,过程的定义必须是在代码段内,因为它是程序的一部分,关键字,PROC,和,ENDP,相当于一对括号,两个关键字之间的内容就是过程中的代码。,过程定义中需要注意:,1,)过程名:不可缺少的字段,是用户自己为子程序定义的名称,必须满足标识符的定义。,2,)过程名和标号有很多共同点,例如都有三个相同的固有属性。(教材,P85,)调用子程序和转移指令转移到某个标号这两个过程都是为了改变程序的执行流程。所不同的是,子程序调用需要保存返回点到堆栈中。,3,)一个过程中至少有一条,RET,指令(子程序返回指令),在程序执行阶段,子程序中最后一条被执行的指令一定是,RET,指令,否则子程序的设计一定有问题。,4.7,汇编语言源程序的基本结构框架,一个程序提交给操作系统后就能够获得操作系统下放的,CPU,的控制权,接下来就可以执行这个应用程序了。,程序执行完后有一件重要的事情需要完成,那就是返回操作系统,把,CPU,的控制权交还给操作系统。,对于,DOS,来说,如果应用程序不主动把,CPU,控制权返还给它,那么它将永远失去对,CPU,的控制,因为这种操作系统太简单,没有剥夺机制。,为了实现应用程序正常返回,可以采用两种程序框架。,1,)把应用程序当作操作系统的子程序,DOS,操作系统把任何一个程序装入到内存时,都会给它分配一个,PSP,(程序段前缀)空间,在,DS,、,ES,段寄存器未进行初始化之前,它们都是指向,PSP,的起始地址,该地址中存放了一条中断指令“,INT 20H”,。(教材,P86,的图,4-7,),中断调用就是系统提供的子程序,完成一些特殊的系统功能。第,20H,号中断调用,可以完成终止当前应用程序并返回,DOS,操作系统的功能。,在初始化,DS,、,ES,寄存器的过程中,,DS,、,ES,中的内容会改变,不再指向,PSP,。,如果希望使用,PSP,起始地址处存放的那条,INT 20H,指令返回,DOS,操作系统,那么应该把应用程序整个设置为一个,FAR,类型的子程序。在程序开始的时候保存逻辑地址(,DS,):,0000H,到堆栈,作为返回点。,整个程序执行完毕以后使用,RET,指令,就会使指令流程转向,PSP,的起始地址,执行,INT 20H,后会返回到操作系统。,这种程序框架参见教材,P86,。,2,)使用特定的中断调用返回,DOS,这种程序框架没有什么特别的地方,只是程序最后两条指令语句是固定的:,MOV AH,,,4CH,INT 21H,使用,21H,号中断调用的,4CH,号子功能,也能完成终止程序、返回,DOS,操作系统的功能。,例子:见教材,P87,两种程序框架的原理和格式一定要熟练。,4.8,其他伪指令,(,1,)定位伪指令,ORG,和位置计数器,汇编程序在翻译源程序的过程中,会对每一个段设置一个位置计数器,用于表示当前解释的指令或数据在段中的偏移量。,注意,位置计数器是汇编程序在汇编阶段中使用的一种工具,在程序执行阶段并没有这样一个计数器。,ORG,伪指令可以修改位置计数器的取值,从而达到指定指令或变量位置,或者预留内存空间的目的。,ORG,语句格式如下:,ORG,数值表达式,ORG,伪指令会把数值表达式的值赋给位置计数器,改变它的取值。,注意,在汇编语言的表达式中可以使用特殊符号“,$“,表示位置计数器当前的取值,也就是说可以根据位置计数器当前的取值计算一个新的取值。,例子参见教材,P87,4.8.2,标题伪指令,TITLE,语句格式:,TITLE,标题名,功能:给源程序命名一个标题。,汇编程序把源程序汇编为目标代码(,OBJ,文件)以后,还可以生成一个列表文件(,LST,文件),对程序中指令语句、变量定义、语法错误等给出详细的统计信息。,TITLE,伪指令指定的标题名会出现在,LST,文件每页的首行。,LST,文件中的信息很全面,相当于对汇编程序的这一次汇编过程做了一个总结和统计,但是在实际应用中,,LST,文件却很少被使用。,LST,文件的相关信息可以参考教材,P311,。,
展开阅读全文