伪指令endp告诉汇编程序_汇编语言程序设计第二篇——80X86汇编语言伪指令

一、伪指令详解

伪指令在百度百科中的定义为:

伪指令(Pseudo Instruction)是用于对汇编过程进行控制的指令,该类指令并不是可执行指令,没有机器代码,只用于汇编过程中为汇编程序提供汇编信息。例如,提供如下信息:哪些是指令、哪些是数据及数据的字长、程序的起始地址和结束地址等。

伪指令有2个特点:由于是伪“指令”,因而它只存在于汇编语言中。高级语言中不叫指令,叫语句;

由于是“伪”指令,也即“假”指令,因而不是可执行指令,不会产生机器代码,不会占用ROM空间,只用于汇编过程中为汇编程序提供汇编信息。

与指令的区别::指令是在执行阶段发挥作用的,由CPU(Intel、AMD等)来执行。

伪指令是在编译阶段发挥作用的,由汇编器(MASM、TASM等)来解释。

二、数据定义伪指令为源程序中的数据和堆栈区分配数据存储单时,使用最多的伪指令。

数据定义伪指令格式如下:

常用的数据定义伪指令类型有:DB(定义字节,常用)一个字节数据占1个字节单元,读完一个,偏移量加1

DW(定义字,常用)一个字数据占2个字节单元,读完一个,偏移量加2

DD(定义双字)一个双字数据占4个字节单元,读完一个,偏移量加4

DQ(定义四字)一个四字数据占8个字节单元,读完一个,偏移量加8

DT(定义十字节,用于BCD码)

数据定义伪指令后面的初值表可以是常数、表达式、字符串。

例如:

D2 DW 110*230 ; 为D2分配1个字,存放表达式的值

D3 DB ‘GOOD!’ ; 为D3分配5字节,用来存放字符串‘GOOD!’

D4 DD 2.4E+3 ; 为D4分配2个字 ,存放一个浮点数

D5 DB ‘AB’ ; 为D5分配2字节,字符A在低字节,B在高字节

D6 DW ‘AB’ ;为D6分配1个字,字符A在高字节,B在低字节

S1 DB 5 DUP(?) ;为S1预留5字节的存储空间

S2 DW 3 DUP(0) ;为S2分配3个字,初值设为0语句一相当于C语言中的 DW D2 = 110*230,只不过是语法结构不太一样

注意:通过变量名操作时,变量名代表存储区的第一个数据的地址。只有DB可以定义2个字符以上的字符串。由此可见在上述代码第5行中,为D5赋值‘AB’,低字节上是A,高字节上是B,是因为DB类型数据分配的存储空间为一个字节,在第一个字节被‘A’填满后就接着在其上面开辟新的空间存储字节B。而第六行中,开辟一块DW类型的空间,在该存储空间上足以存储这两个字符,存储时在该空间从上到下进行写入,所以先把A存储到高字节位,再存储B到低字节位上。图解见下图所示。

高/低字节位的定义:计算机的数值应视为连续若干个二进制位的集合。所谓高、低字节就是此集合中位地址高/低的二进制位集合。两种模式存储‘AB’

三、符号定义伪指令

符号定义伪指令是给一个数值、字符串或表达式赋予一个名字。符号定义伪指令有等值伪指令EQU、等号伪指令“=”、符号/标号伪指令LABEL三种。

1. EQU(等值伪指令)

等值伪指令EQU用来给数值、字符串或表达式定义一个等价的符号,其格式如下:

例如:

为常量定义一个符号:

ONE EQU 1

TWO EQU 2

SUM EQU ONE+TWO

GREETING EQU 'How are you!'

符号名代表字符串“How are you!”

还可以给变量或标号定义新的类型属性并取一个新名字:

例: BYTES DB 4 DUP (?)

FIRSTW EQU WORD PTR BYTES

例:给由地址表达式指出的任意存储单元定义一个符号名:

XYZ EQU [BP+3]

A EQU ARRAY [BX] [SI]

B EQU ES: ALPHA;加段前缀的直接寻址引用

2. =(等号伪指令)

其格式如下:

使用“=”定义的符号名可以被重新定义,使符号名具有新值;等号伪指令定义的符号名仅用于代表数值表达式。

习惯上 “= ”主要用来定义符号常量:

X=18

X=X+1 ;X的值为19

EQU和“=”的区别:使用EQU伪指令定义的符号名不能与其他符号名重名,符号名必须唯一,且不能被重新定义,而使用等号伪指令定义的符号名可以重名,可以被重新定义、重新赋值。

使用EQU伪指令定义的符号名不仅可以代表某个常数或常数表达式,还可以代表字符串、关键字、指令码、一串符号(如WORD PTR)等,而使用等号伪指令定义的符号名仅用于代表数值表达式。

LABEL(符号定义伪指令)

符号定义伪指令和THIS运算符功能类似,可以为当前存储单元定义一个指定类型的变量或标号。格式如下:

其中,数据类型就是常用的数据类型:BYTE、WORD、DWORD、结构类型、记录类型、NEAR、FAR等。如果格式中的数据类型是前面5种类型之一,那么符号名就是变量名;

如果格式中的数据类型是后面两种类型之一,那么符号名就是标号名。

例如:和变量连用:

A1 LABEL BYTE

A2 DW 50 DUP(?)

第一个语句给第二个语句的变量取一个新名字,即A1和A2对应同一个单元。

例如:和标号连用:

A1 LABEL FAR

A2: MOV AX,BX

第一个语句给第二个语句的标号取一个新名字,段内调用使用A2,段间调用使用A1,

他们指向同一个地址。即标号A1和A2指到同一条指令。

四、段和过程定义伪指令

段和过程定义伪指令用来定义代码段、数据段、堆栈段和子程序。

1. 段定义伪指令

为了与存储器的分段结构相对应,汇编语言源程序也是用分段的方法来组织程序代码、数据和变量的。段定义伪指令SEGMENT/ENDS用于段的定义,格式如下:

(1) 段名:给段起的名字,必须有。定位类型、组合类型和类别名是可选的:初学者最好用默认值,什么也不写。

(2) 定位类型:确定逻辑段的起始地址:BYTE,WORD,PARA,FAGE, 默认为PARA (节),低4位地址为0。

(3) 组合类型:说明逻辑段装入内存时如何和其他段组合,有NONE, PUBLIC, STACK, COMMON, MEMORY, AT 6种说明:NONE为默认值,表示本段和其他段不发生关系具有独立的段地址。

PUBLIC:将同名同类型的段相邻地连接到一起,具有共同的段地址。

STACK:和PUBLIC功能一样,但用于堆栈段,定义堆栈段必须有。

COMMON:所有同名同类型段具有相同段地址,但后面的会覆盖前面的,用于共享数据。

MEMORY:将本段定义在其他段之后。

AT :将本段定义在表达式指定位置,但代码段不能用。(4) 类别:用户自定义的类别名,用单引号括起来,如'STACK','CODE','DATA'。连接程序会把类别名相同的所有段装入内存的连续区域。定义段的参数了解一下就行,一般用默认就行。

例如: 定义数据段DATA:

DATA SEGMENT

BUF DB 10H, 20H

BUF1 DW 10H, 20H

DATA ENDS

使用数据段前要使用MOV指令初始化DS。

堆栈段定义举例:

STACK1 SEGMENT STACK

BUF DW 1000 DUP(0)

STACK1 ENDS

定义堆栈的大小是1000。

如果用户不定义堆栈,则默认使用系统的堆栈,有大量的入栈数据时要定义自己的堆栈。初始化程序时要使用MOV指令初始化SS和SP。Q:使用MOV指令初始化SS和SP有什么作用?

A:8086CPU中,段寄存器SS:存放栈顶段地址,段寄存器SP: 存放栈顶的偏移地址。初始化SS与SP方便进行后续操作。

2. 假定伪指令

假定伪指令用在代码段中,它用来告诉汇编程序,如何设定各段与对应段寄存器的相互关系。格式如下:

段寄存器名可以是CS、DS、ES或SS,段名则是由段定义伪指令定义。

ASSUME伪指令中的段名也可以是一个特别的关键字NOTHING,其格式如下:

表示某个段寄存器不再与任何段有关系。

例:定义代码段

CODE1 SEGMENT

ASSUME CS:CODE1 ,DS:DATA1,SS:STACK1

……

CODE1 ENDS

3. 过程定义伪指令

可将具有一定功能的程序段看成一个过程(相当于一个子程序)。它可以被其他程序调用(用CALL指令)转移到这段程序执行,执行完再返回主程序。

一个过程由过程定义伪指令PROC和ENDP来定义,过程定义伪指令格式如下:

例: 设计一个延时的子程序,循环程序段执行28000次。调用该子程序可以延时一定的时间,其过程可定义如下:

SOFTDLY PROC

MOV BL, 10 ;外循环次数为10次

DELAY: MOV CX, 2800 ;内循环次数为2800次

WAIT1: LOOP WAIT1

DEC BL

JNZ DELAY

RET

SOFTDLY ENDP

延时不固定,不同的计算机上不同。80X86汇编程序随版本不同,又增加了一些伪指令,如可以在程序中使用处理器选择伪指令:.386、.486、.586等,指明汇编程序可以识别哪一种CPU的指令;使用简化段定义伪指令:.CODE、.DATA、.STACK简化段的定义;使用存储模式定义伪指令:.MODEL定义代码和数据的存储格式和占用存储器的大小,以及子程序语言类型、操作系统类型、堆栈类型等。

以上只是对伪指令的基本内容进行一些介绍,还有许多问题有待更新,请关注专栏更新!


版权声明:本文为weixin_34653651原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。