关键词不能为空

当前您在: 主页 > 英语 >

第4章 伪指令与源程序格式

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-01-29 23:34
tags:

-

2021年1月29日发(作者:牙模)



4




伪指令与源程序格式



汇编语言程序的 语句有三种,即指令、伪指令,还可以有宏指令。关于宏指令将在第


7

< br>章介绍,本章介绍部分常用的伪指令


(


又称伪操作


)


。这些伪指令在程序中是必不可少的,主


要 用来定义数据变量和程序结构。本章还介绍指令中的操作数和运算符,通过本章的学习,


可以学会使用简便而有效率的指令格式,正确定义数据变量,熟知源程序的格式,编写完整


的汇编语言程序。



4.1


伪指令



伪指令和指令不同的是,


指令是在程序运行期间由计算机的


CPU


来 执行的,


而伪指令是


在汇编程序对源程序进行汇编期间由汇编程 序处理的操作。


它们可以完成如定义数据、


定义


程序模式、


分配存储区、


指示程序结束、


处理器选择等功能。


这里只介绍一些常用的伪指令。


有些和宏汇编有关的伪指令在介绍宏汇编时再作说明。



4.1.1


处理机选择伪指令


< /p>


由于


80x86


的所有处理器都支持


8086


指令系统,但每一种高档的机型又都增加了一些

< p>
新的指令。


为了能使用这些新增指令,


在编写程序 时要用处理机选择伪指令对所用的处理机


作出选择,也就是说,要告诉汇编程序应该选择 哪一种指令系统。




处理机选择伪指令有以下几种:



.8086


选择


8086


指令 系统



.286


选 择


8O286


指令系统



.286P


选择保护方式下的


80286


指令系统



.386


选择


80386


指 令系统



.386P


选择保护方式下的


8O386


指令系统



.486


选择


80 486


指令系统



.486P


选择保护方式下的


8O486


指令系统



.586


选择


Pentium


指令系统



.586P


选择保护方式下的

< br>Pentium


指令系统




指令中的点‘


.


’是需要的。这类伪指 令一般放在整个程序的最前面。如不给出,则汇


编程序认为其默认选择是


8086


指令系统。



4.1.2


段定义伪指令



我们结合第


2


章已介绍的程序实例

< p>
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



d ata


段基地址



mov ds,ax


mov dx,offset string



mov ah,9


int 21h



mov ah,4ch








1


.段定义伪指令



汇编程序在把源程 序转换为目标程序时,必须确定标号和变量


(


代码段和数据段的 符号


地址


)


的偏移地址,连接程序对针 目标程序把不同的段和模块连接在一起,确定各个段的段


地址。段地址确定了,其中的指 令、标号和变量的段地址也就确定了,这样就形成一个可执


行程序。为此,需要段定义伪 指令。



段定义伪指令格式:



segment_name SEGMENT


?



segment_name ENDS


其中


segment_name

由用户确定,大写的为关键字。段定义伪指令两句成对出现,两句


之间为其它指令。



为了确定用户定义的段和哪个段寄存器的关系,用

< p>
ASSUME


伪指令来实现。



ASSUME


伪指令格式:



ASSUME register_name:segment_name


?,


register_name:segment_name


其中


register_name


为段 寄存器名,


必须是


CS



DS



ES



SS




segment_ name


则必须是由


段定义伪指令定义的段中的段名。



ASSUME


伪指令只是指定把某个段分配给 哪一个段寄存器,


它并不能把段地址装入段寄存


器中,所以在代 码段中,还必须把段地址装入相应的段寄存器中。为此,还需要用两条


MOV

< p>
指令完成这一操作。但是,代码段不需要这样做


,


代码段的这一操作是在程序初始化时完成


的。



一般情况下,使用上述的段定义伪指令就可以了,如果需要对段定义作进一步地控制,

< br>SEGMENT


伪指令还可以增加类型及属性的说明,其格式如下:



segment_name SEGMENT [

< p>
定位类型


][


组合类型


] [


使用类型


][


“类别”

< p>
]


?



segment_name ENDS


< br>如果需要用连接程序把本程序与其他程序模块相连接时,


就需要使用这些说明,< /p>


具体内


容安排在第


6

章有关子程序的多模块设计中介绍。



2


.简化的段定义伪指令


< p>
MASM5.0


以上版本还支持一种简化的段定义方法,

< br>把例


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


code ends



end start


;汇编结束


,


程序起始点


start:




int 21h



mov ah,4ch



int 21h


end start



首先用


.MODEL


伪指令说明在内存中如何安排各个段,存储模型为


SMALL

< br>的意思是:所有


数据都放在一个


64KB


的数据段,


所有代码都放在另一个


64KB

< p>
的代码段,


数据和代码都为近访


问。这是最常用的 一种模型。



.DATA


伪指令用来定 义数据段,但没有给出段名,默认段名是


_DATA




@DATA


表示段名


_DATA


,在指令中表示段地址。



简化段定义的表达能力不如


SEGMENT


伪指令那样完整而清 楚,所以很多时候还是用


SEGMENT


伪指令。



有关简化段定义的更多说明在第


6


章有关子程序的多模块设计中介绍。



4.1.3


程序开始和结束伪指令



在前面例子中 ,


都没有使用表示程序开始的伪指令。


用户根据需要可以在程序 的开始用


NAME



TITLE


伪指令定义该程序模块名。


NAME


的格式为 :



NAME module_name


其中


module_name


为模块 的名字。如果程序中没有使用


NAME


伪指令,也可使用


TITLE


伪指令来指定模块名,其格式为:



TITLE text


其中


tex t


中的前六个字符被汇编程序作为模块的名字。



TITLE


伪指令的另一个作用是在列表文件的每一页上打印标题。标题


text


最多可有


6


0


个字符。



如果程序中既无


NAME


又无


TITL E


伪指令,


则用源文件名作为模块名。


所以


NAME



TITLE

< p>
伪指令不是必要的。



表示源程序结束的伪操作的格式为:



END [label]


汇编程序将在遇到


END


时结束汇编。


其中标号


label


指示程序开始执行的起始地址。


< br>果是多个程序模块相连接,


则只有主程序需要使用标号,


其他子程序模块则只用


END


而不能


指 定标号。



4.1.4


数据定义与存储器单元分配伪指令



我们知道,指令语句的一般格式是:



[


标号


:]


操作码



操作数


[


;注释


]


这一类伪指令的格式是:



[


变量


]


操作码


N


个操作数


[


;注释


]


其中变量字段是可 有可无的


,


它用符号地址表示。其作用与指令语句前的标号相同 。但


它的后面不跟冒号。



操作码字段 说明所用伪操作的助记符


,


即伪操作,说明所定义的数据类型。 常用的有以


下几种:



DB


伪操作用来定义字节,其后的每个操作数都占有一个字节


(8



)




DW


伪操作用来定义字,其后的每个操作数占有一个字


(16


位,其低位字节在第一个字


节地址中 ,高位字节在第二个字节地址中,即数据低位在低地址,数据高位在高地址


)

< p>



DD


伪操作用来 定义双字,其后的每个操作数占有两个字


(32



)




DF

< p>
伪操作用来定义


6


个字节的字,其后的每个操作数 占有


48


位。



DQ


伪操作用来定义


4

< p>
个字,其后的每个操作数占有


4


个字


(64



)


,可用来存放双 精



度浮点数。



DT


伪操作用来定义


1O


个字节,其后的每个操作数占有


1O


个字节,为 压缩的


BCD


码。


< br>(


需要说明的是,


MASM6


允 许


DB



DW



DD



DF



DQ



DT


伪操作分别用


BYTE



WORD



DWORD



F WORD



QWORD



TBYTE


代替


)




这些伪操作可以把其后跟着的数据存人指定的存储单元,形成初始化 数据;或者只分



配存储空间而并不确定数值。下面举例说明各种用法。




4.3


操作数为常数、数据表达式。



D_BYTE DB 10,5,10H


D_WORD DW 14,100H,-5



0ABCDH


D_DWORD DD 4


×


8


程序中默认的数据为十进制数,


10H


为十六进制数,



DB


定义的数据的值不能超出一个


字节所能表示的范围。数据


10


的符号地址是


D_BYTE


,数据


5


的符号地址是


D_BYTE+1



数据可以是负数,均为补码形式存放。允许数据表达式,如


4


×


8


,等价为

32


。当数据


第一位不是数字,应在前面加


0


,如


0ABCDH


。数据在 内存中的存放如图


4.1


所示。




D_BYTE D_WORD D_DWORD








0A


05


10


0E


00


00


01


FB


FF


CD


AB


20


00


00


00




4.1



4.3

< br>的汇编结果




4.4


操作数为字符串。问号‘


?


’仅预留空 间。数据在内存中的存放如图


4.2


所示。


MESSAGE DB 'HELLO',?


DB



ABCD




MESSAGE




43


45


4C


4C


4F


--


41


42


43


44



4.2

< br>例


4.4


的汇编结果




4.5


用操作符复制操作数。数 据在内存中的存放如图


4.3


所示。



ARRAY DB 2 DUP(1,3,2 DUP(4,5))


ARRAY




01


03


04


05


04


05


01


03


04


05


04


05



4.3



4.5


的汇编结果





4.6


指令中使用隐含类型属性。



OPER1 DB ?, ?


OPER2 DW ?, ?




MOV OPER1, 0


MOV OPER2, 0





MOV OPER2, AX


第一条指令将使


OPER1


字节单元清零,第二条指令将使


OPER2

字单元清零,因为


OPER2


为字类型变量,第三条指令两 个操作数类型一致,无需说明。




4.7


在指令中使用类型属性操作符指定操作数类型。



OPER1 DB 3, 4


OPER2 DW 5678H, 9




MOV AX



OPER1


MOV BL, OPER2


MOV [BX], 0


前两条指令操作数类型不匹配,


第三条指令的目标操作数类 型不明确,


所以都是错误的。


解决的办法是可在指令中对操作数 类型作临时性指定,


以使操作数类型匹配和明确。


这三条


指令可改为:



MOV AX



WORD PTR OPER1


MOV BL, BYTE PTR OPER2


MOV BYTE PTR[BX], 0


使用类型属性操作符


WORD PTR



BYTE PTR


可对操作 数类型进行重新指定。指令执行结


果:


AX=0403H



BL=78H




实际上一个变量也可以定义成不同类型,以方便使用。这可以用


LABEL


伪操作来定义,


格式为:



name LABEL type



4.8


把变量定义成不同类型, 指令中可灵活选用。指令执行结果如图


4.4


所示。

< p>


OPR_B LABEL BYTE


OPR_W DW 4 DUP(0)




MOV AX, 1234H


MOV OPR_B, AL


MOV OPR_W+2, AX



OPR_B


OPR_W





00


00


00


00


00


00


00


00




4.4 (1)



4.8


的数据定义



OPR_B


OPR_W




34


00


34


12


00


00


00


00



4.4 (2)

< p>


4.8


的指令执行结果



OPR_B LABEL BYTE


伪操作使得


OPR_B



OPR_W

指向同一个内存单元。



4.1.5


表达式赋值伪指令



汇编语言程序也允 许表达式,以方便程序设计。可以用赋值伪操作给表达式赋予一



个名字。其格式如下:



Expression_name EQU Expression


上式中的表达式必须是有效的操作数格式或有效的指令助记符,


此后,


程序中凡需要用


到该表达式之处,就可以用表达式名来代替了。举例如 下:



VAL EQU 86


DATA EQU VAL+5


ADDR EQU [BP+VAL]


此后,指令


MOV AX



ADDR


就代表


MOV AX


< p>
[BP+86]


,可见,


EQU

< br>伪操作的引入提


高了程序的可读性,也更加易于程序的修改。


必须注意:在


EQU


语句的表达 式中,如果有变量或标号的表达式,必须先定义后引用。




另一个更为简洁的赋值伪操作是=,格式同


EQU


,只是用=替换


EQU


。它们之间的区别

< p>


EQU


伪操作中的表达式名是不允许重复定义的 ,而=伪操作则允许重复定义。



例如,


VAL=53


VAL=VAL+53



VAL


可以多次被伪操作=赋值,而


EQU


则不允许 重复定义。



4.1.6


汇编地址计数器与定位伪指令



1


.地址计数器


$$

< br>在汇编程序对源程序汇编的过程中,


为了按序存放程序中定义的数据变量和指令,


使用


16


位的地址计数器


(location


counter)


来保存当前 正在汇编的指令的偏移地址。


当开始汇编


或在每一段开始时,把 地址计数器初始化为零,以后在汇编过程中,每处理一条指令,地址


计数器就增加一个值 ,此值为该指令所需要的字节数。地址计数器的值可用


$$


来表示 ,汇编


语言允许用户直接用


$$


来引用地 址计数器的值。


如在指令中引用


$$


,< /p>


JMP $$+8


的转向地址是本


条指令 的首地址加上


8


。显然


$$+8


必须是另一条指令的首地址,否则汇编程序将指示出错。



$$


用在伪操作的参数字段时,它所表示的是地址计数器的当前值。

< p>



4.9


考察


$$


的作用


,


假定< /p>


$$


初值


=0


,数 据在内存中的存放如图


4.5


所示。



ARRAY DW 3,$$+7,7


COU=$$


NEW DW COU


ARRAY NEW






03


00


09


00


07


00


06


00



4.5


4.9


的汇编结果




2. ORG


伪操作



ORG


伪操作用来设置当前地址计数器的值,其格式为:



ORG constant expression


如常数 表达式的值为


n


,则


ORG

< p>
伪操作可以使下一个字节的地址为


n


< p>



4.10


考察< /p>


ORG


伪操作


,


数据在内存中的存放如图


4.6


所示。



ORG 0


DB 3


ORG 4


BUFF DB 5


ORG $$+6


VAL DB 9


BUFF VAL






03


--


--


--


05


--


--


--


--


--


--


09



4.6



4.10


的汇编结果



可以看成是从< /p>


4


号单元开始定义了一个名为


BUFF< /p>


长度为


6


个字节的键盘输入缓冲区。



3



EVEN< /p>


伪操作



EVEN


伪操作使下一个变量或指令开始于偶数地址。一个字的地址最好从偶数地址开始。


例如 :



EVEN


ARRAY DW 80 DUP(?)


4



ALIGN


伪操作



ALIGN

< br>伪操作使下一个变量的地址从


4


的倍数开始,这可以用来 保证双字数组边界从


4


的倍数开始,其格式为:



ALIGN boundary


其中


Boundary


必须是


2

的幂。例如:



ALIGN 8


ARRAY DW 80 DUP(?)


4.1.7


基数控制伪指令



汇编程序默认的数为 十进制数,


所以在程序中使用其他基数表示的常数时,


需要专门 给


以标记如下:



(1)


二进制数:由一串


0


1


组成,其后跟以字母


B


,如


00101001B




(2)


十进制数:由


0



9


的数字组成的数,一般情况下,后面不必 加上标记,在指定了其



它基数的情况下,后面跟字母


D


,例如


23D




(3)


十六进制数:由


0



9



A



F


组成的数,后面跟字 母


H


。这个数的第一个字符



必须是


0



9


,所以如果第一个字符是


A


< br>F


时,应在其前面加上数字


0


, 如


0FFFFH




RADIX


伪操作可以把默认的基数改变为

< p>
2



16


范围内的任何基 数。其格式



如下:



.RADIX expression


其中表达式用来表示 基数值


(


用十进制数表示


)

< p>




注意:


在用


.RADIX


把基数定为十六进制后,


十进制数后面都应跟字母


D



在这种情况下,


如果某个十六进制数的末字符为


D


,则应在其后跟字母


H


,以免与十进 制数发生混淆。



4.1.8


过程定义伪指令



子程序又称过程,< /p>


可以把一个程序写成一个过程或多个过程,


这样可以使程序结构更 加


清晰,基本的过程定义伪指令的格式为:



procedure_name PROC Attribute




procedure_name ENDP


其中过程名


(procedure_name)


为标识符,起到标号的作用,是子程序入口的符号地址。


属性


(Attribute)


是指类型属性,可以是


NEAR



FAR


。例


4.1


的程序段可以改写为过程,见


下例:




4.11


data segment


;定义数据段


data



string db



hello,world!


$$’



data ends


code segment


;定义代码段


code


assume cs:code,ds:data


main proc far


;定义过程


main


mov ax,data


mov ds,ax


mov dx,offset string


mov ah,9


int 21h


mov ah,4ch


int 21h


main endp


code ends



end main


;汇编结束


,


程序起始点


main


该程序的过程部分也可写成:



main proc far


push ds



ds


进栈



mov ax



0



0


进栈



push ax


mov ax,data


mov ds,ax


mov dx,offset string


mov ah,9


int 21h


ret


;返回



main endp


该过程对


DOS


来说是一个远过程,这里在过程的开始把当前


DS


的值和


0


压入堆栈,过


程的最后用


RET


返回到


DOS


命令状态。这是一个固定用法。


RET


指令 使堆栈中的


2


个字


(0



DS


的值


)


弹出到


IP



CS,


实际上是执行了该处的退出程序的指令


INT 20H




增强功能的过程定义在第六 章介绍。但一般情况下,都是使用基本的过程定义。



4.2


语句格式



程序中用得最多的是指令和 有关数据定义的伪指令,这些语句基本上可以由


4


项组成,


格式如下:



[name] operation 0perand [



comment]


[


名字


]


操作



操作数


[


;注释


]


名字项是一个符号,可以是指令的标号,也可以是变量名。




操作项是一个操作码的助记符,它可以是指令、伪指令 或宏指令名。




操作数项由一 个或多个表达式组成,它提供该操作所要求的操作数或相关信息。


-


-


-


-


-


-


-


-



本文更新与2021-01-29 23:34,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/587867.html

第4章 伪指令与源程序格式的相关文章