1、第5章 汇编语言程序设计,5.1 宏汇编语言的基本语法 5.2 伪指令 5.3 宏指令 5.4 汇编语言程序的结构 5.5 DOS系统功能调用 5.6 汇编语言程序设计方法 5.7 软件调试技术,汇编语言,汇编语言是一种采用助记符表示的程序设计语言,即用助记符来表示指令的操作码和操作数,用符号或标号代表地址。,使用汇编语言编写的程序称作汇编语言源程序。汇编语言源程序不能由机器直接执行而必须翻译成由机器代码组成的目标程序,这个过程称为汇编。,把汇编语言源程序翻译成目标程序的软件称为汇编程序。,汇编过程的含义如图:,宏汇编语言的基本语法,5.1.1 常数、变量和标号,5.1,常 数,常数是没有任何
2、属性的纯数值。在汇编期间,它的值已经完全确定,而且在程序的运行中也不会发生变化,它可以有以下几种类型:,5.1.1 常数、变量和标号,常 数,5.1.1 常数、变量和标号,变 量,变量通常是存放在某些存储单元的数据,这些数据在程序运行期间可以修改。变量使用数据定义伪指令DB、DW、DD等定义的。,经过定义的变量,每个变量均有三个属性:,5.1.1 常数、变量和标号,标 号,标号表示一条指令所在的地址,所以标号也是指令语句的地址符号,常用作转移指令(包含子程序调用指令)的操作数,即目标地址。标号通常由字母数字串组成,但第一个字母必须为字母。,标号有三种属性:,5.1.1 常数、变量和标号,距离属
3、性分为两种:,5.1.1 常数、变量和标号,标 号,表达式与运算符,8086宏汇编语言允许使用的表达式有两种类型:,5.1.2,运算符主要包括以下6种类型:,表达式与运算符,5.1.2,算术运算符,包括加(+)、减(-)、乘(*)、除(/)、求余数(MOD)、左移(SHL)和右移(SHR),表达式与运算符,5.1.2,注意,逻辑运算符,包括按位操作的与(AND)、或(OR)、异或(XOR)、和非(NOT)四种运算符。它们只适用于对常数进行逻辑运算。,表达式与运算符,5.1.2,注意,关系运算符,包括EQ(相等)、NE(不相等)、LT(小于)、GT(大于)、LE(小于或大于)、GE(大于或等于)
4、共六种。,表达式与运算符,5.1.2,分析操作符(数值返回运算符),表达式与运算符,5.1.2,表5-1 存储器操作数的类型值,表达式与运算符,5.1.2,分析操作符(数值返回运算符),分析操作符(数值返回运算符),表达式与运算符,5.1.2,分析操作符(数值返回运算符),表达式与运算符,5.1.2,综合运算符,表达式与运算符,5.1.2,综合运算符,表达式与运算符,5.1.2,注意,其他运算符,表达式与运算符,5.1.2,其他运算符,表达式与运算符,5.1.2,表5-2 运算符的优先级别,表达式与运算符,5.1.2,伪指令,5.2.1 伪指令语句的格式, 定义符字段在伪指令语句中,定义符表示
5、该语句的伪操作功能。定义符有汇编程序规定,宏汇编程序中使用了数十种定义符。,5.2, 符号名字段符号名用在伪指令语句的前面,用空格和定义符隔开。, 操作数字段操作数可以是常数(二进制、十进制、十六进制等)、字符串、常量名、变量名、标号和一些专用符号等。, 注释字段这是一个任选字段,它必须以分号开始,和指令语句的注释功能一样。,常用伪指令,1. 符号定义伪指令(赋值语句),5.2.2,注意,1. 符号定义伪指令(赋值语句),常用伪指令,5.2.2,常用伪指令,5.2.2,1. 符号定义伪指令(赋值语句),数据定义伪指令,2.,常用伪指令,5.2.2,表达式是赋给变量的初始值,可以有一个,也可以有
6、多个,常见的有以下几种:,这实际上是为数据分配存储单元,并把变量名作为该存储单元的名称。,(1)数值表达式,常用伪指令,5.2.2,数据定义伪指令,2., DW伪指令可以为两个字符组成的字符串分配一个字单元。,(2) ASCII字符串,可以用DB伪指令为ASCII字符串中的每一个字符分配一个字单元。,常用伪指令,5.2.2,数据定义伪指令,2.,(3) ?表达式,这是为数据项分配存储单元的一种方法,只是存储单元中不预置确定的值,常用来预留存储单元,存放程序的中间结果或最终结果。,(4)重复定义子句DUP,利用重复定义子句DUP可以为若干个重复数据分配存储单元。,其中圆括号内的表达式是重复的内容
7、,n 是重复次数。,常用伪指令,5.2.2,数据定义伪指令,2.,段定义伪指令,段定义伪指令用于将源程序划分成若干段,这些逻辑段按用途可分为代码段(用于存放程序)、数据段(用于存放数据)、堆栈段(用于堆栈操作)和附加段(附加的数据段)。,需要说明的是,并不是所有的程序都必须包含这四个逻辑段,有时只需要一个段或两个段。,功能:把模块划分为若干个逻辑段。每个SEGMENT/ENDS可定义一个逻辑段。,3.,常用伪指令,5.2.2, SEGMENT后的3个参数一般来说可以任选,它们的含义、类型及功能如下:,定位类型表示将某段装入内存时,对段的起始边界的要求。合理选择定位类型能够在进行段和模块的定位时
8、充分利用存储空间。它有以下4种选择:,(1)定位类型,常用伪指令,5.2.2,段定义伪指令,3.,(2)组合类型,用来在多模块连接时告诉连接程序本段和其他段的组合关系。,组合类型有以下几种:,常用伪指令,5.2.2,段定义伪指令,3.,(3)类别,可以是任何合法的自定义符,必须用单引号括起来。连接程序只使其与同类别段发生关联,这些同类别段被依序放在连续存储区域内,但各段仍独立。,常用伪指令,5.2.2,段定义伪指令,3.,注意,段寄存器说明伪指令,4.,常用伪指令,5.2.2,过程定义伪指令,过程是程序的一部分,它可以被程序调用。每次可调用一个过程,当过程中的指令执行完后,控制返回调用它的地方
9、。过程的定义是用过程定义伪指令完成的。,5.,常用伪指令,5.2.2, 过程名是自定义符,定义开始和结束时的过程名必须相同。 过程名有三个属性:段地址、偏移量和距离属性(NEAR或FAR),汇编程序在汇编时根据过程类型生成段内或段间的调用或返回指令代码。 在一个过程中,可以有多个RET指令。一个过程总是通过RET指令返回,RET常作为过程的最后一条指令。,常用伪指令,5.2.2,模块定义及通信伪指令,汇编语言可以把程序划分成许多模块,并对每个模块独立地进行汇编和调试。,(1) 模块开始伪指令,模块名是自定义符,不能是系统保留字。若该项使用默认值,则取TITLE语句中的页标题6个字符;若没有TI
10、TLE语句,则取源程序文件名为模块名。,6.,常用伪指令,5.2.2,(2)模块结束伪指令(源程序结束伪指令),常用伪指令,5.2.2,注意,模块定义及通信伪指令,6.,(3)定义公共符号名伪指令,常用伪指令,5.2.2,模块定义及通信伪指令,6.,注意,定义外部符号名伪指令,(4),常用伪指令,5.2.2,注意,模块定义及通信伪指令,6.,列表伪指令,(1) 格式控制伪指令,格式控制伪指令用于对源程序排版、加标题和子标题。,1) 自动排版(行数、列数),7.,常用伪指令,5.2.2,2)建立标题,常用伪指令,5.2.2,列表伪指令,(1) 格式控制伪指令,7.,(2)列表控制伪指令,这些伪指
11、令用于打开或关闭列表文件的输出。,常用伪指令,5.2.2,列表伪指令,7.,8.记录伪指令,(1) 记录定义,记录名、字段名必须 存在,不可使用默认值。 各字段总和不能超过 16位。 表达式的初值应取正 整数。,常用伪指令,5.2.2,(2)记录存储单元分配及赋值,字段值表中缺省项的默认值为0。,此例在存储器中分配两个记录,每个记录为两个字节。,常用伪指令,5.2.2,8.记录伪指令,记录操作符,1) 取字段宽度操作符,(3),常用伪指令,5.2.2,8.记录伪指令,2)取字段位置操作符,常用伪指令,5.2.2,记录操作符,(3),8.记录伪指令,结构伪指令,结构伪指令是把多个数据定义语句组成
12、一个结构,而把每一个数据定义语句称为一个结构字段,内存变量名称为字段名。,(1) 结构定义伪指令,9.,常用伪指令,5.2.2,(3)结构及字段的引用,常用伪指令,5.2.2,结构伪指令,9.,条件汇编伪指令,条件汇编的主要作用是根据条件有选择地对程序汇编。,10.,常用伪指令,5.2.2,条件汇编有多种伪指令操作,下面介绍常用的几个:,常用伪指令,5.2.2,条件汇编伪指令,10.,常用伪指令,(1) 定位伪指令,(2) 注释说明伪指令,11. 其他伪指令,5.2.2,注意,宏指令,为了简化汇编语言源程序,可以把一些频繁出现的程序段 定义为“宏指令”,1. 宏定义及其调用,5.3,宏指令,5
13、.3,1. 宏定义及其调用,2.带参数的宏, X是一个形式参数,这里代表移位次数。在调用时,可把实际要求的移位次数作为实际参数代入,如SHIFT 4,就可用实在参数4代替在宏定义体中出现的形式参数X,从而实现移位4次。若再引用一个形式参数:,SHIFT MACRO X,YMOV CL,XSAL Y,CLENDM,用形式参数Y来代替需要移位的寄存器,只要在调用时,把要移位的寄存器作为实际参数代入,就可以对任一个寄存器实现指定的左移操作。,宏指令,5.3,3.主要的宏操作伪指令,(1) 宏定义伪指令,(2) 取消宏指令名伪指令,(3) 重复伪指令,宏指令,5.3,汇编语言程序的结构,汇编语言源程序
14、由语句序列组成,该语句序列应包括可执行指令组成的指令语句和对符号定义、分配存储单元、分段等一些伪指令语句。,此外,80X86微处理器系统的存储结构是分段式访问结构,这种结构是程序运行的基础。因此80X86汇编语言源程序通常具备数据段、代码段和堆栈段等。,5.4.1 汇编语言源程序的结构,5.4,5.4.1 汇编语言源程序的结构,汇编语言和DOS操作系统之间的接口,为保证用户程序执行完后能回到DOS,应采取两项措施:,5.4.2,汇编语言和DOS操作系统之间的接口,5.4.2,正常返回DOS的方法如下:CODE SEGMENTSTART PROC FARPUSH DS ;保护PSP段地址MOV
15、AX,0 ;保护偏移0地址PUSH AXRETSTART ENDPCODE ENDSEND START,还有一种非标准返回DOS的方法,即在CODE ENDS之前插入:MOV AH, 4CHINT 21H,DOS系统功能调用,5.5,INT 21H中断本身包含很多子程序,每个子程序对应一个功能,其编号从062H。调用它们时采用统一的格式如下:,1. 键盘输入单字符1号系统功能调用, 功能:执行时系统首先等待键盘输入,待程序员按下任何一键,系统先检查是否是Ctrl-Break键。如果是则退出,否则将键入字符的ASCII码置入AL寄存器,并在屏幕上显示该字符。,DOS系统功能调用,5.5,2. 无
16、回显键盘输入单字符8号系统功能调用, 功能与1号功能调用基本相同,惟一的差别是键入的字符不送屏幕显示。,3无回显直接控制台输入单字符7号系统功能调用, 功能:从标准输入设备键盘输入单字符送AL,和1号调用相比,一是不回显字符,二是不做针对Ctrl-Break键的检查。,DOS系统功能调用,5.5,4. 键盘输入字符串0AH号系统功能调用,功能是将键盘输入的字符串写入到内存缓冲区中,因此必须事先定义一个缓冲区。,DOS系统功能调用,5.5,5. 输出单字符2号系统功能调用,DOS系统功能调用,5.5,功能是将指定的内存缓冲区中的字符串在屏幕上显示出来,缓冲区的字符串以“$ ”为结束标志。使用格式
17、如下:,6. 输出字符串9号系统功能调用,DOS系统功能调用,5.5,7.直接控制台输入/输出单字符6号系统功能调用,DOS系统功能调用,5.5,8.返回操作系统4CH号系统功能调用,DOS系统功能调用,5.5,9.从串口输入单字符3号系统功能调用,10. 向串口输出单字符4号系统功能调用,DOS系统功能调用,5.5,汇编语言程序设计,5.6.1 程序设计步骤,程序是计算机命令的有序集合,用计算机求解某些问题时往往需要编制程序,其设计步骤归纳如下:,5.6,汇编语言程序设计方法,1. 简单程序设计,简单程序,又称为顺序程序。这种程序的形式最简单,计算机执行程序的方式是“从头到尾”,逐条执行指令
18、语句,直到程序结束,这是最基本的形式,任何程序都离不开这种形式。在汇编语言程序中简单程序主要由数据传送指令、算术运算指令和逻辑运算指令组合而成。,5.6.2,汇编语言程序设计方法,1. 简单程序设计,5.6.2,【例5-36】假设有多项式形如:f(X)= 5X3 + 4X2 - 3X + 2 ,要求编制程序计算自变量X=5时函数f(X)的值。,汇编语言程序设计方法,5.6.2,2. 分支程序设计,分支程序可以有两种形式:简单分支结构和多分支结构。其中简单分支结构有两种,相当于高级语言中的IFTHEN和IFTHENELSE结构;多分支结构则相当于高级语言中的DO-CASE结构。它们的流程图如图4
19、-3所示。,【例5-37】 比较两个无符号数的大小。在A和B单元各有一个8位无符号数,要求比较这两个无符号数, 并根据比较结果在屏幕上显示AB或BA(假设这两个数不相等)。,汇编语言程序设计方法,5.6.2,2. 分支程序设计,【例5-37】 比较两个无符号数的大小。,汇编语言程序设计方法,5.6.2,2. 分支程序设计,【例5-38】 某应用程序主菜单有8个可选项,其入口地址分别记为R0、R1 R7。要求编制程序根据变量N的值转向相应的处理程序(N为入口编号)。,3.,(1) 循环程序的结构与组成,循环程序设计,2) 循环工作部分又称为循环体,是循环结构的基本部分,完成实际的处理操作。,3)
20、 循环控制部分循环控制部分用于控制重复执行的次数。包括修改变量、修改指针,为下一次循环做准备,以及修改循环计数器,判断循环结束条件是否满足,若条件满足则退出循环,否则继续循环。,4) 循环结束部分主要用来分析和存放程序的结果。,汇编语言程序设计方法,5.6.2,3.,循环程序设计,(2) 循环控制方法,汇编语言程序设计方法,5.6.2,【例5-39】统计负数个数并显示。,3.,循环程序设计,汇编语言程序设计方法,5.6.2,【例5-39】统计负数个数并显示。,3.,循环程序设计,(3) 多重循环,设计多重循环程序时,可以从外层循环到内层循环一层一层的进行。通常在设计外层循环时,仅把内层循环看成
21、一个处理粗框,然后再将粗框细化,分成初始化、工作、控制、结束四个组成部分。当内层循环设计完毕以后,用其替换外层循环体中被视为处理粗框的对应部分,就构成了一个多重循环程序。,汇编语言程序设计方法,5.6.2,注意,子程序设计,子程序相对主程序而言,是一个子的程序段,确切地说,它是被主程序调用的程序。子程序调用示意图如图5-8所示。,4.,汇编语言程序设计方法,5.6.2,一般来说有公用性、重复性或有相对独立性的程序段应设计成子程序。这种结构给程序设计带来了许多方便。,(2) 子程序设计应注意的问题,(1)子程序调用和返回,汇编语言程序设计方法,5.6.2,(3)子程序调用技巧,汇编语言程序设计方
22、法,5.6.2,图4-9 子程序递归和重入示意图,汇编语言程序设计方法,5.6.2,(3)子程序调用技巧,程序设计举例,前面已经介绍了程序设计的基本方法。本节将给出一些程序设计的例子,这些例子涉及一些常用程序,通过这些例子可以掌握一些程序设计的技巧和方法。,1. 算术运算程序,【例5-44】 多字节压缩型十进制数加法。,5.6.3,程序设计举例,1. 算术运算程序,【例5-44】 多字节压缩型十进制数加法。,5.6.3,C DB 11 DUP(?),MOV AL,0 ADC AL,0 MOV BX, AL,非数值处理程序,非数值处理即处理数值以外的数据,如字符、字符串、代码、记录和表格等。非数
23、值处理程序有很多,主要有:代码转换、字符处理、表处理等。,(1) 代码转换,1) BCD码与ASCII码间的相互转换。,2.,程序设计举例,5.6.3,【例5-45】已知从A单元开始存有10个字节的压缩BCD码,要求编程将其转换为ASCII码并显示在CRT上。,非数值处理程序,2.,程序设计举例,5.6.3,【例5-45】压缩BCD码转换为ASCII码。,非数值处理程序,非数值处理即处理数值以外的数据,如字符、字符串、代码、记录和表格等。非数值处理程序有很多,主要有:代码转换、字符处理、表处理等。,(1) 代码转换,2) 二进制数到七段显示码的转换。,2.,程序设计举例,5.6.3,图5-11
24、 七段显示器及其显示码表,程序设计举例,5.6.3,非数值处理程序,2.,(1) 代码转换,非数值处理程序,【例5-46】二进制数到七段显示码的转换。,2.,程序设计举例,5.6.3,(2)字符数据处理,(3) 表处理,字符和字符串的处理是计算机应用的一个重要方面。字符数据处理一般包括统计、比较、删除、插入等。,表格是软件最基本的数据结构。表格中可以存放一系列相关联的数据及执行结果,可供运算和查询。,程序设计举例,5.6.3,【例5-48】数据或程序的加密。从键盘上输入一个09之间的数字,将其加密后存入MIMA单元。,(3) 表处理,程序设计举例,5.6.3,【例5-48】数据或程序的加密。,
25、软件调试技术,5.7.1 调试软件DEBUG简介,DEBUG调试软件是专为汇编语言设计的一种调试工具,具有跟踪程序执行、观察运行中间结果、显示和修改寄存器或存储单元内容等多项功能,是开发汇编语言程序所必须掌握的调试手段。,5.7,在操作系统环境下,启动DEBUG后将进入DEBUG的命令状态,在此状态下,可以使用DEBUG的任何命令,每个命令均以回车结尾。,注意,用DEBUG.EXE装入调试程序的两种方法如下:,5.7.1 调试软件DEBUG简介, 在DOS提示符下,键入下列命令并回车:C DEBUG d:pathfilename.extparm1parm2其中 d:表示被调试程序所在盘的盘符,
26、path是filename的目录路径,filename是被分析或调试的二进制程序文件名,.ext是该程序文件的扩展名(一般是.exe或.com),parm1被调试程序约定的第一个参数文件名,parm2被调试程序约定的第二个参数文件名。此时屏幕上出现提示符“”,表示当前正在DEBUG的命令状态。, 在盘符后直接键入DEBUG并回车,在DEBUG命令状态下用N和 L命令装入被调试文件的方法如下:C DEBUG-N 文件名-L,DEBUG命令中的“地址”和“地址范围” :,5.7.1 调试软件DEBUG简介,地址表示形式段寄存器名:相对地址 例:DS:100 或 段地址:相对地址 例:24AB:10
27、00 或 相对地址 例:1000,地址范围表示: 起始地址 结束地址或 起始地址 L(表示字节数),常用DEBUG命令 1. 显示存储单元内容,5.7.1 调试软件DEBUG简介, 功能:格式1表示从起始地址开始按16进制显示80个单元的内容,每行16个单元。每行右侧还显示该16个单元的ASCII码字符,无字符对应的ASCII码显示“.”;格式2命令显示指定地址范围的存储单元中的内容,每行16个单元。每行右侧也显示该16个单元ASCII码字符,无字符对应的ASCII则显示“.”;如果不给出起始地址或地址范围则从当前地址开始按格式1操作。, 格式1:D 起始地址格式2:D 地址范围,常用DEBU
28、G命令 2修改存储单元内容,5.7.1 调试软件DEBUG简介, 功能:格式1按列表内容修改从起始地址开始的多个存储单元内容。例如E 12DF AB ABC 41命令可从12DF单元开始修改5个单元的内容,修改后这5个单元的内容分别是ABH、ABC字母的ASCII码以及41H。格式2完成的操作是修改指定地址单元内容。, 格式1:E 起始地址 列表格式2:E 地址,常用DEBUG命令 3显示、修改寄存器内容,5.7.1 调试软件DEBUG简介, 功能:功能:如果指定了寄存器名,则显示寄存器的内容,并允许修改。如果不指出寄存器名则按如下格式显示通用寄存器、段寄存器、标志寄存器的内容: AX=XXX
29、X BX=XXXX CX=XXXX DX=XXXX SP=XXXX BP=XXXX SI=XXXX DI=XXXX DS=XXXX ES=XXXX SS=XXXX CS=XXXX IP=XXXX NV UP DI PL NZ PO NC XXXX:XXXX C7060010FF01 MOV WORD PTR1000,01FF DS:1000=0000, 格式:R 寄存器名,常用DEBUG命令 4. 运行命令,5.7.1 调试软件DEBUG简介, 功能:CPU从指定起始地址开始执行,依次在第一、第二等断点中断。若不给起始地址,则从当前CS:IP指示地址开始执行。, 格式:G =起始地址 第一断点
30、地址 第二断点地址,5. 跟踪命令, 功能:从指定地址开始执行正整数条指令。如果不给出正整数;则按1处理;如果不给起始地址,则从当前CS:IP指示地址开始执行。, 格式:T =起始地址 正整数,常用DEBUG命令 6. 汇编命令,5.7.1 调试软件DEBUG简介, 功能:从指定地址开始接受汇编指令。如果不给出起始地址,则从当前地址(CS:IP)开始接受汇编指令。如果输入汇编指令过程中在某行不作任何输入而直接回车,则结束A命令,回到DEBUG命令状态处, 格式:A 起始地址,7. 反汇编命令, 功能:格式1从指定起始地址处开始对32个字节内容转换成汇编指令形式,如果不给出起始地址,则从当前地址
31、开始。格式2将指定范围内的存储内容转换成汇编指令。, 格式1:U 起始地址格式2:U 地址范围,常用DEBUG命令 8. 指定文件名命令,5.7.1 调试软件DEBUG简介, 功能:指出即将调入内存文件的文件名。这条命令要配合L或W命令一起使用。, 格式:N 文件名及扩展名,9. 装入命令, 功能:格式1根据指定驱动器号(0表示A驱,1表示B驱,2表示C驱),指定起始逻辑扇区号和扇区数将相应扇区内容装入到指定起始地址的存储区中。格式2将N命令指出的文件装入到指定起始地址的存储区中。若没有指定起始地址,则装入到CS:100处或按原来文件定位约定装入到相应位置。, 格式1:L 起始地址 驱动器号
32、起始扇区 扇区数格式2:L 起始地址,常用DEBUG命令 10.写磁盘命令,5.7.1 调试软件DEBUG简介, 功能:格式1的功能与L命令格式1的功能正好相反。格式2将起始地址开始的BX*10000H+CX个字节内容放到由N命令指定的文件中,使用格式2之前注意给BX、CX置上恰当的值。, 格式1:W 起始地址 驱动器号 起始扇区 扇区数格式2:W 起始地址,11. 退出命令, 功能:退出DEBUG,返回操作系统。, 格式:Q,5.7.2 软件调试的基本方法,利用调试软件DEBUG装入二进制执行程序,通过连续运行、分段运行、单步运行,可以实现软件剖析、查错或修改。,将.COM文件装入后,指令指
33、针IP置成100H,即程序入口的相对地址。首先从此处开始连续运行,考察程序的功能是否达到。如果出错,则可用分段运行方式,缩小错误所在程序段的范围,然后,再用单步方式找出错误确切所在处。,对 .EXE类型文件的调试与上相似,但不能直接用DEBUG存盘命令存盘。,用DEBUG调试程序需要注意以下几点:,5.7.2 软件调试的基本方法,设有程序EXAMP.COM,调试方法如下:,在此期间如果出现问题,就说明这些指令中有错误,这时,可用单步逐条执行,如:-T =100执行这一条指令后,会显示通用寄存器、段寄存器、标志寄存器的内容。由此可分析出本条指令的执行结果是否正确。若正确,则执行下一条指令;否则进
34、行必要的修改。, CDEBUG EXAMP.COM-G可以先用上述命令连续执行程序,如果结果不正确或死机,应该使用分段方式运行,查看问题出现在哪里,此时可用到T命令或G命令。-T =100,5 或 G 断点前者从相对地址为100H开始执行EXAMP.COM,连续执行5条指令;后者从当前地址开始连续执行到断点。可以恰当地选择执行的指令条数或断点,确定分段大小(一般应是完成相对完整的子功能的一段程序)。,5.7.2 软件调试的基本方法,软件调试举例,下面以【例5-41】中的冒泡排序程序为核心介绍如何用DEBUG调试程序。题目要求将内存区中自TABLE单元存放的一串8位有符号数按从小到大的顺序排列并
35、存回原处,数据长度存放在LEN单元。将该程序用编辑程序输入到计算机,保存时一定要将扩展名设定为.ASM,这样它才成为汇编语言源程序,假设此文件名为TEST.ASM。该文件经MASM宏汇编程序可汇编为TEST.OBJ,再经连接程序LINK可连接成TEST.EXE文件。实际上该程序已经可以直接执行,但是因为此程序的结果并不在显示器上显示,而是存在存储单元中,所以如果直接执行,则程序会直接返回DOS,而看不到任何结果。要想知道该程序能否将数据正常排序还需要用DEBUG调试。下面是TEST.EXE文件的调试过程:,5.7.2 软件调试的基本方法,软件调试举例,下面是TEST.EXE文件的调试过程:,C
36、: DEBUG TEST.EXE DEBUG程序以“”做提示符等待键入命令。要查看程序运行的情况,就必须首先用反汇编指令U来列出程序清单。 U 其中最左边给出了指令所在的段地址:偏移地址,然后是机器语言指令,右边是汇编语言指令,指令中所有的符号都被具体的数据代替。从列出的程序清单可以看出从13CAH:002CH开始存放的是返回DOS操作系统的指令,所以程序执行时执行到002CH就可以在存储单元中看到排序后的结果了。不过在看结果之前可以先查看一下排序前的数据,这样就可以先将断点设在装填数据段之后,即0005H处。,5.7.2 软件调试的基本方法,软件调试举例,反汇编后的程序:,5.7.2 软件调
37、试的基本方法,软件调试举例,下面用G命令将程序执行到0005H,命令和屏幕显示如下:,G 0005 AX=1379 BX=0000 CX=0080 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=13C9 ES=13B9 SS=13C9 CS=13CA IP=0005 NV UP EI PL NZ NA PO NC 13CA:0005 B506 MOV CH,06 此时程序停在断点处并显示出所有寄存器以及各标志位的当前值,第3行列出了下一条将要执行的指令的地址、其机器语言指令和汇编语言指令。从上面给出的寄存器内容可以知道,数据段的段地址为13C9H,再对照
38、源程序与反汇编出来的汇编语言程序可以知道数据的长度为06H,在第3条语句中传送给CH寄存器,TABLE的偏移地址为0000H,通过第5条指令送入SI寄存器中,也就是说要查看的数据已经锁定在从13C9H:0000H开始的6个存储单元中。,5.7.2 软件调试的基本方法,软件调试举例,下面用D命令来察看一下未排序之前这些存储单元的内容。,D 13C9:0000 000513C9:0000 0C 4E FE 00 4B 0F .NK. 其中第2行显示的就是从TABLE开始的6个字节的内容,刚好对应程序中的十进制数12、78、-2、0、75和15,最右边给出的是这些数据对应的ASCII字符。,5.7.
39、2 软件调试的基本方法,软件调试举例,下面要做的就是将程序执行到002CH(即返回DOS之前),然后再用D命令查看上述单元。,G 002C AX=130C BX=0000 CX=0300 DX=0000 SP=0000 BP=0000 SI=0003 DI=0000 DS=13C9 ES=13B9 SS=13C9 CS=13CA IP=002C NV UP EI PL ZR NA PE NC 13CA:002C B44C MOV AH,4C D 13C9:0000 0005 13C9:0000 FE 00 0C 0F 4B 4E KN 从上述结果可以看出排序之后数据的顺序对应十进制数刚好是-2,0,12,15,75,78,这说明这些带符号数据已经按从小到大的顺序排好,程序没有错误。如果调试过程中发现结果错误,还可以用T指令单步执行,执行时随时观察结果并判断程序中的错误,发现错误之后再重新进行编辑、汇编、连接和调试即可。,小结,难点 数据定义伪指令的内存分配、多重循环程序、子程序的递归。,