5.2 汇编语言源程序的格式
    在第四章介绍指令系统时曾给出若干程序举例,但是,它们仅仅是一些程序片段,并不是完整规范的汇编语言源程序。下而给出一个比较简单,然而比较规范的汇编语言源程序。
5.1 要求将两个五字节16进制数相加,可以编写出以下汇编语言源程序。
        DATA    SEGMENT                                        ;定义数据段
                DATA1    DB 0F8H60H0ACH74H3BH          ;被加数
                DATA2    DB 0C1H36H9EH0D5H20H          ;加数
                DATA    ENDS                                    ;数据段结束
        CODE    SEGMMENT                                        ;定义代码段
                ASSUME CSCODEDSDATA
            STARTMOV    AXDATA
                  MOV    DSAX                                ;初始化DS
                  MOV    CX5                               ;循环次数送CX
          MOV  SI0                ;置SI初值为0
          CLC                    ;清CF标志
      LOOPERMOV  ALDATA2[SI]            ;取一个字节加数
          ADC  DATA1[SI]AL            ;与被加数相加
          INC    SI                ;SI1
          DEC  CX                 ;CX1
          汇编指令有多少个JNZ    LOOPER              ;若不等于0,转LOOPER
          MOV  AH4CH
          INT  21H                 ;返回DOS
      CODE  END                    ;代码段结束
          END  START                ;源程序结束

    5.2.1 分段结构
    由上面的例子可以看出,汇编语言源程序的结构是分段结构形式,一个汇编语言源程序由若干段(SEGMENT)组成,每个段以SEGMENT语句开始,以ENDS语句结束。整个源程序的结尾是END语句。
    这里所说的汇编语言源程序中的段与前面讨论的CPU管理的存储器的段,既有联系,又在概念上有所区别。我们已经知道,微处理器对存储器的管理是分段的,因而,在汇编语言程序中也要求分段组织指令、数据和堆栈,以便将源程序汇编成为目标程序后,可以分别装入存储器的相应段中。但是,以8086/8088 CPU为例,它有四个段寄存器(CSESSSDS),因此CPU对存储器按照四个物理段进行管理,即数据段,附加段,堆栈段和代码段。 任何时侯CPU只能访问四个物理段。而在汇编语言源程序中,设置段的自由度比较大。例如一个源程序中可以有多个数据段或多个代码段等等。一般来说,汇编语言源程序中段的数目可以根据实际需要而设定。为了和CPU管理的存储器物理段相区别,我们将汇编语言程序中的段称为逻辑段。在不致发生混淆的地方,有时简称为段。
    在上面的简单源程序中只有两个逻辑段,一个逻辑段的名字是DATA,其中存放着与程序有关的数据,称为逻辑数据段;另一个逻辑段的名字是CODE,其中包含着程序的指令,称为逻辑代码段。每个段内均有若干行语句(STATEMENT),因此, 可以说一个汇编源程序是由一行一行的语句组成的。下面我们来讨论汇编语言语句的类型和组成。

    5.2.2 汇编语言语句的类型和格式
    一.语句的类型
    汇编语言源程序中的语句可以分为两种类型:指令语句,伪指令语句。
    ⒈ 指令语句:它是能产生目标代码,CPU 可以执行的能完成特定功能的语句。
    ⒉ 伪指令语句:它是一种不产生目标代码的语句,它仅仅在汇编过程中告诉汇编程序应如何汇编。例如,告诉汇编程序已写出的汇编语言源程序有几个段,段的名字是什么;定义变量,定义过程,给变量分配存储单元,给数字或表达式命名等。所以伪指令语句是为汇编程序在汇编时用的。
    二.语句的格式
    指令语句与伪指令语句的格式是类似的。一般情况下,汇编语言的语句可以由1~4部分构成:
    [名字]? 助记符? [操作数]? [;注释]
    其中带方括号的部分表示任选项,既可以有,也可以没有。例5.1中有如下语句:
    LOOPER MOV ALDATA2[SI]                  ;取一个字节加数
    DATA1 DB  0F8H60H0ACH74H3BH             ;被加数
    第一条语句是指令语句,其中“LOOPER是名字,“MOV”是指令助记符,“ALDATA2
[SI]”是操作数,后面是注释部分;第二条语句是伪指令语句,其中“DATA1”是名字,“DB”是伪指令定义符,“0F8H60H0ACH74H3BH”是操作数,后面是注释部分。下面对汇编语言中的各个组成部分进行讨论。
    ⒈ 名字
    汇编语言语句的第一个组成部分是名字(Name)。在指令语句中,这个名字是一个标号。指令语句中的标号实质上是指令的符号地址。并非每条指令语句必须有标号,但如果一条指令前面有一标号,则程序中其它地方就可以引用这个标号。在例5.1中,STARTLOOPER就是标号。标号后面通常有一个冒号。
    标号有三种属性:段、偏移量和类型。
    ① 标号的段属性是定义标号在程序段的段地址,当程序中引用一个标号时,该标号的段值应在CS寄存器中。
    ② 标号的偏移量属性表示标号所在段的起始地址到定义该标号的地址之间的字节数。偏移量是一个16位无符号数。
    ③ 标号的类型属性有两种:NEARFAR。前一种标号可以在段内被引用,地址指针为2个字节;后一种标号可以在其它段被引用,地址指针为4字节。如果定义一个标号时后跟冒
号,则汇编程序确认其类型为NEAR
    伪指令语句中的名字可以是变量名、段名、过程名。与指令语句中的标号不同,这些伪指令语句中的名字并不总是任选的,有些伪指令规定前面必须有名字,有些则不允许有名字,也有一些伪指令的名字是任选的。即不同的伪指令对于是否有名字有不同的规定。伪指令语句的名字后面通常不跟冒号,这是它和标号的一个明显区别。
    很多情况下伪指令语句中的名字是变量名,变量名代表存储器中一个数据区的名字,例如例5.1中的DATA1DATA2就是变量名。
    变量也有三种属性:段、偏移量和类型。
    ① 变量的段属性是变量所代表的数据区所在段的段地址。由于数据区一般在存储器的数据段中,因此变量的段地址常常在DSES寄存器中。
    ② 变量的偏移量属性是该变量所在段的起始地址与变量的地址之间的字节数。
    ③ 变量的类型属性有BYTE(字节)、WORD(字)、 DWORD (双字)、 QWORD (四字)、TBYTE(十字)等,表示数据区中存取操作对象的大小。
    ⒉ 助记符
    汇编语言语句中的第二个组成部分是助记符(Memonic)。
    在指令语句中的第二部分是CPU指令系统中指令的助记符,例如:MOV ADC等等。助记符约有90多种,在第四章中已经进行了详细的讨论。
    在伪指令语句中的第二部分是伪指令的定义符,例如:DBSEGMENT ENDS END等都是伪指令定义符。它们在程序中的作用是定义变量的类型、定义段以及告诉汇编程序结束汇编等。关于伪指令的作用和使用方法,将在本章第三节进行讨论。
    ⒊ 操作数
    汇编语言语句中的第三个组成部分是操作数。在指令语句中是指令的操作数,可能有单操作数或双操作数,也可能无操作数;而在伪指令中可能有更多个操作数。当操作数不止一个时,相互之间应该用逗号隔开。
    可以作为操作数的有:常数、寄存器、标号、变量和表达式等。
    ⑴ 常数
    常数就是指令中出现的哪些固定值,可以分为数值常数和字符串常数两类。例如,立即数寻址时所有的立即数,直接寻址时所有的地址,ASCII字符串都是常数, 常数是除了自身的值以外,没有其它属性的数值。在源程序中,数值常数按其基数的不同,可有二进制数,八进制数,十进制数,十六进制数等几种不同表示形式。汇编语言用不同的后缀加以
区别。
    还应指出,汇编语言中的数值常数的第一位必须是数字,否则汇编时将被看成是标识符,如常数B7H应写成0B7HFFH应写成0FFH。字符串常数是由单引号括起来的一串字符。例如‘ABCDEFG’‘179’。单引号内的字符在汇编时都以ASCII的代码形式存放在存储单元中。如上述两字符串的ASCII代码为41H42H43H44H48H31H37H39H。字符串最长允许有255个字符。
    ⑵ 寄存器
    80868088CPU的寄存器可以作为指令的操作数。
    ⑶ 标号
    由于标号代表一条指令的符号地址,因此可以作为转移(无条件转移或条件转移)、过程调用CALL以及循环控制LOOP指令的操作数。
    ⑷ 变量
    因为变量是存储器中某个数据区的名字,因此在指令中可以作为存储器操作数。
    ⑸ 表达式
    汇编语言语句中的表达式,按其性质可分为两种:数值表达式和地址表达式。数值表达
式产生一个数值结果,只有大小,没有属性。地址表达式的结果不是一个单纯的数值,而是一个表示存储器地址的变量或标号,它有三种属性:段、偏移量和类型。
    表达式中常用的运算符有以下几种:
    1) 算术运算符
    常用的算术运算符有:+(加),-(减),*(乘),/(除)和MOD(模除, 即两个整数相除后取余数)等。
    以上算术运算符可用于数值表达式,运算结果是一个数值。在地址表达式中通常只使用其中的+和-(加和减)两种运算符。
    2) 逻辑运算符
    逻辑运算符有:AND(逻辑),OR(逻辑)、XOR(逻辑异或)和 NOT(逻辑)。
    逻辑运算符只用于数值表达式中对数值进行按位逻辑运算,并得到一个数值结果。对地址进行逻辑运算是没有意义的。
    3) 关系运算符
    关系运算符有:EQ(等于),NE(不等),LT(小于),GT(大于),LE(小于或等
于),GE(大于或等于)等。
    参与关系运算的必须是两个数值或同一段中的两个存储单元地址,但运算结果只可能是两个特定的数值之一:当关系不成立(假)时,结果为0(全0);当关系成立(真)时,结果为0FFFFH(全1)。例如:
    MOV AX4 EQ 3        ;关系不成立,故(AX←0
    MOV AX4 NE 3        ;关系成立,故(AX←0FFFFH
    4) 分析运算符
    分析运算符用于分析一个存储器操作数的属性,如段值,偏移量和类型等,或取得它所定义的存储空间的大小。分析运算符有SEGOFFSETTYPESIZELENGTH等。
    ① SEG运算符
    利用运算符SEG可以得到一个标号或变量所在段的段地址。例如下面两条指令将变量ARRAY的段地址送DS寄存器。
    MOV AXSEG ARRAY
    MOV DSAX
    ② OFFSET运算符
    利用运算符OFFSET可以得到一个标号或变量的偏移地址,例如:
    MOV DIOFFSET DATA1
    ③ TYPE运算符
    运算符TYPE的运算结果是一个数值,这个数值与存储器操作数类型属性的对应关系见表5.1
    下面是使用TYPE运算符的例子:
    VAR DW                      ;变量VAR的类型为字
    ARRAY DD 10 DUP(?)                ;变量ARRAY的类型为双字
    STR DB 'THIS IS TEST'              ;变量STR的类型为字节
       
        MOV  AXTYPE VAR             ;(AX)←2
        MOV  BXTYPE ARRAY            ;(BX)←4
        MOV  CXTYPE STR              (CX)←1
      
    其中的DWDDDB等为伪指令定义符,这将在第三节中介绍。

5.1 TYPE返回值与类型的关系
TYPE返回值
存储器操作数的类型
1
BYTE
2
WORD
4
DWORD
6
FWORD
8
QWORD
10
TBYTE
-1
NEAR
-2
FAR

    ④ LENGTH运算符
    如果一个变量已用重复操作符DUP说明其变量的个数,则利用LENGTH 运算符可得到这个变量的个数。如果未用DUP说明,则得到的结果总是1
    例如上面的例子中已经用“10 DUP(?)”说明变量ARRAY的个数,则LENGTH ARRAY的结果为10
    ⑤ SIZE运算符
    如果一个变量是已用重复操作符DUP说明,则利用SIZE 运算符可得到分配给该变量的字节总数。如果未用DUP说明,则得到的结果是TYPE运算的结果。
    例如上面例子中变量ARRAY的个数为10,类型为DWORD(双字),因此,SIZE ARRAY的结果为10×440。由此可知,SIZE的运算结果等于LENGTH的运算结果乘以TYPE 的运算结果。
    5) 合成运算符
    合成运算符可以用来建立或临时改变变量或标号的类型或存储器操作数的存储单元类型。合成运算符有PTRTHISSHORT等。
    ① PTR运算符
    PTR运算符可以指定或修改存储器操作数的类型,例如:
    INC BYTE? PTR[BX][SI]
    指令中利用PTR运算符明确规定了存储器操作数的类型是BYTE(字节),因此, 本指令将一个字节型存储器操作数加1
利用PTR运算符可以建立一个新的存储器操作数,它与原来的同名操作数具有相同的段和偏移量,但可以有不同的类型。不过这个新类型只在当前语句中有效。例如:
    STUFF DD?                   ;定义STUFF为双字类型变量
      :
        MOV  BXWORD PTR STUFF       ;从STUFF中取一个字到BX
      :
    ② THIS运算符
    运算符THIS也可指定存储器操作数的类型。使用THIS运算符可以使标号或变量更具灵活性。例如要求对同一个数据区,既可以字节为单位,又可以字为单位进行存取,则可用以下语句:
    TAB1 EQU THIS WORD
    TAB2 DB  100 DUP(?)
    上面TAB1TAB2实际上代表同一个数据区,其中共有100个字节,但TAB1的类型为WORD(字类型),而TAB2的类型为BYTE(字节类型)。
    ③ SHORT运算符
    运算符SHORT指定一个标号的类型为SHORT(短标号),即标号到引用该标号指令之间的距离在-128~+127个字节的范围内。短标号可以被用于无条件转移指令中。使用短标号的指令比使用缺省的近标号的指令少一个字节。
    6) 其它运算符
    ① 段超越运算符
    运算符(冒号)跟在段寄存器名(DSESSSCS)之后,表示段超越,用以给一个存储器操作数指定一个段属性,而不管其原来隐含的段是什么。例如:
    MOV  AXES[DI]
    ② 字节分离运算符LOWHIGH
    运算符LOWHIGH分别得到一个数值或地址表达式的低位和高位字节。例如:
 

汇编语言程序格式
汇编语言源程序用语句书写,MASM中可使用的语句分成两类,他们是指令性语句和伪指令语句
1.指令性语句:指令性语句与机器指令相对应,汇编程序将他翻译成目标代码(机器指令代码)。语句格为:
标号: 指令助记符  操作数,操作数;注释
标号表示指令语句的符号地址,标号后面必须紧跟。标号可以省略,他经常作为转移指令或CALL指令的一个操作数,用以表示地址的转移。
指令助记符是该语句的指令名称的代表号码,他指出操作的类型,汇编程序将其翻译成机器指令。不可省略。
操作数表示参加本指令的运算数据,根据指令的操作类型,操作数不同,中间必须用隔开。
注释指明一条指令的功能,可以省略。
2.伪指令语句
伪指令语句没有对应的机器指令。汇编程序汇编源程序时对伪指令进行处理,他可以完成数据定义,存储区分配,段定义,段分配,指示程序结束功能。伪指令语句的格式为:
名字 伪指令指示符 操作数,操作数;注释
名字时给伪指令取得名称,他用符号地址表示。伪指令中的名字通常是变量名,段名,过程名、符号名等。
伪指令指示符是汇编程序MASM规定的符号。
操作数是根据伪指令的具体要求来得。
3.数据项
汇编语言中使用的操作数,可以是常数、寄存器、存储器、变量、标号活表达式,其中藏书、变量和标号是三种基本数据项。
常数必须是固定的值,没有属性,是确定的数据。
变量在程序运行中是可以修改的。所有的变量具有三种属性
段值(SEGMENT):指明变量所在段的基址。
段内偏移地址(OFFSET):指变量所在地址与段首地址之间的偏移字节数。
类型(TYPE):变量的类型属性指变量中每个单元所包含的字节数,类型有:字节变量(BYTE)、字变量(WORD)、双字变量(DOUBLE WORD
标号:标号是指可执行指令语句的地址的符号表示,他可作为转移指令和调用指令的目标操作数,以确定程序转换的目标地址,他具有三个属性。
段值(SEGMENT):指明标号所在段的基址。
段内偏移地址(OFFSET):指标号所在地址与所在段段首地址之间的偏移字节数。
类型(TYPE):标号的类型属性指在转移指令中标号可转移的距离类型.NEAR,表示近标号只能实现在本代码段内转移或调用;FAR,表示远标号,可;以作为其他代码段中的目标地址,实现段间调用或转移。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。