1、第一节 DEBUG的主要用途及DEBUG的调用 DEBUG是为汇编语言设计的一种调试工具,它通过单步执行、设置断点等方式为汇编语言程序员提供了非常有效的程序调试手段。DEBUG可以直接用来检查和修改内存单元、装入、存储及启动运行程序、检查及修改寄存器,也就是说DEBUG可深入到计算机的内部,可使用户更紧密地与计算机中真正进行的工作相联系。不仅如此,对汇编语言初学者来说,DEBUG也是练习使用汇编指令的一种有效工具。初学者可以直接在DEBUG环境下执行汇编指令。然而,在DEBUG下运行汇编语言源程序也受到了一些限制,它不宜汇编较长的程序,不便于分块程序设计,不便于形成以DOS外部命令形
2、式构成的 .EXE文件,不能使用浮动地址,也不能使用ASM和MASM提供的绝大多数伪指令。 在DOS系统中,DEBUG是以DOS外部命令文件形式提供给用户的,名为DEBUG.EXE。命令文件DEBUG.EXE一般存放在DOS子目录下,因此调用DEBUG时,只需在DOS提示符下键入: DEBUG [<驱动器名>:][<路径>][<文件名>[.<扩展名>]][<参数1>][<参数2>] < 回车> 例如: C:/DOS>DEBUG DISKCOPY.COM A: B: 进入DEBUG的提示符是符号“-”。即,出现提示符“-”就表示可以接受DEBUG命令了。 当进入
3、DEBUG时,寄存器和标志设成以下数值,这些值用于DEBUG调试中的程序。 段寄存器CS,DS,ES和SS均指向DEBUG末尾的第一个段。 IP寄存器置为0100H。栈指针SP指向尾部或装入程序的暂存部分的底部。 其余寄存器皆取零值,但若用户调用时含文件说明,则CX含文件长度(长度大于64K时BX含长度的高位);标志为各自的复位值;驱动器传送地址在代码段位移80H处。 注意,若DEBUG装入扩展名为.EXE的文件,则DEBUG需重定位且设置段寄存器指示器为文件中所定义的值。但DS,ES指向最低可用段处的程序区前缀。BX和CX为文件容量值。而 .EXE文件如果在连
4、接时选择了装入内存高处的参数,则该程序装入高处。 第二节 DEBUG的主要命令功能与格式 DEBUG命令是在DEBUG提示符“-”下,由键盘键入的。每条命令以单个字母的命令符开头,然后是命令的操作参数,操作参数与操作参数之间,用空格或逗号隔开,操作参数与命令符之间用空格隔开,命令的结束符是回车键 Enter。命令及参数的输入可以是大小写的结合。Ctrl+Break键可中止命令的执行。Ctrl+Num Lock键可暂停屏幕卷动,按任一键继续。所用数均为十六进制数,且不必写H。 * 1. 汇编命令A 格式:A [[<段寄存器名>/<段地址>:] <段内偏移>] 上式
5、等价于: (1) A <段寄存器名>:<段内偏移> (2) A <段地址>:<段内偏移> (3) A <段内偏移> (4) A 功能:键入该命令后显示段地址和段内偏移并等待用户从键盘逐条键入汇编命令,逐条汇编成代码指令,顺序存放到段地址和段内偏移所指定的内存区域,直到显示下一地址时用户直接键入回车键返回到提示符“-”。 注: 其中(1)用指定段寄存器的内容作段地址,(3)用CS的内容作段地址,(4)以CS:100作地址。以后命令中提及的各种‘地址’形式,均指(1)、(2)、(3)中A后的地址形式。 2. 比较命令C 格式: C <源地址范围>,<
6、目标地址> 其中<范围>是由<起始地址> <终止地址>或者是由<起始地址> L <长度>指出的一片连续单元。 功能:从<源地址范围>的起始地址单元起逐个与目标起始地址以后的单元顺序比较单元的内容,直至源终止地址为止。遇有不一致时,以<源地址> <源内容> <目标内容> <目标地址>的形式显示失配单元及内容。 * 3. 显示内存命令D 格式: D [<地址>/<范围>] 上式等价于: (1) D <地址> (2) D <范围> (3) D 功能:以两种形式显示指定范围的内存内容。一种形式为十六进制内容,一种形式为以相应字节的内容作为ASC
7、II码的字符,对不可见字符以‘.’代替。 注: 其中(1)以CS为段寄存器。(3)显示CS:100起始的一片内容。
8、 * 4. 修改内存命令E 格式: E <地址> [<单元内容表>] 上式等价于: (1) E <地址> (2) E <地址> <单元内容表> 其中<单元内容表>是以逗号分隔的十六进制数,或用’或”括起来的字符串,或者是二者的组合。 功能: (1)不断显示地址,可连续键入修改内容,直至新地址出现后键入回车Enter为止。(2)将<单元内容表>逐一写入由<地址>开始的一片单元
9、
5. 填充内存命令F
格式: F <范围> <单元内容表>
功能: 将单元内容表中的值逐个填入指定范围,单元内容表中内容用完后重复使用。
例如: -F 5BC:200 L 10 B2,‘XYZ’,3C
10、六进制算求运算指令H 格式: H <值1> <值2> 功能: 求十六进制数<值1>和<值2>的和与差并显示结果。 8. 端口输入命令I 格式: I <端口地址> 功能: 从指定端口接收信息并将输入的内容显示出来。 * 9. 读盘命令L 格式: L <地址> <驱动器号> <起始逻辑扇区> <所读扇区个数n> 其中<地址>的缺省值为CS: 100。逻辑扇区可由物理扇区号换算得到,以双面双密度盘为例:物理扇区是按0面0道1区,0面0道2区,……,0面0道9区,0面1道1区,……,0面 39道9区,1面0道1区,……,1面39道9区排列。而逻辑扇区与物理扇区号的对应关系为物理
11、扇区0面0道1扇区至9扇区,逻辑扇区号为0—8;物理扇区1面0道1扇区至9扇区,逻辑扇区号为9—11H;物理扇区0面1道1扇区至9扇区,逻辑扇区号为12—1AH;……。这样每道先0面后1面一直排下去。
其中<驱动器号>为0、1或2,0表示A驱,1表示B驱,2表示硬盘。
功能: 将<驱动器号>指定的盘上,从<起始逻辑扇区>起,共n个逻辑扇区上的所有字节顺序读入指定内存地址开始的一片连续单元。当L后的参数缺省时,必须在L之前由N命令指定(或进入DEBUG时一并指出)所读驱动器文件名。此时L执行后将该文件装入内存。
例如:-N EXAMPLE
12、 -L
13、OS手册
12. 端口输出命令O
格式: O <端口地址> <字节>
功能:将该<字节>从指定<端口地址>输出。
例如:-O 2F 4F
14、1 状态标志显示形式
标志位
溢出OF
方向DF
中断IF
符号SF
零 ZF
辅助AF
奇偶PF
进位CF
状 态
有/无
减/增
开/关
负/正
零/非
有/无
偶/奇
有/无
显 示
OV/NV
DN/UP
EI/DI
NG/PL
ZR/NZ
AC/NA
PE/PO
CY/NC
(2)显示指定寄存器内容
例如:-R AX
15、S CS:100 110 41
16、如:-T
17、 <地址> <盘号> <起始逻辑扇区> <所写逻辑扇区数n> 功能:与L命令不同的地方是将内存从<地址>起始的一片单元内容写入指定扇区。只有W而没有参数时,与N命令配合使用将文件写盘。 注:要求读者对其中打"*"的DEBUG命令必须能熟练使用。 第三节 在DEBUG环境下执行汇编指令 本节从几个典型例子出发,通过上机实习,引导读者学会使用DEBUG调试程序运行汇编语言程序,以便读者在以后的学习中能够有一个熟练的调试和运行手段。 在进入DEBUG的提示符‘-’之后,用户可以通过DEBUG的命令输入汇编源程序,并用相应命令将其汇编成机器语言程序;然后调试并运行该程序
18、
例1 在DEBUG下运行如下程序。
MOV DL,33H ;字符3的ASCII码送DL
MOV AH,2 ;使用DOS的2号功能调用
INT 21H ;进入功能调用,输出‘3’
INT 20H ;BIOS中断服务程序,正常结束。
该程序运行结果是在显示器上输出一个字符‘3’。如果要输出其它字符,请改变程序中‘33H’为相应字符的ASCII码。
运行步骤:
(1)进入DEBUG
设DEBUG.EXE位于C盘DOS子目录,进入DOS后键入DEBUG
19、DOS>DEBUG
20、CS段100H起始的8个存储单元。
如果在汇编后想看一下机器指令是什么样子的话,方法之一是可以用反汇编命令U作如下操作:
(3)反汇编
-U 100 108
21、汇编指令,中间是该汇编指令的机器码,左边是存放该条指令的内存单元地址。
(4)运行程序
-G
22、X)为该数的高16位,(CX)为该数的低16位。因此,上面的过程实际上是要将A个字节写入文件EXCOM.COM。
(6)送机器指令程序
-E 200 B2 33 B4 02 CD 21 CD 20
23、)退出DEBUG返回DOS,执行EXCOM.COM文件
-Q
C:/DOS>EXCOM
24、0108
25、用T命令单条执行,可以看到中间结果。 -T AX=0300 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1392 ES=1392 SS=1392 CS=1392 IP=0102 NV UP EI PL NZ NA PO NC 1392:0102 B002 MOV AL,02 -T AX=0302 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1392 ES=1392
26、 SS=1392 CS=1392 IP=0104 NV UP EI PL NZ NA PO NC 1392:0104 00E0 ADD AL,AH (5)再执行T命令,可以看到最终结果,(AL)=5 -T AX=0305 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1392 ES=1392 SS=1392 CS=1392 IP=0106 NV UP EI PL NZ NA PO NC 1392:0106 C
27、D02 INT 20
-T
AX=0305 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=1392 ES=1392 SS=1392 CS=011C IP=1094 NV UP DI PL NZ NA PO NC
011C:1094 90 NOP
-
(6)退出
-Q
28、 MOV CL,2 SHL AX,CL ;被乘数乘以4,结果送AX MOV BX,AX ;被乘数乘以4的结果送BX保留 MOV CL,2 SHL AX,CL ;被乘数乘以16,结果送AX ADD AX,BX ;被乘数乘以20,结果在AX中 MOV [300H],AX ;将积存入DS段第300H—301H号内存单元 MOV AH,4CH ;将功能号4CH送AH INT 21H ;执行DOS的4CH号功能
29、调用,结束程序返回DOS。
该程序运行结果是将0FEH乘以14H,结果放在DS段第300H—301H号内存单元中。
(1)进入DEBUG,显示300H至301H号内存单元内容
C:/DOS>DEBUG
30、0104 SHL AX,CL
31、T=100,8
32、命令指定写盘文件长度
-R BX
33、
-N A:YWZCHF.COM
34、
(11)用Q命令退出DEBUG环境,返回DOS
-Q
35、Enter>
169C:0109 MOV AH,4C
36、ormally
-T=100,3
37、第四节 使用DEBUG调试和运行可执行文件 事实上,在第三节例题中已经对使用DEBUG命令调试和运行可执行文件有所接触。本节只需对使用DEBUG调试和运行可执行文件的一般步骤做一介绍,并通过一个含有错误的程序来对程序调试进行实践。 用户程序经过编辑、汇编、连接后得到一个可执行文件(.EXE),这时借助于调试程序DEBUG对用户程序进行调试,查看程序是否能完成预定功能。对于初学者,如何选用DEBUG中各命令,有效地调试与运行程序,需要一个学习过程。在初次使用DEBUG时,可参照下列步骤进行。 1.调用DEBUG,装入用户程序 可以在调用DEBUG是直接装入用户程序可执行文
38、件,也可以在进入DEBUG环境后使用N命令和L命令装入用户程序可执行文件。无论用哪种方法,装入用户程序可执行文件时,一定要指定文件全名(即文件名和扩展名)。 2.观察寄存器初始状态 程序装入内存后,用R命令查看寄存器内容。从各段寄存器现在的内容,便能了解用户程序各逻辑段(代码段,堆栈段等)在内存的分布及其段基值。R命令亦显示了各通用寄存器和标志寄存器的初始值,显示的第三行就是即将执行的第一条指令。 3.以单步工作方式开始运行程序 首先用T命令顺序执行用户程序的前几条指令,直到段寄存器DS和/或ES已预置为用户的数据段。在用T命令执行程序时,每执行一条指令,显示指令执行后
39、寄存器的变化情况,以便用户查看指令执行结果。 4.观察用户程序数据段初始内容 在第3步执行后DS和/或ES已指向用户程序的数据段和附加段,这时用D命令可查看用户程序的原始数据。 5.继续以单步工作方式运行程序 对于初学者,一般编写的程序比较短,用T命令逐条执行指令,可清楚地了解程序的执行过程:现在执行的是什么指令,执行后的结果在哪里(寄存器,存储单元)?所得结果是否正确?…等等。在逐次使用T命令时,若有需要,可选用D命令了解某些内存单元的变化情况。 用T命令逐条执行程序时,如遇上用户程序中的软中断指令INT(如INT 21H),这时,通常不要用单步工作方式执行
40、INT指令。因为系统提供的软中断指令INT是以中断处理子程序形式实现功能调用,且这种处理子程序常常是较长的。若用T命令去执行INT指令,那么将跳转到相应的功能调用于程序中,要退出该子程序需要化费较多时间。如果既要执行INT指令,又要跳过这段功能调用子程序,则应使用连续工作方式(G命令),且设置断点,其断点应为INT指令的下一条指令。例如要以单步工作方式执行下面一段程序: 10B0:0022 MOV DX,0010 10B0:0026 MOV AH,09 10B0:0028 INT 21
41、 10B0:002A MOV CX,00
当用T命令完成“MOV AH,09”指令后,应使用G命令:
-G 002A
42、若发现程序有错,则需要适当进行修改。这时,如果仅需作个别修改,可在DEBUG状态下,使用A命令。这种修改仅仅是临时修改内存中的可执行文件,未涉及源程序。当确认修改正确后,应返回至编辑程序,修改源程序,然后再汇编、连接。 为了确认用户程序的正确性,常常需用几组不同的原始数据去运行程序,查看是否都能获得正确结果。这时,可用E命令在用户程序的数据段和附加段中修改原始数据,然后再用T命令或G命令运行程序,查看运行结果,直到各组数据都能获得正确结果为止。 8.运用断点调试程序 如果已确认程序是正确的,在连续工作方式下,可快速地运行程序;如果已知程序运行结果不正确,用G命令运行程序
43、中途不停,很难查找错误。改用T命令,虽然可以随意暂停程序的执行,但是运行速度慢,如果运用断点,可快速查找错误。这里的“断点”是程序连续运行时要求暂停的指令位置(地址),用要求暂停的一条指令首字节地址表示。当程序连续运行到这断点地址时,程序就暂停,并显示现在各寄存器内容和下面将要执行的指令(即断点处指令)。为了准确设置断点,可用反汇编命令U 察看源程序。运用断点,可以很快地查找出错误发生在哪一个程序段内,缩小查找错误的范围。然后在预计出错的范围内,再用T命令仔细观察程序运行情况,确定出错原因和位置,完成程序的调试。 例5 现有一个双字加法源程序如下,其中存在错误。现假设已汇编、连结生成了可执
44、行文件SZJiaFa.EXE,存放在C:/DOS目录下。请使用DEBUG对其进行调试。 Code SEGMENT ASSUME CS:code,DS:code ORG 100H ;从100H处开始存放下列指令 Start:MOV AX,code ;将DS置成code段的首地址 MOV DS,AX MOV SI,200H ;取第一个数的首地址 MOV AX,[SI] ;将第一个数的低16位取到AX MOV DI,204H ;
45、取第二个数的首地址 ADD AX,[DI] ;第一个数和第二个数的低16应相加 MOV [SI+8],AX ;低16位相加的结果送到208H和209H单元 MOV AX,[SI+2] ;取第一个数的高16位送到AX中 ADD AX,[DI+2] ;两个数的高16位相加 MOV [SI+0AH],AX ;高16位相加的结果送到20AH,20BH单元 MOV AX,4C00H ;使用DOS的4CH号功能调用 INT 21H
46、 ;进入功能调用,返回DOS
ORG 200H ;从200H处开始存放下列数据
DD 12345678h,654387A9h,0h ;被加数、加数、和
Code ENDS
END start
调试过程:
(1)进入DEBUG并装入可执行文件SZJiaFa.EXE
C:/DOS>DEBUG SZJiaFa.EXE
47、DI=0000
DS=1892 ES=1892 SS=18A2 CS=18A2 IP=0100 NV UP EI PL NZ NA PO NC
18A2:0100 B8A218 MOV AX,18A2
(3)以单步工作方式开始运行程序
首先用T命令顺序执行用户程序的前l两条指令,将段寄存器DS预置为用户的数据段。
-T
48、A2 IP=0103 NV UP EI PL NZ NA PO NC
18A2:0103 8ED8 MOV DS,AX
-T
49、20F
50、 MOV AX,[SI] 18A2:010A BF0402 MOV DI,0204 18A2:010D 0305 ADD AX,[DI] 18A2:010F 894408 MOV [SI+08],AX 18A2:0112 8B4402 MOV AX,[SI+02] 18A2:0115 034502 ADD AX,[DI+02] 18A2:0118 89440A MOV [SI+0A],AX 18A2:011






