《第五章汇编语言程序设计.doc》由会员分享,可在线阅读,更多相关《第五章汇编语言程序设计.doc(10页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第五章汇编语言程序设计 难点和重点1 变量通过伪指令DB、DW、DD、DQ、DT来定义DB定义的是字节变量,DW定义的是字变量;DD定义的是双字变量,DQ定义的是长字变量;DT定义的是一个十字节变量。当变量为DW和DD类型时,才可以作为地址表达式,此时应遵循以下规则:(l)当用DW定义地址表达式时,地址表达式中的变量名称表示该变量的第一个存储单元的偏移地址。(2)当用DD定义地址表达式时,低位字用于预置偏移地址,高位字用于预置段地址。(3)地址表达式中的变量或标号可与常数值相加减。对于变量来说运算结果的类型不变;对标号来说,运算结果仍表示原标号所在段中的偏移地址。(4)变量或标号不能与变量或标
2、号相加,但可相减,结果是没有属性的纯数值。2源程序模块一个源程序模块能允许包括多个代码段和其它段,也允许多次使用ASSUME语句,重新约定段寄存器和段的关系。但 ASSUME语句并不意味着汇编后这些段地址已经装入相应的段寄存器中了,除了CS寄存器以外,其它各个段寄存器的实际值,还要用MOV指令来赋值,例如:MYCODE SEGMENTASSUME CS:MYCODE,DS:MYDATA,ES:MYEXTRA,SS:MYSTACKSTART:MOV AX , MYDATAMOV DS , AX MOV AX , MYEXTRA MOV ES , AX MOV AX , MYSTACK MOV S
3、S , AX MYCODE ENDS 然而,也不能只用赋值语句而将ASSUME语句省略,这样汇编程序就找不到所定义的各个段。3跳转表法当程序是CASE结构,即需引出多个分支时,最好利用跳转表法。其主要设计思想是:首先将n个选择项所对应的n个分支程序的标号存放在一个数据表(即跳转表)中,然后判别程序是否满足第一个条件,若满足就根据分支程序标号在跳转表中存放的地址将程序转入相应的分支;否则继续判别下个条件是否满足,。下面程序主要实现一组选择项(5个)存于AL寄存器中,要根据AL中为1的位将程序分别转移到相应的分支:BRANCH SEGMTBRANTAB DW ROUTINE1DW ROUTINE2
4、DW ROUTINE3 DW ROUTINE4 DW ROUTINE5BRANCH ENDS ROUTINE SEGMENTMAIN PROC FAR ASSUME CS:ROUTINE,DS:BRANCH START: PUSH DS SUB BX , BX PUSH BX MOV BX , BRANCH MOV DS , BX CMP AL , 0 JE DONE LEA BX , BRANCH CTINUE: SHR AL , l JNC NOTYET JMP WORD PTR BX NOTYET: ADD BX , TYPE BRANCHJMP CTINUE DONE: ROUTINE
5、I:ROUTINEZ:RET MAIN ENDP ROUTINE ENDS END START 4过程的嵌套、递归调用和可重入性过程也可以作为调用程序去调用其它过程,这里称为过程的嵌套。一般来说,嵌套的层次是没有限制的,只要堆栈空间允许即可,但当嵌套层次较多时应特别注意寄存器内容的保护和恢复,以免发生冲突。当子程序嵌套时,若某子程序要调用的子程序就是该子程序本身,则称这种调用为子程序的递归调用。递归过程被递归调用时必须保证不破坏前边调用所用到的参数及产生的结果,否则,就不能求出最后结果。此外,递归过程还必须具有递归结束的条件,以便在递归调用一定次数后退出,否则,递归调用将无限地嵌套下去。为了能
6、在每次递归调用后保留该次所用到的参数和运行结果,必须对每次递归调用所用到的参数和运行结果都专门分配一个存储区域。通常将一次递归调用所存储的信息称为帧,一帧信息包括递归调用时的入口参数、寄存器内容及返回地址等。存储每次递归调用每帧信息的最好方法是采用堆栈,每次递归调用时用PUSH指令将一帧信息压入堆栈;每次返回时,再从堆栈中弹出一帧信息。5过程的重入当一个公用子程序被某一个程序调用且还未执行完时,被另一个程序中断。同时,后一个程序执行时又一次调用该公用子程序,这样公用子程序便被再一次进入。若该公用子程序的设计能保证两次调用都得到正确结果,则称该公用子程序具有可重入性。保证子程序可重入性的方法,通
7、常也是将每次调用子程序时所用到的参数和中间结果逐层压入堆栈,以达到每次调用的结果都能正确保存的目的。5.1 伪操作命令(伪指令共有20条,常用的有以下几条:)5.1.1 数据定义语句(l)赋值伪指令EQU:当某个表达式被多次引用时,常采用给这个表达式赋一个名称,这样源程序中就可以以名称代替表达式;另外常使用标号来代表数据,数据地址或程序地址。伪指令EQU有两种格式,即名称EQU表达式,如:XYZ EQU 2000H ,定义后 XYZ 的值就为 2000H 名称EQU被定义过的名称或标号,如:ABC EQU xyz 定义后ABC的值就为xyz的值,即2000H(2)定义变量(分配存储单元)伪指令
8、:也即给变量分配内存的伪指令,这些伪指令是:DB、DW、DD、DQ、DT (3)定义存储单元类型伪指令:定义存储单元类型的伪指令并不是单独使用,而是和指令结合起来使用的。利用这些伪指令,对存储单元类型进行规定。例如:INC BYTE PTR DI ; DI所指存储单元为字节型 JMP DWORD PTR 2000H ;2000H开始的4个存;储单元为双字型5.1.2 表达式赋值语句ORG伪指令。伪指令ORG用来规定目标程序存放单元的偏移量。它的格式如下:ORG表达式汇编程序 ASM86 规定ORG伪指令不能带标识符,如: START : ORG 2000 是非法语句。如果在源程序中的第一条指令
9、用了如下伪指令:ORG 2000H 则汇编程序将把指令指针IP的值置成2000H,目标程序的第一个字节将放在2000H单元,后面的程序就会依次顺序存放。当遇到另一条。ORG语句时,目标程序的存放地址才会从新的ORG语句指定的地址单元存放。5.1.3 段定义语句定义段伪指令SEGMENT/ENDS主要是用来定义段的名称和范围,还可指明段的定位类型、组合类型和分类名。定义段伪指令的格式是:段名 1 SEGMENT 定位类型 组合类型 分类名 段名 1 ENDS段定义格式中,带有“ ”部分可根据需要选择其有无。当用于定义数据段、附加数据和堆栈段时,介于SEGMENT/ENDS伪指令中间的语句,只能包
10、括伪指令语句,不能包括指令语句。只有当SEGMENT/ENDS定义代码段时,中间的语句才能为指令语句以及与指令有关的伪指令语句。一个段一经定义,其中指令的标号、变量等在段内的偏移地址就已排定,它们都在同一个段地址控制之下,整个段占用的存储空间大小也就确定。由SEGMENT/ENDS所定义的段小于64K 单元。ASSUME伪指令。ASSUME伪指令语句用来告诉汇编程序在指令执行期间内存的哪一段是数据段,哪一段是堆栈段,哪一段是代码段。 ASSUME 伪指令的格式如下:ASSUME 段寄存器名:段名符,段寄存器名:段名符,ASSUME 语句只能安排在代码段内,一般应排在代码段作为首指令。ASSUM
11、E语句中的段寄存器名:段名符可以有一项,也可以有多项,可以将这些项写成多个ASSUME语句。一个源程序模式至少包括一个段,当代码、数据及堆栈都集中在一个段内时,ASSUME语句的格式应该是:ASSUME CS : MYCODE , SS : MYCODEASSUME DS : MYCODE , ES : MYCODE5.1.4过程定义语句定义过程的伪指令 PROC、ENDP、NEAR和FAR。在ASM一86语言中,过程的含义和子程序是一样的。一个过程可以被其它程序所调用,它的最后一条指令总是返回指令,用以控制过程在执行完毕后,返回到主程序。定义过程的伪指令总是成对出现的,在这两条伪指令间的内容
12、就作为一个过程,即一个子程序。5.1.5程序开始和结束语句源程序结束伪指令END。该指令是用来表明END语句处是源程序的终结。其格式如下:END表达式这里的表达式通常就是程序第一条指令的语句标号。这样程序在汇编、连接后,将目标代码装入内存之后准备要执行的起始地址由此标号所决定。这个表达式也可以省去。5.1.6外部伪指令及对准伪指定义访问外部标识符的伪指令 EXTRN,PUBLIC:当多个模块连接在一起时,可以利用定义访问外部标识符的伪指令 EXTRN,PUBLIC来引用其它模块中的某些变量或标号。定义结构的伪指令STRUC/ENDS。结构定义的格式如下:结构名称 STRUC ;由DB、DW、D
13、D伪指令所组成的语 ;句序列,每条语句定义一个字段标识符结构名称 ENDS 结构定义并不保留任何存储空间也不为任何存储单元赋值,它仅仅是一种模式,因而在引用结构和其字段之前,必须为结构分配空间或赋值。要给结构分配存储空间或赋值,必须有一个援用该结构的语句。其格式如下:变量结构 名称 赋值说明通过援用语句对结构进行存储空何分配和预置之后,结构及其字段就以变量的形式出现,可以像使用其它变量一样使用。但对结构的访问必须用变量路径名的方法进行,路径名的格式为:变量名,字段名 5.2 DOS系统功能调用和BIOS中断调用5.2.1常用的软件中断 INT 25H和INT 26H软件中断指令,分别用来实现对
14、磁盘指定扇区进行读/写,这两条指令执行时,会分别转去执行BIOS中的读写磁盘扇区子程序。使用这两条指令前,必须按表中入口参数的要求,对指定的寄存器分别设置读/写驱动器号,读/写扇区数,起始逻辑扇区号和读/写内存的缓冲区首址,然后才执行相应的中断命令。用INT 27H退出程序时,MS-DOS会把此用户程序看成是系统的一个组成部分而驻留内存,因此在其它程序装配运行时,这部分程序不会受到覆盖。通常,用户对自已编写的中断处理程序进行装配以后,常用这种方式返回控制台命令接收状态,其它用户程序可以用软中断方式调用这部分程序。必须注意DX中要设置驻留程序的长度,否则返回后程序不能驻留。5.2.2 DOS系统
15、功能调用DOS系统功能调用分别实现设备管理、文件读/写、文件管理和目录管理等功能。每个子程序对应一个功能号,所有的系统功能调用的格式是一致的,按下面4步进行: (1)系统功能号送到AH寄存器中, (2)入口参数送到指定寄存器中, (3)用INT 21H指令执行功能调用,(4)根据出口参数分析功能调用执行情况。 有些系统功能调用比较简单,不需要设置入口参数或者没有出口参数。DOS系统功能调用的功能及入口/出口参数表,详细见附录。 1设备管理包括:键盘输入、显示输出、设置磁盘缓冲器、选择当前盘等功能调用。 2目录管理包括:查找目录项、更改目录项、建立子目录、删除子目录等功能调用。 3文件管理包括:
16、建立文件、打开文件、读/写文件、删除文件等功能调用。 5.3 汇编语言程序设计5.3.1 汇编语言源程序的框架结构标准化汇编语言源程序采用分段结构。对于单模块程序的基本框架如下所NAME 模块名(可省略)EQU 符号定义区(可依据需要而定)EXTRN 外部符号名说明(依实际需要而定)PUBLIC 公共符号名说明(依实际需要而定)数据段名(如DATA) SEGMENT 参数(依据实际要求而定,可省略)变量定义预置存储空间数据段名(如DATA) ENDS堆栈段名(如STACK) SEGMENT 参数(依实际要求而定)预置堆栈空间堆栈段名(如STACK) ENDS代码段名(如CODE) SEGMEN
17、T 参数(依实际需要而定)ASSUME:段寄存器指派START: MOV AX,DATA ;段地址装填MOV DS,AXMOV AX,STACKMOV SS,AX 主程序体 MOV AH,4CH INT 21H过程名1 PROC 类型说明过程体1过程名1 ENDP过程名2 PROC 类型说明 过程体2过程名2 ENDP代码段名(如CODE) ENDSEND START汇编语言源程序采用分段结构,包括代码段、数据段和堆栈段。任何一个源程序至少有一个代码段,用来放置指令性语句构成的程序。堆栈段和数据段依据实际要求而决定。数据段用来定义变量,定义所需要的数据常数及预置存储空间,中间都是由伪指令语句构
18、成。堆栈段依需要而定,如果用户使用堆栈操作,最后使用用户自己定义的存储空间;若没有定义堆栈段,将自动使用系统定义的堆栈区。过程可放在代码段,也可单独建立一个过程段(另一个代码段)。EQU可放在数据段、代码段,宏指令一般放在程序的开始。PUBLIC可放在程序的任何一行。 因为各逻辑段通过段寄存器寻址,所以必须在代码程序的开头给相应的段寄存器赋值(装入地址)。ASSUME伪指令仅仅是指明了各逻辑段与段寄存器的对应关系,即该逻辑段是什么属性的逻辑段,并没有对段寄存器赋值。因此,必须在程序的开头先进行DS、SS、ES(若存在扩展段)的段基址装入。5.3.2 程序设计基本步骤对于给定的课题进行程序设计,
19、一般应按下述步骤进行。 1分析课题 对于实际的课题任务要有一个明确的认识,例如已知条件是什么,输入输出是什么,现场的工艺过程和工序,对运算的精度和速度有什么要求等要有一个全面的理解。 2确定算法 把实际问题转化成计算机求解的具体步骤和方法,而程序是来描述算法的。在计算机控制系统中,依据某种算法实现对现场设备的控制称为控制算法。尽可能选择多种算法,比较其优缺点,结合具体情况选择其中最适用的一种。 3画出流程图 依据算法,使用框状图形符号,加上简明的文字说明,用以描述解决问题的具体逻辑步骤和方法,这种框状图形符号称为流程图。流程图的国家标准为CBl52689,也有国际标准,二者基本一致。 4存储器
20、资源分配 编写程序前要进行资源分配,例如程序区和数据区如何安排,工作单元分配,变量的名称,最好画出一个详细的存储分配的明细表,以便编程时随时查阅。 5编写程序 应用汇编语言依据流程图进行程序编写,要求程序层次清楚,执行速度快,且尽可能少占内存,并且适当地加以诠释。编写程序后,利用PC机进行交叉汇编、调试和修改。 6上机调试5.3.3 汇编语言程序设计应注意的问题1程序模块化:对于复杂的,大型的程序将其划分为若干个相对独立的功能模块(一般编为过程),每个模块可以单独编写,单独汇编,单独调试。这种相对独立的模块程序易于分析和修改,维护方便,而且一个程序模块可以为多个程序所调用。 2程序正确完整,具
21、有容错功能。程序设计编写完毕后,要反复进行测试,把可能出现的故障的错误都要考虑在内,并且尽可能在调试价段予以排除。对于程序中不符合要求的运算错误和干扰错误,要给出相应“错误”的信息提示,对某些错误应能自动校正修复。 3算法的可靠性和合理性。选择算法时,要比较多种算法方案。虽然解决一个问题可以有多种算法,但效率和精度可能有很大差别,应依据实际需要而定。例如,尽量减小运算中的舍入误差,查表法代替复杂的函数运算等。 4实时性要求高的工程控制程序,要充分考虑软件执行速度。例如采样速率、控制量的计算时间等。 5.3.4 程序的基本结构与基本程序设计2 .程序设计初步 (l)程序是人们编写的、由计算机硬件
22、执行的一系列指令。编写程序的过程称为程序设计。由机器指令的二进制代码组成的程序称为机器语言程序。这是计算机直接能够识别的程序。(2)简单程序按照指令的书写顺序依次执行的程序。(3)分支程序采用条件转移指令进行判断、使程序的流程不再是一条顺序执行的直线,而变为由许多分支组成的树形结构,其中每个分支只有在满足给定条件时才被执行。(4)循环程序是程序设计的一个技巧,当程序处理的对象具有某种重复性的规律时,可用这种方法编写程序。(5)子程序一个完整的独立的程序段,它可以多次被其它程序调用,并在这个程序段执行完后返回到原调用的程序处。分支程序的设计程序的分支主要是靠条件转移指令来实现的。这里需要注意的是
23、条件转移语句都是近程跳转,若程序所要转移的地址超出其范围时,则需利用一条无条件转移语句作为中转。循环程序的设计循环程序的设计主要用于某些需要重复进行的操作,主要使用循环指令LOOP、LOOPZ或LOOPNZ或条件转移指令。循环程序的结构可分为设置循环初始状态、循环体和循环控制条件 3 部分:(l)设置循环初始状态主要是指设置循环次数的计数初值,以及其它为能使循环体正常工作的初始状态等。(2)循环体是指循环操作(重复执行)的部分,包括循环的工作部分及修改部分。循环的工作部分是实现程序功能的主要程序段;循环的修改部分是指当程序循环执行时,对一些参数如地址、变量的有规律的修正。 (3)循环控制部分是
24、循环程序设计的关键。每个循环程序必须选择一个控制循环程序运行和结束的条件,且如何选择一个合适的循环控制条件对一个循环程序的设计来说也是非常重要的。最常采用的循环控制条件是循环次数,即可先预置一个循环次数初值,每执行一次,循环体将该计数值减1,直至循环计数值减到0,便退出循环。子程序的设计子程序是一个独立的程序段,能完成某些确定的功能,并能被其它程序调用。当一个子程序被调用,且该子程序完成确定的功能后便返回调用程序处。1过程的定义和调用过程的定义是采用过程定义伪指令,其格式为:过程名 PROC 属性 RET 过程名 ENDP 调用过程时只要在CALL指令后写上该过程名即可,属性字段用来指明过程的
25、类型属性是NEAR还是FAR。RET指令总是放在过程体的末尾,用来返回主程序。当过程和主程序在同一代码时,过程可定义为NEAR属性,若过程和主程序不在一个代码段时,则过程定义为FAR属性。2寄存琴内容的保护和恢复通常主程序和过程的设计是分开进行的,因而它们所使用的寄存器往往会发生冲突,所以在进入过程时应将该过程所用寄存器的内容保存起来,这称为保护现场。过程返回主程序前,应将这些寄存器内容恢复,这称为恢复现场保护现场和恢复现场通常分别用堆栈压入指令和弹出指令来实现。须注意,并不是过程中用的所有寄存器内容都要保护,例如,若用寄存器在主程序和过程间传递参数就不需要保护。3主程序和过程间的参数传送在主
26、程序调用过程时,必须先把过程所需的初始数据设置(即入口参数)好,过程执行完毕返回主程序时也必须将过程运行所得结果(即出口参数)送给主程序。过程入口参数和出口参数的送入和送出称为主程序和过程间的参数传送。参数传送的方法主要有以下 4 种:(1)用CPU内部的寄存器传送参数。(2)当过程和主程序同在一个代码段时,过程可以直接访问该代码段中的变量(即参数)。(3)通过地址表传送变量地址。该方法是将所有变量的偏移地址顺序存放在一张地址表中,然后通过寄存器将地址表的地址传送给过程,进入过程后可用寄存器间接寻址方式从地址表中取出变量地址,以便访问所需变量。(4)通过堆栈传送参数或参数地址。该方法是:调用过
27、程前在主程序中用PUSH指令将参数地址压入堆栈;进入过程后再用基址寄存器BP从堆栈中取出这些参数地址,并送入寄存器,以便寄存器以间接寻址方式访问所需变量。 5.4 汇编语言上机调试过程汇编语言源程序的汇编、连接和装入运行汇编语言是一种面向机器的符号语言,要想在计算机上运行汇编语言程序,必须对源程序进行汇编和连接。下面是用汇编语言产生一个可执行文件的过程:(l)建立和修改源程序,可用各种字符编辑器,如:EDIT、WORDSTAR等建立一个扩展名为。ASM的源程序文件,并将产生的源文件存盘。(2)调用PC下的汇编程序(ASM或MASM),将源程序编译成。OBJ目标文件和LST可打印文件。OBJ文件
28、是用二进制代码表示的目标文件,可存盘,但不能直接上机运行,这是因为它的程序地址为可浮动的相对地址,而不是可执行的绝对地址。汇编时若发现源文件有错,可返回第一步改正。(3)将汇编程序生成的OBJ目标文件与库文件(若程序中调用公共子程序库中的子程序)或其它OBJ目标文件连接在一起,形成可装入执行的EXE程序文件。连接后可产生一个MAP文件,它提供文件中内存分配的一些信息以供用户检查。若用户根据EXE文件及MAP文件分析后发现有错误,仍需返回编辑器下修改源程序。(4)最后在PC一DOS的提示符下输入该程序名,DOS便会自动装入并运行该程序。 5.5 宏汇编和条件汇编5.5.1 宏汇编 宏指令、宏定义
29、、宏调用和宏嵌套 (l)宏指令可由用户自己在源程序中定义宏指令一经定义,便可在以后的程序中多次调用。 (2)宏定义的格式为:宏指令名 MACRO ENDM 形式参数 (3)宏调用的格式为: 宏指令名 实际参数(4)宏扩展。具有宏调用的源程序被汇编时,每个宏调用将被 MASM进行宏展开。宏展开实际上是用宏定义时设计的宏体去代替相应的宏指令名,并且用实际参数一一取代形式参数。( 5 )宏嵌套。宏定义中允许使用宏调用,但所调用的宏指令必须先定义过。而且宏定义中还可以包含宏定义。 5.5.2条件汇编 条件汇编是对给定的条件进行测试,汇编程序根据测试结果,将一段程序嵌入源程序汇编或不进行汇编,它的一般格式为:IF 条件 (表达式) (指令体1) ;条件为真汇编指令体1ELSE (指令体2) ;条件为假汇编指令体2 ENDIF IFENDIF;条件汇编伪指令助记符,必须成对出现,不可省略。条件:测试条件,条件为真汇编IFENDIF中指令体,否则不汇编。ELSE:选择命令,条件为真汇编指令体1,条件为假汇编指令体2,可以省略。