设计指令系统及汇编语言程序设计Word文件下载.docx
《设计指令系统及汇编语言程序设计Word文件下载.docx》由会员分享,可在线阅读,更多相关《设计指令系统及汇编语言程序设计Word文件下载.docx(32页珍藏版)》请在冰豆网上搜索。
CREQUODH;
定义CR为常数(回车的ASCII代码)
TABEQUTABLE-ASCII;
定义变量
DISEQU1024*768;
定义数值表达式
ADREQUES:
[DI+3];
定义地址表达式
MEQUMOV;
定义助记符
2.等号(=)伪指令
变量名=表达式
等号(=)伪指令的功能与EQU伪指令相仿,它可以对同一个名字重复定义。
利用等号(=)伪指令可以使程序设计更加灵活。
例如下面的程序段:
TABLE=1
MOVAX,TABLE
RRRR:
ADDAX,1
┊
TABLE=TABLE+1
CMPAX,100
JNERRRR
┊
3.定义符号名伪指令LABEL
符号名LABEL类型
定义一个标号或变量名,并指定其类型。
其中符号名可以是标号或变量,LABEL伪指令通常要与指令语句或DB、DW、DD伪指令语句连用。
与指令连用时,类型属性有NEAR和FAR两种;
与DB等伪指令语句连用,可以使同一个数据区既有BYTE属性,又有WORD属性和DWORD属性,这样在以后的程序中根据不同的需要分别以字节或字为单位存取其中的数据。
LABEL伪指令具体使用如下:
DATAWLABELWORD;
变量DATAW类型为WORD
DATABDB20DUP(?
);
变量DATAB类型为BYTE
MOVDATAW,AX;
按字存入
MOVDATAB[2],AL;
按字节存入
LABEL伪指令也可以将属性已经定义为NEAR的标号再定义为FAR属性。
例如:
ABCFLABELFAR;
过程入口(远程调用)
ABCMOVAX,0000H;
过程入口(段内调用)
上面的过程既可用标号ABC在本段调用,也可以用标号ABCF被其他段调用。
2.4.3段定义伪指令
段定义伪指令在汇编语言源程序中定义逻辑段。
常用的段定义伪指令有ASSUME、SEGMENT和ENDS等。
1.段定义伪指令SEGMENT和ENDS
SEGMENT和ENDS伪指令用于定义一个逻辑段,给逻辑段赋予—个段名,并在后面的任选项中给出这个逻辑段的其他特性,如定位类型、组合类型和类别。
段定义伪指令格式如下:
段名SEGMENT[定位类型][组合类型][‘类别’]
┊
段名ENDS
说明:
SEGMENT伪指令定义一个逻辑段的开始,ENDS伪指令则表示一个逻辑段的结束,这两个伪指令总是成对出现,而且前面的段名必须一致。
两个伪指令语句之间的部分是该逻辑段的内容。
汇编语言的逻辑段包括代码段、数据段和堆栈段等。
代码段主要是程序指令和某些伪指令;
数据段用于定义数据和存储单元;
堆栈段为堆栈操作预留出存储空间。
SEGMENT伪指令后面可以有三个任选项:
1)定位类型定位类型任选项是告诉汇编程序如何确定逻辑段的边界在存储器中的位置,定位类型有四种:
①BYTE表示逻辑段边界可以从任何一个字节开始。
②WORD表示逻辑段边界从字地址开始,这样该逻辑段的起始地址必须是偶数。
③PARA表示逻辑段边界从节地址开始,16个字节称为一个节。
如果省略定位类型任选项,汇编语言程序默认该逻辑段为PARA。
④PAGE表示逻辑段边界地址从页边界开始,256个字节称为一个页。
2)组合类型SEGMENT伪指令的第二个任选项是组合类型,它告诉连接程序,装入存储器时各个逻辑段如何进行组合。
组合类型有6种。
①NONE此项为不组合,如果编程时省略SEGMENT伪指令的组合类型。
②PUBLIC汇编程序连接时,将不同程序模块中具有相同的类别名的逻辑段顺序连接成一个逻辑段装入内存。
③STACK组合类型为STACK时,编译程序把所有同名段连接成一个连续的堆栈段。
④COMMON该组合类型产生一个覆盖段。
模块连接时,如果有相同的类别名,则都从同一个地址开始装入,因而连接的逻辑段将发生重叠。
连接以后段的长度等于原来最长的逻辑段的长度,重叠部分的内容是最后一个逻辑段的内容。
⑤MEMORY组合类型为MEMORY时,表示本段在存储器中应定位在所有其他段的最高地址。
⑥ATAT组合类型表示本段可以定位在表达式所指示的边界上。
如:
AT0830H;
本段的地址从0830H开始。
3)类别名类别名必须用单引号括起来,类别名可由程序设计人员自己选定任何字符串组成,但它不能再作为程序的标号,变量名或其他定义的符号。
在连接处理时,LINK程序把类别名相同的所有段存放在连续的存储区内。
下面是一个分段结构的源程序框架:
DATAlSEGMENT
DATAlENDS
STACK1SEGMENTPARASTACK
STACK1ENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATAl,SS:
STACKl
BEGIN:
……
CODEENDS
ENDBEGIN
2.指定段址伪指令ASSUME
格式:
ASSUME段寄存器名:
段名[,段寄存器名:
段名,……]
指定段寄存器与某个逻辑段建立对应关系。
其中段寄存器名是指四个段寄存器CS、SS、DS、ES中的一个,段名是指逻辑段的段名。
ASSUME伪指令只是告诉汇编程序段寄存器与逻辑段的关系,并没有给段寄存器赋予实际的初值。
若要给段寄存器赋值,可参考下面程序:
CODESEGMENT
DATA1,SS:
MOVAX,DATA1
MOVDS,AX
MOVAX,STACKl
MOVSS,AX
2.4.4过程定义伪指令
程序设计中,我们常常把具有一定功能的程序段设计成一个子程序。
汇编程序用“过程”来构造子程序。
过程名PROC[NEAR/FAR];
NEAR与FAR只选一个,或都不选
RET
过程名ENDP
定义一个过程(子程序)。
其中,过程名不能省略,过程的开始和结束应使用同一个过程名。
过程名也就是子程序的程序名,可以通过CALI指令调用,它类同于一个标号的作用,具有三个属性:
段、偏移量和类型。
类型可以选择NEAR或FAR,如果没有选择距离类型,则默认为NEAR。
2.4.5定位伪指令ORG和当前位置计数器$
ORG数值表达式
指定在它之后的程序段或数据块所存放的单元起始地址的偏移量。
当前地址计数器‘$’它表示当前地址,即地址计数器的值。
DATASEGMENT
ORG20H
D1DB12H,13H
ORG$+01H
D2DB61H,62H,63H
DATAENDS
ASSUMECS:
CODE,……
ORG100H
MOVAX,DATA
┋
上面的数据段中,D1的段内偏移量为0020H而不是0000H,D2的段内偏移量是0023H。
代码段里,指令代码从偏移量0100H处开始。
2.4.6结束汇编指令END
END标号
通知汇编程序结束汇编。
标号为主程序执行时的入口标号。
注意,该指令并表示执行程序结束,只是汇编程序结束汇编。
而要计算机停止执行程序而退回到DOS操作系统,需用DOS调用:
MOVAH,4CH
INT21H
第2章指令系统及汇编语言程序设计
2.5汇编语言程序设计
2.5.1汇编语言程序
1.汇编语言的基本概念
使用助记符号来表示二进制格式的指令代码和变量地址的指令称为符号指令。
汇编语言程序运行之前要将其转换成机器代码,转换的过程是由编译程序完成。
2.汇编语言源程序的格式
汇编语言源程序采用分段式结构,一个汇编语言源程序由若干个逻辑段组成,每个逻辑段以SEGMENT语句开始,以ENDS语句结束,整个源程序以END语句结束(表示结束汇编)。
下面给出一个简单的汇编语言源程序。
DATASEGMENT;
定义一个名字为DATA的段
DATDB1,2,0;
在DATA段内定义3字节数据
DATAENDS;
DATA段结束
;
---------------------------------------------------------
STACKSEGMENTPARASTACK;
定义名字为STACK的堆栈段
DW20DUP(0);
堆栈段大小为20个字
STACKENDS;
堆栈段结束
CODESEGMENT;
定义一个名为CODE的程序代码段
ASSUMECS:
DATA,SS:
STACK
MOVDS,AX;
给DS赋数据段初值
MOVAL,DAT
ADDAL,DAT+1;
前两个数据相加
MOVDAT+2,AL;
和存入第三个数据的位置
MOVAH,4CH
INT21H;
使用系统调用返回操作系统
CODEENDS;
代码段结束
----------------------------------------------------------
ENDBEGIN;
源程序结束,入口地址为BEGIN
从上面的例子可以看出,汇编语言源程序由若干段组成,最上面是数据段,接下来是堆栈段,最后是代码段。
2.5.2顺序程序设计
顺序结构是解决简单问题的一种程序设计方法,它按语句书写的先后次序执行一系列操作。
程序中没有分支、循环和转移指令。
顺序结构程序在设计上比较简单,这种程序也称为直线程序。
下面举例对顺序结构程序的设计作具体说明。
【例2.54】对两个4位十进制数进行求和运算,十进制数用BCD码表示(1234+5678)。
解:
根据题意,在程序的数据段放置BCD码形式的十进制数。
在计算中考虑到多位运算,高位使用带进位加法指令,并注意进行十进制加法调整。
程序如下:
DATA1SEGMENT
DATlDB12H,34H
DAT2DB56H,78H
SUMDB?
DATA1ENDS
STACKlSEGMENTPARASTACK
DW20DUP(0)
STACKlENDS
ASSUMECS:
STACK1
MOVAX,DATA1
MOVDS,AX
MOVAL,DAT1+1
ADDAL,DAT2+1
DAA
MOVSUM+1,AL
MOVAL,DAT1
ADCAL,DAT2
MOVSUM,AL
INT21H
CODEENDS
【例2.55】试编制汇编语言程序,并按公式Z=((X+Y)*8-X)/4计算Z值,并将结果保存在RESULT中。
分析:
按题意,本题为典型的顺序结构。
在已知X、Y的情况下,只需按公式计算Z值即可,故在数据段设定了X、Y的值。
编制程序如下:
XDW2
YDW4
RESULTDW?
DATA1ENDS
DW20DUP(0)
BEGINMOVAX,DATA1
MOVBX,X
ADDBX,Y
MOVCL,3
SALBX,CL
SUBBX,X
MOVCL,2
SARBX,CL
MOVRESULT,BX
ENDBEGIN
2.5.3分支程序设计
1.分支程序设计的结构形式
分支程序结构形式如图2.16所示。
其中(a)、(b)为二分支结构,(c)为多分支结构。
2.分支程序的设计方法
测试分支程序设计方法:
选用影响状态标志的指令和条件转移指令来设计分支程序的方法。
跳转表法分支程序设计方法:
选用间接寻址的无条件转移指令来选择转向不同的程序分支。
(1)测试法分支程序设计
【例2.56】设有单字节无符号数X、Y、Z,若X+Y>
255,则求X+Z,否则求X-Z,运算结果放在F1中。
因为X,Y均为无符号数,所以当X+Y>
255时则会产生进位,即CF=1,所以可以用进位标志来判断。
程序流程图如图2.17所示。
程序段如下:
…………数据段…………
DATASEGMENT
XDB128
YDB90
ZDB50
F1DB?
…………代码段…………
ASSUMECS:
DATA
START:
MOVAX,DATA
MOVDS,AX
MOVAL,X
ADDAL,Y
JCP1
SUBAL,Z
JMPEXIT
P1:
MOVAL,X
ADDAL,Z
EXIT:
MOVF1,AL
ENDSTART
(2)跳转表法分支程序设计
1)分支地址表法
用分支地址表法实现分支程序设计的思想是:
将一系列的转移地址(即各分支处理子程序的首地址)存放在一段连续的存储区中,构成跳转表,采用间接转移指令来实现多分支转移。
【例2.57】设计多路分支程序,现有5个程序段,各程序段的首地址分别为P1,P2,P3,P4,P5,要求根据给定的参数转入相应的程序段。
分析:
根据题意,本题采用分支地址表法实现的多路分支结构程序设计,也是一种较常见的分支结构设计方法。
将5个程序段的入口地址作成表TABLE放入数据段,程序根据给定的参数计算出欲转入的程序段的首地址在TABLE中的位置后,取出该地址,跳转至该程序段。
由于表中按“字”存放数据,则每个数据的位移量是:
0、2、4、6、8。
对于给定参数N,计算位移量的公式是:
N=(N-1)*2。
TABLEDWP1,P2,P3,P4,P5;
转移地址表
DATDB3;
CHARlDB‘1’;
结果显示字符
CHAR2DB‘2’
CHAR3DB‘3’
CHAR4DB‘4’
CHAR5DB‘5’
DW20DUP(0)
MOVAX,DATA1
MOVDS,AX
MOVAL,DAT
MOVAH,00H
DECAL
SHLAL,1
LEABX,TABLE
ADDBX,AX
JMP[BX]
P1:
MOVDL,CHAR1
JMPP6
P2:
MOVDL,CHAR2
P3:
MOVDL,CHAR3
P4:
MOVDL,CHAR4
P5:
MOVDL,CHAR5
P6:
MOVAH,02H
INT21H
MOVAH,4CH
ENDBEGIN
运行后在屏幕上输出3,即运行了P3程序段。
该程序利用了分支地址表法设计程序的走向。
实际应用时,可以在各程序段中放入实际程序。
2)转移指令表法
转移指令表与上述的分支地址表法相比有两点区别:
其一,构成跳转表里不是n个分支程序入口处的偏移地址,而是转向n个分支程序的无条件转移指令:
JMPBRi
(i=0,1,2,3,……,n-1);
其二,跳转表不是用DW或DD指令定义,而是作为代码段的一段程序,该跳转表的首址BASE不是变量而是标号。
当需要跳转到第i个分支时,只需将标号BASE的偏移地址与2*i之和送BX,然后使用指令:
JMPBX
即使程序转向
JMPBRi
进而转向BRi分支。
【例2.58】根据键盘输入数字0,1,2和3分别显示信息“8086/8088”,“80386”,“80486”,“Pentium”。
将4条无件短转移指令(该指令占2个字节)依次存放在基地址为BASE的跳转表中,这些指令的功能分别是转向显示信息“8086/8088”,“80386”,“80486”及“Pentium”的分支程序。
程序如下:
DSEGSEGMENT
MESS0DB‘8086/8088’,’$’
MESS1DB‘80386’,’$’
MESS2DB‘80486’,’$’
MESS3DB‘Pentium’,’$’
DSEGENDS
…………堆栈段…………
SSEGSEGMENT
DB80DUP(0)
SSEGENDS
CSEGSEGMENT
ASSUMEDS:
DSEG,SS:
SSEG,CS:
CSEG
START:
MOVAX,DSEG
MOVDS,AX
MOVAH,01H
INT21H;
从键盘输入’0’,’1’,’2’,’3’的ASCII码到AL
ANDAL,0FH;
将输入’0’,’1’,’2’,’3’的转换为数字i
SHLAL,1;
AX←2*i
CBW
MOVBX,OFFSETBASE
ADDBX,AX
JMPBX
BASE:
JMPSHORTM0
JMPSHORTM1
JMPSHORTM2
JMPSHORTM3
M0:
MOVDX,OFFSETMESS0
JMPDISP
M1:
MOVDX,OFFSETMESS1
M2:
MOVDX,OFFSETMESS2
M3:
MOVDX,OFFSETMESS3
DISP:
MOVAH,09H
INT21H
MOVAH,4CH
CSEGENDS
ENDSTART
当需要实现超出短转移范围的近转移,或需要实现远转移时,跳转表中的指令就应该相应改为无条件近转移指令或无条件远转移指令,这两种指令分别占用3个字节和5个字节。
对于上例来说,应该对BX的内容的设置作相应的修改。
具体如何修改,请读者自己思考。
2.5.4循环结构程序设计
1.循环结构的组成
循环结构主要有三部分组成:
1)1)
初始化部分包括设置地址指针、计数器及其它变量的初值等为循环做的准备工作;
2)2)
循环体部分这是主要部分,即对问题的处理;
3)3)
循环控制部分包括每次执行循环体之后或之前参数的修改,对循环条件的判断等。
循环程序结构如图2.20所示,其中图2.18(a)是“先工作后控制”的结构,这种结构下,循环工作部分至少被执行一次;
图2.18(b)是“先控制后工作”的结构,这种结构下允许“0”次循环。
2.循环的分类
按照“先判断”还是“先执行”,可以分成“当型循环”与“直到型循环”;
按照循环条件,可以分成“循环次数已知”与“循环次数未知”。
汇编语言程序设计中更主要的是按照是否已知循环次数来区分,分别写成不同形式的程序代码。
另外,按照是否有循环嵌套,还可分成单重循环结构与多重循环结构。
3.单循环程序的设计方法
(1)“循环次数已知型”的程序设计
这种程序设计方法很直观、流程比较清晰,但必须在循环次数已知的的条件下才能采用。
【例2.59】在以NUM为首址的存区中存有n个带符号的字节类型的数据,从中找出最大数并送入MAX单元。
编程方法是首将先第1单元内容送AL中,然后将AL中内容与后面余下的n-1个数据进行比较,若AL中内容大于内存单元中内容,则保持AL中内容不变,否则将内存单元中内容送AL中。
最后AL中就为最大数并送MAX单元,程序流程图如图2.19所示。
DATASEGMENT
NUMDB