第二节 汇编语言的数据

数据是指令和伪指令语句中操作数和参数的基本组成部分。一个数据包含有它的数值和属性两部分,这两部分对一条语句汇编成机器目标代码都有直接关系。通常,汇编语言能识别的数据有:常数和标识符号(变量、标号、段名、过程名等)。此外,8086/8088汇编语言还支持结构数据。

一、常数

常数是没有任何属性的纯数值。在汇编期间,它的值已能完全确定,且在程序运行中也不会发生变化。

(一)常数的类型

汇编语言源程序中允许使用的常数有以下类型。

(1)二进制数:以字母B结尾的0和1组成的数字序列,如01011101B。

(2)八进制数:以字母O或Q结尾的0~7数字序列,如723Q,377O。

(3)十进制数:0~9数字序列,可以用字母D结尾,也可以没有结尾字母,如2000,2000D,110.11。

(4)十六进制数:以字母H结尾的0~9和A~F(或a~f)的数字字母序列,如3A40H,0FH。为了区别由A~F(或a~f)组成的一个十六进制数不是一个标识符,凡以字母A~F(或a~f)为起始的一个十六进制数,必须在前面冠以数字0,否则汇编程序认作标识符。

(5)实数:实数包含整数、小数和指数3个部分。这是计算机中的浮点表示法。实数一般用十进制数形式给出,格式为:

     ±整数部分.小数部分E±指数部分

其中,整数部分和小数部分形成这个数的值,称作尾数,它可以是带符号的数。指数部分由指数标识符E开始,它表示值的大小,如5.391E-4。汇编程序在汇编源程序时,把实数转换为由4个字节、8个字节或10个字节构成的二进制数形式存放。因此,必须用DD、DQ或DT来设置实数。

可以用十六进制数直接说明实数的二进制数编码形式,这个十六进制数必须以0~9为起始,且不带符号。最后要用实数标识符R表示。

(6)字符串常数:用引号括起来的一个或多个字符。这些字符用它的ASCII码形式存储在内存中。如A,在内存中就是41H,AB是41H42H。

(二)常数的使用

在程序中,常数的使用有以下几种情况。

(1)在指令语句中作源操作数(立即数),它应与目的操作数的位数相一致,可以是8位或16位二进制数。如:

(2)在指令语句的基址寻址方式、变址寻址方式或基址变址寻址方式中作位移量。如:

(3)在数据定义伪指令中作参数。如:

二、变量

变量代表存放在某些存储单元的数据,这些数据在程序运行期间随时可以修改。为了便于对变量的访问,它常常以变量名的形式出现在程序中。变量名是存放数据的存储单元的符号地址。

(一)变量的定义与预置

定义变量就是给变量分配存储单元,且对这个存储单元赋予一个名字——变量名,同时将这些存储单元预置初值。

定义变量是用数据定义伪指令DB、DW、DD等(有关定义6字节的DF,定义8字节的DQ,定义10字节的DT伪指令,读者需要时,可查阅有关资料)。用这种伪指令构成的语句格式是:

其中DB为定义字节伪指令(Define Byte),DW为定义字伪指令(Define Word),DD为定义双字伪指令(Define Double Word)。表达式是给变量预置的初值,可以是下述情况之一。

(1)数值表达式:数值允许用二进制、八进制、十进制、十六进制形式书写。

(2)?:表示不预置确定的值。

(3)字符串表达式:用引号括起来的不超过255个字符或其他ASCII码符号。DB伪指令将按顺序为字符串中每一个字符或符号分配一个字节单元,存放它们的ASCII编码,但DB以外的数据定义伪指令只允许定义最多2个字符的字符串,且按逆序存放在低地址开始的单元。

(4)带DUP操作符的表达式:DUP(Dup location)是定义重复数据操作符,它的使用格式是:

N为重复次数,EXP为表达式。

例:

上述语句汇编后内存分配情况如图4-1所示。

图4-1 变量内存分配示意

(二)变量的属性

经过定义的每个变量均具有3个属性。

1. 段属性(SEG)

变量是在某个段中被定义的,因此,它具有这个段的属性。这好比学生具有班级属性,职工具有单位属性一样。变量的段属性值就是变量所在段的段基值。可以通过在变量名前面冠以一个段属性值运算符(SEG)来取得变量的段属性值。

例如:

     MOV AX,SEG DATA1

这条语句传送到AX中的不是变量DATA1的值,而是它的段属性值,即DATA1所在段的段地址。

2. 偏移量属性(OFFSET)

变量的偏移量属性表示它在逻辑段中离段起始点的字节数(这好比学生具有学号属性),其属性值就是变量的偏移地址。例如图4-1中,若变量DATA1的偏移量为0,那么DATA2的偏移量就为3,DATA3的偏移量为0BH。

同样,变量的偏移量属性值可以通过偏移值属性运算符(OFFSET)取得。

段和偏移量两个属性构造了变量的逻辑地址。

3. 类型属性(TYPE)

类型属性表示变量占用存储单元的字节数。这一属性是由数据定义伪指令DB、DW、DD来规定的。变量DATA1、DATA2、DATA3是用DB定义的,它的类型属性为字节;而DATA4是用DW定义的,类型属性为字;若用DD定义的,类型属性为双字(即4个字节)。

要取得变量的某一属性值,可以使用相应的运算符完成。

变量的类型属性值如表4-1所示。

表4-1 变量的类型属性值

(三)变量的使用

变量名是存储单元的符号地址,在使用中具有两个含义:一是代表它所指向的存储单元的内容,即变量值;二是代表它所指向的存储单元的偏移地址。初学者务必加以区别。

1. 变量作为指令中的操作数,代表变量值

在指令语句中,如要对某存储单元进行存取操作,就可以直接引用它的变量名作操作数,它等同一个直接寻址的存储器操作数。请看下面例子:

上述第一条传送指令是把符号地址DA1指向的存储单元的内容0FEH(即变量DA1的值)传送给AL,第二条传送指令是把DA1+1存储单元的内容57H即变量DA1的第二个元素值传送给DL。千万不要理解为把变量DA1的值0FEH加1后传送给DL,因为变量名是地址符号,而不是数值的符号。第三条传送指令送入BX的内容是1234H,第四条传送指令送入CX的值是5678H。

2. 变量出现在伪指令的参数中或指令语句寻址方式表达式中时,代表变量偏移地址

在许多指令语句中,无论在源操作数还是目的操作数中,常采用寄存器间接寻址(基址寻址、变址寻址或基址加变址寻址)方式。这时,在寻址方式表达式中引用一个变量名就是取用它的偏移量。

例如:

第一条传送指令的目的操作数地址是DA3的偏移量加上寄存器SI的内容。而第二条传送指令的源操作数的地址是DA4的偏移量加上寄存器BX和DI的内容之和。

变量也可以作为伪指令的参数。例如:

上述示例中,前两个语句定义并预置了简单变量NUM和数组变量ARRAY。后两个语句虽然也使用数据定义伪指令,定义了两个变量ADR1和ADR2,但是这些伪指令参数字段的表达式是引用的另一变量名。这时变量ADR1和ADR2的值(即存储单元的内容)均是被引用变量名的地址——它的段基值和偏移量。如用DW,则仅有变量的偏移量;如用DD,则前两个字节存放偏移量,后两个字节存放段基值。假设上述语句所在段的段基值为0915H,NUM的偏移量为0004H,则变量ADR1的值为0004H,ADR2的值为09150004H。

三、标号

标号是一条指令目标代码的符号地址,它常作为转移指令(含子程序调用指令)的操作数。例如:

与变量类似,每个标号亦具有3个属性。

1. 段属性(SEG)

该属性表示标号所在的逻辑段。

2. 偏移量属性(OFFSET)

该属性表示标号指示的这条指令目标代码的首字节在段内离段起始点的字节数。

同样,上述两个属性构造了标号指示的指令目标代码首字节的逻辑地址。

3. 类型属性(TYPE)

该属性表示本标号可作为段内或段间的转移特性。标号的类型属性分为两种。

(1)NEAR(近):本标号只能被标号所在段的转移和调用指令所访问(即段内转移)。

(2)FAR(远):本标号可被其他段的转移和调用指令所访问(即段间转移)。

标号的类型属性值是:NEAR为-1,FAR为-2。它们可通过属性值返回运算符TYPE得到。

四、段名和过程名

段名是段定义伪指令SEGMENT前面引入的名字,过程名是过程定义伪指令PROC前面引入的名字。段名用作指令的操作数时,代表其段值,属于立即操作数,过程名用于调用语句的操作数,代表过程的起始(执行入口)地址。