第4章 伪指令与源程序格式
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第4章伪指令与源程序格式
汇编语言程序的语句有三种,即指令、伪指令,还可以有宏指令。关于宏指令将在第7章介绍,本章介绍部分常用的伪指令(又称伪操作)。这些伪指令在程序中是必不可少的,主要用来定义数据变量和程序结构。本章还介绍指令中的操作数和运算符,通过本章的学习,可以学会使用简便而有效率的指令格式,正确定义数据变量,熟知源程序的格式,编写完整的汇编语言程序。
4.1 伪指令
伪指令和指令不同的是,指令是在程序运行期间由计算机的CPU来执行的,而伪指令是在汇编程序对源程序进行汇编期间由汇编程序处理的操作。它们可以完成如定义数据、定义程序模式、分配存储区、指示程序结束、处理器选择等功能。这里只介绍一些常用的伪指令。有些和宏汇编有关的伪指令在介绍宏汇编时再作说明。
4.1.1 处理机选择伪指令
由于80x86的所有处理器都支持8086指令系统,但每一种高档的机型又都增加了一些新的指令。为了能使用这些新增指令,在编写程序时要用处理机选择伪指令对所用的处理机作出选择,也就是说,要告诉汇编程序应该选择哪一种指令系统。
处理机选择伪指令有以下几种:
.8086 选择8086指令系统
.286 选择8O286指令系统
.286P 选择保护方式下的80286指令系统
.386 选择80386指令系统
.386P 选择保护方式下的8O386指令系统
.486 选择80486指令系统
.486P 选择保护方式下的8O486指令系统
.586 选择Pentium指令系统
.586P 选择保护方式下的Pentium指令系统
指令中的点‘.’是需要的。这类伪指令一般放在整个程序的最前面。如不给出,则汇编程序认为其默认选择是8086指令系统。
4.1.2 段定义伪指令
我们结合第2章已介绍的程序实例2来看段定义,注意有分号的注释行,程序如下:例4.1
data segment ;定义数据段data
string db ‘hello,world!$’
data ends
code segment ;定义代码段code
assume cs:code,ds:data ;指定段寄存器和段的关系
start:mov ax,data ;对ds赋data段基地址
mov ds,ax
mov dx,offset string
mov ah,9
int 21h
mov ah,4ch
int 21h
code ends
end start ;汇编结束, 程序起始点start:
1.段定义伪指令
汇编程序在把源程序转换为目标程序时,必须确定标号和变量(代码段和数据段的符号地址)的偏移地址,连接程序对针目标程序把不同的段和模块连接在一起,确定各个段的段地址。段地址确定了,其中的指令、标号和变量的段地址也就确定了,这样就形成一个可执行程序。为此,需要段定义伪指令。
段定义伪指令格式:
segment_name SEGMENT
…
segment_name ENDS
其中segment_name由用户确定,大写的为关键字。段定义伪指令两句成对出现,两句之间为其它指令。
为了确定用户定义的段和哪个段寄存器的关系,用ASSUME伪指令来实现。
ASSUME伪指令格式:
ASSUME register_name:segment_name …,register_name:segment_name
其中register_name为段寄存器名,必须是CS,DS,ES和SS。而segment_name则必须是由段定义伪指令定义的段中的段名。
ASSUME伪指令只是指定把某个段分配给哪一个段寄存器,它并不能把段地址装入段寄存器中,所以在代码段中,还必须把段地址装入相应的段寄存器中。为此,还需要用两条MOV 指令完成这一操作。但是,代码段不需要这样做,代码段的这一操作是在程序初始化时完成的。
一般情况下,使用上述的段定义伪指令就可以了,如果需要对段定义作进一步地控制,SEGMENT伪指令还可以增加类型及属性的说明,其格式如下:
segment_name SEGMENT [定位类型][组合类型][ 使用类型][“类别”]
…
segment_name ENDS
如果需要用连接程序把本程序与其他程序模块相连接时,就需要使用这些说明,具体内容安排在第6章有关子程序的多模块设计中介绍。
2.简化的段定义伪指令
MASM5.0以上版本还支持一种简化的段定义方法,把例4.1程序用简化的段定义方法可以改写如下:
例4.2
.model small ;定义存储模型为small
.data ;定义数据段data
string db ‘hello,world!$’
.code ;定义代码段code
start:mov ax,@data ;对ds赋data段基地址
mov ds,ax
mov dx,offset string
mov ah,9
int 21h
mov ah,4ch
int 21h
end start
首先用.MODEL伪指令说明在内存中如何安排各个段,存储模型为SMALL的意思是:所有数据都放在一个64KB的数据段,所有代码都放在另一个64KB的代码段,数据和代码都为近访问。这是最常用的一种模型。
.DATA伪指令用来定义数据段,但没有给出段名,默认段名是_DATA。
@DATA表示段名_DATA,在指令中表示段地址。
简化段定义的表达能力不如SEGMENT伪指令那样完整而清楚,所以很多时候还是用SEGMENT伪指令。
有关简化段定义的更多说明在第6章有关子程序的多模块设计中介绍。
4.1.3 程序开始和结束伪指令
在前面例子中,都没有使用表示程序开始的伪指令。用户根据需要可以在程序的开始用NAME或TITLE伪指令定义该程序模块名。NAME的格式为:
NAME module_name
其中module_name 为模块的名字。如果程序中没有使用NAME伪指令,也可使用TITLE 伪指令来指定模块名,其格式为:
TITLE text
其中text中的前六个字符被汇编程序作为模块的名字。
TITLE伪指令的另一个作用是在列表文件的每一页上打印标题。标题text最多可有6 0个字符。
如果程序中既无NAME又无TITLE伪指令,则用源文件名作为模块名。所以NAME及TITLE 伪指令不是必要的。
表示源程序结束的伪操作的格式为:
END [label]
汇编程序将在遇到END时结束汇编。其中标号label指示程序开始执行的起始地址。如果是多个程序模块相连接,则只有主程序需要使用标号,其他子程序模块则只用END而不能指定标号。
4.1.4 数据定义与存储器单元分配伪指令
我们知道,指令语句的一般格式是:
[标号:] 操作码操作数 [;注释]
这一类伪指令的格式是:
[变量] 操作码 N个操作数 [;注释]
其中变量字段是可有可无的,它用符号地址表示。其作用与指令语句前的标号相同。但它的后面不跟冒号。
操作码字段说明所用伪操作的助记符,即伪操作,说明所定义的数据类型。常用的有以下几种:
DB 伪操作用来定义字节,其后的每个操作数都占有一个字节(8位)。
DW 伪操作用来定义字,其后的每个操作数占有一个字(16位,其低位字节在第一个字节地址中,高位字节在第二个字节地址中,即数据低位在低地址,数据高位在高地址)。
DD 伪操作用来定义双字,其后的每个操作数占有两个字(32位)。