第三章汇编程序设计讲稿.docx
- 文档编号:10230994
- 上传时间:2023-02-09
- 格式:DOCX
- 页数:38
- 大小:41.60KB
第三章汇编程序设计讲稿.docx
《第三章汇编程序设计讲稿.docx》由会员分享,可在线阅读,更多相关《第三章汇编程序设计讲稿.docx(38页珍藏版)》请在冰豆网上搜索。
第三章汇编程序设计讲稿
第三章汇编语言程序设计
第一讲
回顾:
8086/8088的内部结构、寄存器功能和工作过程,指令格式、寻址方式和功能。
本讲重点:
了解汇编的概念及其方法,掌握汇编程序的基本格式,常用运算符的使用方法,汇编的步骤。
讲授内容:
3.1汇编语言的基本元素
一、汇编语言的语句格式
由汇编语言编写的源程序是由许多语句(也可称为汇编指令)组成的。
每个语句由1~4个部分组成,其格式是:
[标识符]指令助记符[操作数][;注解]
其中用方括号括起来的部分可有可无。
每部分之间用空格(至少一个)分开,一行最多可有132个字符。
1.标识符
是给指令或某一存储单元地址所起的名字,以字母或圆点开头。
可由下列字符组成:
字母:
A~z;数字:
0~9;特殊字符:
?
、·、@、一、$。
标识符最长为31个字符。
当标识符后跟冒号时,表示是标号。
它代表该行指令的起始地址;当标识符后不带冒号时,表示变量;伪指令前的标识符不加冒号。
2.指令助记符
表示不同操作的指令,可以是8088的指令助记符,也可以是伪指令。
3.操作数
是指令执行的对象。
依指令的要求,可能有一个、两个或者没有,
例如:
RET;无操作数
COUNT:
INCCX;一个操作数
如果是伪指令,则可能有多个操作数,例如:
COSTDB3,4,5,6,7;5个操作数
MOVAX,[BP十4];第二个操作数为表达式
4.注解
该项可有可无,是为源程序所加的注解,用于提高程序的可读性。
二、汇编语言的运算符
1.算术运算符、逻辑运算符和关系运算符
①算术运算符可以应用于数字操作数,结果也是数字。
而应用于存储器操作数时,只有+、-运算符有意义。
2.取值运算符SEG、OFFSET、TYPE、SIZE和LENGTH
·SEG和OFFSET分别给出一个变量或标号的段地址和偏移量。
例如,定义:
SLOTDW25
则:
MOVAX,SLOT;从SLOT地址中取一个字送入AX
MOVAX,SEGSLOT;将SLOT所在段的段地址送入AX
MOVAX,OFFSETSLOT;将SLOT所在段的段内偏移地址送AX
表3-1存储器操作数的类型属性及返回值
字节
1
字
2
双字
4
NEAR
-1
FAR
-2
·TYPE操作符返回一个表示存储器操作数类型的数值。
各种存储器地址操作数类型部分的值如表3-1所示。
·LENGTH和SIZE操作符只应用于数据存储器操作数。
(用DB/DW/DD且用DUP等定义的操作数)
LENGTH返回一个与存储器地址操作数相联系的基本数据个数,
SIZE操作数返回一个为存储器操作数分配的字节数(即单元数)。
例如:
若MULT-WORDDW50DUP(0)
则LENGTHMULT-WORD=50
SIZEMULT-WORD=100
注意:
SIZEX=(LENGTHX)*(TYPEX)
3.属性运算符
属性运算符用来给指令中的操作数指定一个临时属性,而暂时忽略当前的属性。
常用的有:
(1)合成运算符PTR
它作用于操作数时,则忽略了操作数当前的类型(字节或字)及属性(NEAR或FAR),而给出一个临时的类型或属性,
一般格式:
类型PTR表达式
功能:
建立一个存储器地址操作数,它与其后的存储器地址操作数有相同的段地址偏移量,但有不同的类型。
例如:
SLOTDW25
此时SLOT已定义成字单元。
若我们想取出它的第一个字节内容,则可用PTR对其作用,使它暂时改变为字节单元,即
MOVAL,BYTEPTRSLOT
三、表达式
是由运算符和操作数组成的序列,在汇编时产生一个确定的值。
这个值可以仅表示一个常量,也可以表示一个存储单元的偏移地址,相应的表达式称为常量表达式和地址表达式。
1.常数
汇编语言语句中出现的常数可以有7种:
①二进制数后跟字母B,如01000001B。
②八进制数后跟字母Q或O,如202Q或202O。
③十进制数后跟D或不跟字母,如85D或85。
④十六进制数后跟H,如56H,0FFH。
注意,当数字的第一个字符是A~F时,在字符前应添加一个数字0,以示和变量的区别。
另有,十进制浮点数、十六进制实数、字符和字符串
2.常量操作数
常量操作数是一个数值操作数,一般是常量或者是表示常量的标识符。
可以为数字常量操作数或字符串常量操作数。
前者可采用二进制、八进制、十进制或十六进制等计数形式;而后者则为相应字符的ASCII码。
3.存储器操作数
存储器操作数是一个地址操作数,代表一个存储单元的地址,通常以标识符的形式出现。
存储器操作数可以分为变量及标号两者类型,如果存储器操作数所代表的是某个数据在数据段、附加段或堆栈段中的地址,那么这个存储器操作数就称为变量;如果存储器操作数所代表的是某条指令代码在码段中的地址,那么这个存储器操作数称为标号。
变量所对应的存储单元内容在程序的运行过程中是可以改变的,标号通常作为转移指令或调用指令的目标操作数,在程序运行过程中不能改变。
存储器操作数有三个方面的属性。
(1)段地址:
即存储器操作数所对应的存储单元所在段的段地址;
(2)偏移地址:
即存储器操作数所对应的存储单元在所在段内的偏移地址;
(3)类型:
变量的类型是相应存储单元所存放的数据项的字节数;而标号的类型则反映了相应存储单元地址在作为转移或调用指令的目标操作数时的寻址方式,可有两种情况,即NEAR和FAR。
4.常量表达式
由常量操作数及运算符构成,在汇编时产生一个常量。
如PORT、VAL十1、OFFSETSUM、SEGSUM、TYPECYCLE等。
5.地址表达式
由存储器操作数与运算符构成,必须有明确的物理意义。
例如SUM+2、CYCLE-5
表达式SUM+2、CYCLE-5的值仍然是一个存储器操作数,该存储器操作数的段地址与类型属性分别与存储器操作数SUM及CYCLE相同,但偏移地址分别比SUM及CYCLE大2或小5。
表达式是在汇编时计算的,而变量单元的内容在程序的运行过程中可以改变。
四、汇编语言程序汇编步骤
1.编写源程序
在弄清问题的要求,确定方案后,汇编语言程序设计者便可依据前面的指令系统和汇编语言的规定,逐个模块地编写汇编语言源程序。
通常使用编辑软件(例如:
EDLIN、EDIT或其他软件),将源程序输入到计算机中。
汇编语言源程序的扩展名为.ASM。
2.汇编
利用汇编程序(或宏汇编程序)(ASM或MASM)对汇编语言源程序进行汇编,产生扩展名为.OBJ的可重定位的目的代码。
同时,如果需要,宏汇编还可以产生扩展名为.LST的列表文件和扩展名为.CRF的交叉参考文件。
前者列出汇编产生的目的代码及与之有关的地址、源语句和符号表;后者再经CREF文件处理可得各定义符号与源程序行号的对应清单。
在对源程序进行汇编过程中,汇编程序会对源程序中的非逻辑性错误给出显示,例如,源程序中使用了非法指令、标号重复、相对转移超出转移范围等等。
利用这些提示,设计者需修改源程序,以消除这些语法上的错误。
程序设计者在改正源程序中的错误过程中,重新编辑源程序,形成新的.ASM文件。
然后重新汇编,直到汇编程序显示无错误为止。
3.连接
利用连接程序(LINK)可将一个或多个.OBJ文件进行连接,生成扩展名为.EXE的可执行文件。
在连接过程中,LINK同样会给出错误提示。
设计者应根据错误提示,分析发生错误的原因,并修改源程序,然后重复前面的过程——汇编、连接,最后得到.EXE可执行文件。
4.调试
对于稍大一些的程序来说,经过上述步骤所获得的.EXE文件,在运行过程中难免无错。
也就是说,前面只能发现一些明显的语法上的错误。
而对程序的逻辑错、能否达到预期的功能均无法得知。
因此,必须对可执行文件(.EXE文件)进行调试。
通过调试来证明程序确实能达到预期的功能且没有漏洞。
程序调试通过则可进入试运行。
在试运行过程中不断进行观察、测试,发现问题及时解决,最后完成软件设计。
习题与思考:
1.下列语句在存储器中分别为变量分配多少字节空间?
并画出存储空间的分配图。
VAR1DB10,2
VAR2DW5DUP(?
),0
VAR3DB‘HOWAREYOU?
’,‘$’,3DUP(1,2)
VAR4DD-1,1,0
2.假定VAR1和VAR2为字变量,LAB为标号,试指出下列指令的错误之处。
(1)ADDVAR1,VAR2
(2)SUBAL,VAR1
(3)JMPLAB[CX](4)JNZVAR1
(5)MOV[1000H],100(6)SHLAL,4
3.对于下面的符号定义,指出下列指令的错误。
A1DB?
A2DB10
K1EQU1024
(1)MOVK1,AX
(2)MOVA1,AX
(3)CMPA1,A2(4)K1EQU2048
第二讲
回顾:
汇编的概念及其方法,掌握汇编程序的基本格式。
8086/8088的指令格式。
本讲重点:
了解伪指令的功能,掌握定义数据、符号、段、过程等伪指令的使用方法,能编写格式正确的汇编程序。
讲授内容:
3.2伪指令
伪指令用来对汇编程序进行控制,对程序中的数据实现条件转移、列表、存储空间分配等处理,其格式和汇编指令一样,但一般不产生目的代码,即不直接命令CPU去执行什么操作。
一、定义数据伪指令
该类伪指令用来定义存储空间及其所存数据的长度。
·DB:
定义字节,即每个数据是1个字节。
·DW:
定义字,即每个数据占1个字(2个字节)。
·DD:
定义双字,即每个数据占2个字。
低字在低地址,高字在高地址。
·DQ:
定义4字长,即每个数据占4个字。
·DT:
定义10个字节长,用于压缩式十进制数,
例如:
DATA1DB5,6,8,100
DATA2DW7,287
TABLEDB?
;表示在TABLE单元中存放的内容是随机的
当一个定义的存储区内的每个单元要放置同样的数据时,可用DUP操作符。
一般格式:
COUNTDUP(?
),COUNT为重复的次数,“( )”中为要重复的数据。
如:
BUFFERDB100DUP(0);表示以BUFFER为首地址的100个字节中存放00H数据
BUFFER1DB100DUP(3,5,2DUP(10),35),24,‘NUM’)
想一想存储区的情况?
二、符号定义伪指令EQU、=、及PURGE
·EQU伪指令给符号定义一个值。
在程序中,凡是出现该符号的地方,汇编时均用其值代替,
如:
TIMESEQU50
DATADBTIMESDUP(?
)
上述两个语句实际等效于如下一条语句:
DATADB50DUP(?
)
·“=”伪指令可给初始变量赋值。
如:
COUNT=100;COUNT=100
TIME=50;TIME=50
·PURGE伪指令用于释放由EQU伪指令定义的变量,使这些变量可以被重新定义。
PURGETIMES;释放TIMES变量
TIMESEQU2;重新定义
三、段定义伪指令SEGMENT和ENDS
一般来说,一个完整的汇编源程序由3个段组成,即堆栈段、数据段和代码段。
段定义伪指令可将源程序划分成若干段,以便生成目的代码和连接时将各同名段进行组合。
段定义伪指令一般格式为:
段名SEGMENT[定位类型][组合类型][类别]
段名ENDS
SEGMENT和END5应成对使用,缺—不可。
其中段名是不可省略的。
其它是可选项,是赋予段名的属性,可以省略。
例如:
DATASEGMENT
DW20DUP(?
)
DATAENDS
四、设定段寄存器伪指令ASSUME
一般格式:
ASSUME段寄存器:
段名[,段寄存器:
段名,……]
功能:
通知汇编程序,哪一个段寄存器是该段的段寄存器,以便对使用变量或标号的指令汇编出正确的目的代码。
由于ASSUME伪指令只指明某一个段地址应存于哪一个段寄存器中,并没有包含将段地址送入该寄存器的操作。
因此要将真实段地址装入段寄存器还需用汇编指令来实现。
这一步是不可缺少的。
例如,CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,SS:
STACK
MOVAX,DATA;DATA段值送AX
MOVDS,AX;AX内容送DS,DS才有实际段值
CODEENDS
注意:
当程序运行时,由于DOS的装入程序负责把CS初始化成正确的代码段地址,SS初始化为正确的堆栈段地址,因此用户在程序中就不必设置。
但是,在装入程序中DS寄存器由于被用作其它用途,因此,在用户程序中必须用两条指令对DS进行初始化,以装入用户的数据段地址。
当使用附加段时,也要用MOV指令给ES赋段地址。
五、定义过程的伪指令PROC和ENDP
在程序设计中,可将具有一定功能的程序段看成为一个过程(相当于一个子程序),它可以被别的程序调用。
要求先定义后使用。
一个过程由伪指令PROC和ENDP来定义,其格式为:
过程名PROC[类型]
过程体
RET
过程名ENDP
其中过程名是为过程所起的名称,不能省略,过程的类型由FAR(远过程,为段间调用)和NEAR(近过程,在本段内调用)来确定,如果缺省类型,则该过程就默认为近过程。
ENDP表示过程结束。
过程体内至少应有一条RET指令,以便返回被调用处。
过程可以嵌套,也可以递归使用。
例如一个延时100ms的子程序,其过程可定义如下,
DELAYPROC
PUSHBX
PUSHCX
MOVBL,10
;延时10ms,改变BL和CX中的值,即可改变延时时间。
AGAIN:
MOVCX,2801;
WAIT;LOOPWAIT
DECBL
JNZAGAIN
POPCX
POPBX
RET
DELAYENDP
CALLDELAY;调用该过程
远过程调用时被调用过程必定不在本段内。
例如,有两个程序段,其结构如下:
CODE1SEGMENT
ASSUMECS:
CODE1
FARPROCPROCFAR
RET
FARPROCENDP
CODE1ENDS
CODE2SEGMENT
ASSUMECS:
CODE2
CALLFARPROC
…..
CODE2ENDS
CODE1段中的FARPROC过程被另一段CODE2调用,故为远过程。
六、宏指令
在汇编语言书写的源程序中,若有的程序段要多次使用,为了简化程序书写,该程序段可以用一条宏指令来代替,而汇编程序汇编到该宏指令时,仍会产生源程序所需的代码。
宏指令的一般格式为:
宏指令名MACRO[形式参量表]
宏体
ENDM
例如:
SHIFTMACRO
MOVCL,4
SALAL,Cl
ENDM
这样定义以后,凡是要使AL中内容左移4位的操作都可用一条宏指令SHIFT来代替。
宏指令与子程序有许多类似之处。
它们都是一段相对独立的、完成某种功能的、可供调用的程序模块,定义后可多次调用。
但在形成目的代码时,子程序只形成一段目的代码,调用时转来执行。
而宏指令是将形成的目的代码插到主程序调用的地方(称为宏扩展)。
因此,前者占内存少,但执行速度稍慢;后者刚好相反。
七、ORG伪指令
ORG伪指令规定了在某一段内,程序或数据代码存放的起始偏移地址。
一般格式:
ORG<表达式>
例如:
DATASEGMENT
BUFF1DB23,56H,‘EOF’
ORG2000H
BUFF2DB‘STRING’
DATAENDS
上述变量定义中,BUFF1从DATA段偏移地址为0的单元开始存放,而BUFF2则从DATA段偏移为2000H的单元开始存放,两者不是连续存放。
八、汇编结束伪指令END
该伪指令表示源程序的结束.令汇编程序停止汇编。
因此,任何一个完整的源程序均应有END指令。
一般格式:
END[表达式]
其中表达式表示该汇编程序的启动地址。
例如:
ENDSTART;表明该程序的启动地址为START。
习题与思考:
4.数据定义语句如下所示:
FIRSTDB90H,5FH,6EH,69H
SECONDDB5DUP(?
)
THIRDDB5DUP(?
)
自FIRST单元开始存放的是一个四字节的十六进制数(低位字节在前),要求:
编一段程序将这个数逻辑左移两位后存放到自SECOND开始的单元,逻辑右移两位后存放到自THIRD开始的单元。
(注意保留移出部分)
5.在当前数据区从400H开始的256个单元中存放着一组数据,试编程序将它们顺序搬移到从A000H开始的顺序256个单元中。
6.试编程序将当前数据区从BUFF开始的4K个单元中均写入55H,并逐个单元读出比较,看写入的与读出的是否一致。
若全对,则将ERR单元置0H;如果有错,则将ERR单元置FFH。
第三讲:
3.3汇编程序设计
回顾:
8086/8088的指令系统,汇编程序的基本格式,伪指令的功能,汇编程序的正确格式。
本讲重点:
掌握汇编程序的分析与设计方法(包括分支程序和循环程序)
讲述内容:
一、简单程序设计
简单程序设计是没有分支,没有循环的直线运行程序,程序执行按照IP内容自动增加的顺序进行。
例1利用查表法计算平方值。
已知0~9的平方值连续存在以SQTAB开始的存储区域中,求SUR单元内容X的平方值,并放在DIS单元中。
假定0≤X≤9且为整数。
分析:
建立平方表,通过查表完成。
STACKSEGMENT
DB100DUP(?
)
STACKENDS
DATASEGMENT
SURDB?
DISDB?
SQTABDB0,1,4,9,16,25,36,49,64,81;0~9的平方表
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,SS:
STACK
BEGIN:
PUSHDS
MOVAX,0
PUSHAX;保证返回DOS,
MOVAX,DATA
MOVDS,AX;为DS送初值
LEABX,SQTAB;以下程序部分完成查表求平方值
MOVAH,0;亦可用查表指令完成(如下程序段)
MOVAL,SUR;AL=XLEABX,SQTAB
ADDBX,AX;MOVAL,SUR
MOVAL,[BX];XLAT
MOVDIS,AL;MOVDIS,AL
CODEENDS
ENDBEGIN
例2已知Z=(X+Y)-(W+Z),其中X,Y,Z,W均为用压缩BCD码表示的数,写出程序。
分析:
这也是一种典型的直线程序,在这里要注意是BCD数相加,要进行十进制调整。
具体程序如下:
MOVAL,Z
MOVBL,W
ADDAL,BL
DAA;十进制调整
MOVBL,AL;BL=(W+Z)
MOVAL,X
MOVDL,Y
ADDAL,DL;AL=(X+Y)
DAA;十进制调整
SUBAL,BL;AL=(X+Y)-(Z+W)
DAS;十进制调整
MOVZ,AL;结果送Z
二、分支程序设计
分支程序的基本思想是根据逻辑判断的结果来形成程序的分支,如图,若A成立,则执行P1;否则执行P2。
例1试编写程序段,实现符号函数。
分析:
变量X的符号函数可表示为:
1X>0
Y=0X=0
-1X<0
程序可通过对符号标志的判别来确定执行哪一分支。
START:
MOVAX,BUFFER;(BUFFER)=X
ORAX,AX
JEZERO;X=0,则转ZERO
JNSPLUS;X为正数,则转PLUS
MOVBX,0FFFFH;X为负数,则-1送BX
JMPCONT1
表3-2子程序R1—R8的入口地址表
P1
子程序R1的入口偏移地址
P2
子程序R2的入口偏移地址
P3
子程序R3的入口偏移地址
……
……
…….
……
P7
子程序R7的入口偏移地址
P8
子程序R8的入口偏移地址
ZERO:
MOVBX,0
JMPCONT1
PLUS:
MOVBX,1
CONT1:
……
例2利用表实现分支
根据AL中各位被置位情况,控制转移到8个子程序P1~P8之一中去。
转移表的结构如表3-2所示。
分析:
对于这种程序关键要找出每种情况的转移地址,从图中可见:
表地址=表基地址+偏移量,而偏移量可由AL各位所在位置*2求得。
流程图见图3-3。
DATASEGMENT
BASEDWSR0,SR1,SR2,SR3,
SR4,SR5,SR6,SR7
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,ES:
DATA
BEGIN:
PUSHDS
XORAX,AX
PUSHAX
MOVAX,DATA
MOVDS,AX
LEABX,BASE;表头送BX
INAL,PORT
GETBIT:
SHRAL,1;右移一位
JCGETAD;移出位是1?
INCBX
INCBX;修改指针
JMPGETBI
GETAD:
JMPWORDPTR[BX];实现散转
CODEENDS
ENDBEGIN
根据跳转表构成方法不同,实现分支的方法也有所改变,下面有三个问题希望大家思考:
(1)若跳转表地址由段值和偏移量四个字节构成,程序应如何实现?
(2)若跳转表中的内容由JMPOPRD指令构成,表的结构应如何组织、程序如何实现?
(3)上述程序若不用间接跳转指令,而改为直接跳转,程序如何变动?
将内存中某一区域的原数据块传送到另一区域中。
分析:
这种程序若源数据块与目的数据块之间地址没有重叠,则可直接用传送或串操作实现;若地址重叠,则要先判断源地址+数据块长度是否小于目的地址,若是,则可按增量方式进行,否则要修改指针指向数据块底部,采用减量方式传送。
程序如下:
DATASEGMENT
STRDB1000DUP(?
)
STR1EQUSTR+7
STR2EQUSTR+25
STRCOUNTEQU50
DATAENDS
STACKSEGMENTPARASTACK‘STACK’
STAPNDB100DUP(?
)
STACKENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,ES:
DATA,SS:
STACK
GOOPROC
P
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三 汇编程序 设计 讲稿