首页 理论教育 段定义伪指令

段定义伪指令

时间:2022-02-28 理论教育 版权反馈
【摘要】:段定义语句的主要伪指令有SEGMENT、ENDS、AS-SUME和ORG。SEGMENT和ENDS语句成对使用,把汇编语言源程序分成段。ASSUME伪指令就是使汇编程序在汇编指令时,能知道各段寄存器的值。注意,代码段寄存器CS不能这样做,代码段的赋值是在程序初始化时自动完成的。ASSUME伪指令除了告诉汇编程序各段寄存器的值之外,还可以在指令中省掉很多跨段越前缀代码。伪指令ORG可设置于代码段、数据段的任何地方。

3.2.3 段定义伪指令

8086/8088系统的存储器是分段的,所以8086/8088必须按段来组织程序和使用存储器,这就需要有段定义语句。段定义语句的主要伪指令有SEGMENT、ENDS、AS-SUME和ORG。

SEGMENT和ENDS语句成对使用,把汇编语言源程序分成段。这些段就相当于存储器段,在这些段中可分为代码段、数据段、附加段和堆栈段。代码段中存放指令和伪指令、宏指令,其他段中存放伪指令。

汇编程序为什么要关心存储器段呢?这是由于首先,若有一个段内的转移或调用指令,在指令中只包含新的指令单元的16位段内偏移地址;而在一个段间的转移和调用指令,还必须包含段地址。其次,使当前(即现行)数据段和当前堆栈段的数据访问指令,对于8086/8088结构来说是最优的,因为它只包含数据单元的16位段内偏移地址,任何别的访问指令,访问处在四个当前的可寻址段中的某一个段的数据单元,在机器码指令中还必须附加一个段超越前缀(增加一个8位字节)。

因此汇编程序必须知道程序的段结构,并知道在各种指令执行时将访问哪一个段——由段寄存器指出这个信息,并应由ASSUME语句提供。

下面的程序是一个简单的例子,它说明了如何使用SEGMENT、ENDS和ASSUME伪指令来定义代码段、数据段、附加段和堆栈段。

【例3-25】

DATA SEGMENT

A DB ?

B DW ?

C DD ?

DATA ENDS

EXTRA SEGMENT

ALPHA DB ?

BETA DW?

GAMMA DD?

EXTRA ENDS

STACK SEGMENT

DB 100 DUP(?)

TOP EQU$

STACK ENDS

CODE SEGMENT

ASSUME CS:CODE,DS:DATA,ES:EXTRA,SS:STACK

START:MOV AX,SEG A

MOV DS,AX

MOV AX,SEG ALPHA

MOV ES,AX

MOV AX,STACK

MOV SS,AX

MOV SP,OFFSET TOP

CODE ENDSEND START

在例3-25中,分为四段,每一段都有段定义伪指令SEGMENT和ENDS来分段,此伪指令的一般格式为:

段名 SEGMENT

段名 ENDS

其中每一个段都应有个段名(Seg ment_name),在SEGMENT和ENDS伪指令前都要用同一个段名,如:

CODE SEGMENT

CODE ENDS

这是一个段名为CODE的代码段,在SEGMENT与ENDS之间,对于数据段、附加段和堆栈段来说,一般是存储单元定义、初始化数据、分配单元数等伪指令,对于代码段来说,主要是指令序列和伪指令。

例3-25中运用了ASSUME伪指令,它的格式为:

ASSUME 段寄存器名:定义的段名,…,段寄存器名:定义的段名

其中,段寄存器名(Segment_registername)必须是CS、DS、ES和SS,而段名(Segment_name)相应于分段时,写在SEGMENT和ENDS前面的段名,如例3-25,CS:CODE,DS:DATA,等等。

任何对存储器或堆栈访问的指令,都将使用CS、DS、ES和SS段寄存器的值才能形成真正的物理地址。因此在这些指令之前,必须要首先对这些段寄存器设定它们的值,即段的起始地址。ASSUME伪指令就是使汇编程序在汇编指令时,能知道各段寄存器的值。由于ASSUME伪指令只是指定某个段分配给哪个段寄存器,但它并不能把段地址装入段寄存器中,所以DS、ES和SS段寄存器的值还必须通过MOV指令来赋予。如例3-25中从START开始的六条指令,就是给DS、ES和SS赋值的语句。注意,代码段寄存器CS不能这样做,代码段的赋值是在程序初始化时自动完成的。

ASSUME伪指令除了告诉汇编程序各段寄存器的值之外,还可以在指令中省掉很多跨段越前缀代码。如例3-25中需把DS数据段A单元的内容送到附加段ALPHA单元中去,如果DS、ES没有用ASSUME说明,那么必须要加访问数据所需要的段名,否则就会出错,程序如下:

【例3-26】

DATA SEGMENT

A DB 12H

DATA ENDS

EXTRA SEGMENT

ALPHA DB ?

EXTRA ENDS

CODE SEGMENT

ASSUME CS:CODE

START:MOV AX,DATA

MOV DS,AX

MOV AX,EXTRA

MOV ES,AX

MOV BL,DS:A

MOV ES:ALPHA,BL

CODE ENDS

END START

然而,利用ASSUME伪指令,就可以只告诉汇编程序一次,访问这些变量需要使用哪些段寄存器,而不需在每条指令中,在每个数据前加上段名,如下面程序改写为:

DATA SEGMENT

A DB 12H

DATA ENDS

EXTRA SEGMENT

ALPHA DB ?

EXTRA ENDS

CODE SEGMENT

ASSUME CS:CODE,DS:DATA,ES:EXTRA

START:MOV AX,DATA

MOV DS,AX

MOV AX,EXTRA

MOV ES,AX

MOV BL,A

MOV ALPHA,BL

CODE ENDS

END START

段内的偏移地址是从段名SEGMENT以下,以0000H作为开始,以后每分配一个字节,偏移地址加1。

【例3-27】 DATA SEGMENT

AAA DB 12H

BBB DW ?

CCC DD 9C56H

DATA ENDS

AAA单元的偏移地址为0000H,也即存放12H数据单元的地址。BBB为空字单元,它的偏移地址为0001H,CCC为双字单元,该单元偏移地址为0003H。为了给存储单元设置起始偏移地址,可以用ORG伪指令。

格式:ORG〈表达式〉

其中表达式必须是一个可计算得到正整数的、数值范围为0~65535的表达式。

【例3-28】 DATA SEGMENT

ORG 100H

AAA DB 12H

BBB DW ?

CCC DD 9C56H DATA ENDS

此时因用了ORG伪指令重新设置DATA数据段的起始偏移地址为100H,所以AAA单元偏移地址为0100H,BBB单元偏移地址为0101H,CCC单元偏移地址为0103H。

伪指令ORG可设置于代码段、数据段的任何地方。这表明程序和数据要从某一特定的地址开始存放,但在大多数程序中都不需要ORG,汇编程序都从每段的0000H开始存放程序和数据。

在汇编程序对源程序汇编的过程中,使用地址计数器来保存当前正在汇编的指令地址。地址计数器值可用“$”来表示,汇编语言允许用户直接用“$”来引用地址计数器的当前值,因此ORG$+8可以表示从当前地址开始跳过8个字节存储单元。在指令和伪指令中也可直接用“$”表示地址计数器的当前值,如:

1000:2543 JNE $+6…

1000:2549 ……则转移地址是JNE指令的首地址加上6(即2549H),即在指令中使用的“$”表示本指令中的第一个字节的偏移地址(2543H)。而在伪指令中的参数字段中使用$,它表示地址计数器的当前值,如:

【例3-29】 ARRAY DW 1,2,$+4,3,4,$+4

若汇编时ARRAY分配的偏移地址为0074H,则汇编后ARRAY数组的存储情况如图3-7所示。

img69

图3-7 ARRAY数组汇编后的存储情况

注意,ARRAY数组中的两个$+4得到的结果是不同的,这是由于“$”的值在不断变化的缘故。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈