以是大小写的结合。Ctrl+Break键可中止命令的执行。Ctrl+Num
Lock键可暂停屏幕卷动,按任一键继续。所用数均为十六进制数,且不必写H。
* 1. 汇编命令A
格式:A [[<段寄存器名>/<段地址>:] <段内偏移>]
上式等价于:
(1) A <段寄存器名>:<段内偏移>
(2) A <段地址>:<段内偏移>
(3) A <段内偏移>
(4) A
功能:键入该命令后显示段地址和段内偏移并等待用户从键盘逐条键入汇编命令,逐条汇编成代码指令,顺序存放到段地址和段内偏移所指定的内存区域,直到显示下一地址时用户直接键入回车键返回到提示符“
-”。
注:
其中(1)用指定段寄存器的内容作段地址,(3)用CS的内容作段地址,(4)以CS:100作地址。以后命令中提及的各种‘地址’形式,均指(1)、(2)、(3)中A后的地址形式。
2. 比较命令C
格式: C <源地址范围>,<目标地址>
其中<范围>是由<起始地址> <终止地址>或者是由<起始地址> L
<长度>指出的一片连续单元。
功能:从<源地址范围>的起始地址单元起逐个与目标起始地址以后的单元顺序比较单元的内容,直至源终止地址为止。遇有不一致时,以<源地址>
<源内容> <目标内容> <目标地址>的形式显示失配单元及内容。
* 3. 显示内存命令D
格式: D [<地址>/<范围>]
上式等价于:
(1) D <地址>
(2) D <范围>
(3) D
功能:以两种形式显示指定范围的内存内容。一种形式为十六进制内容,一种形式为以相应字节的内容作为ASCII码的字符,对不可见字符以‘.’代替。
注: 其中(1)以CS为段寄存器。(3)显示CS:100起始的一片内容。
* 4. 修改内存命令E
格式: E <地址> [<单元内容表>]
上式等价于:
(1) E <地址>
(2) E <地址> <单元内容表>
其中<单元内容表>是以逗号分隔的十六进制数,或用’或”括起来的字符串,或者是二者的组合。
功能:
(1)不断显示地址,可连续键入修改内容,直至新地址出现后键入回车Enter为止。(2)将<单元内容表>逐一写入由<地址>开始的一片单元。
5. 填充内存命令F
格式: F <范围> <单元内容表>
功能: 将单元内容表中的值逐个填入指定范围,单元内容表中内容用完后重复使用。
例如:
-F 5BC:200 L 10 B2,‘XYZ’,3C <Enter>
* 6. 执行命令G
格式: G [=<地址>[,<断点>]]
上式等价于:
(1) G
(2) G=<地址>
(3) G=<地址>,<断点>
功能: 执行内存中的指令序列
注: (1)从CS:IP所指处开始执行
(2)从指定地址开始执行
(3)从指定地址开始执行,到断点自动停止。
7. 十六进制算求运算指令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区排列。而逻辑扇区与物理扇区号的对应关系为物理扇区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 <Enter>
-L <Enter>
将当前驱动器上的EXAMPLE文件装入CS:100起始的一片内存单元。
10. 内存搬家命令M
格式: M <源地址范围> <目标起始地址>
其中源及目标地址若仅输入偏移量,则隐含相对DS。
功能:把<源地址范围>中的内容顺序搬至<目标起始地址>起的一片连续单元。
例如:
-M CS:100 110 600
把从CS:100起至CS:110止17个字节搬至DS:600至DS:610的一片单元。
* 11. 命名待读/写文件命令N
格式: N <文件名说明>
功能: 为L/W命令指定待装入/写盘文件
注: 其它形式参考DOS手册
12. 端口输出命令O
格式: O <端口地址> <字节>
功能:将该<字节>从指定<端口地址>输出。
例如:
-O 2F 4F <Enter>
将4FH从端口2FH输出
* 13. 结束DEBUG返回DOS命令Q
格式:Q
功能:返回DOS提示符下
* 14. 显示修改寄存器命令R
格式: R [<寄存器名>]
上式等价于:
(1) R
(2) R <寄存器名>
功能:
(1)显示当前所有寄存器内容,状态标志及将要执行的下一指令的地址,代码及汇编语句形式。其中对状态标志FLAG以每位的形式显示,详见
表5-1。
表5-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 <Enter>
-R F
<Enter>
15. 搜索指定内存命令S
格式: S <地址范围> <表>
功能:在指定范围搜索表中内容,找到后显示表中元素所在地址
例如:
-S CS:100 110 41
<Enter>
显示:04BA:0104
04BA:010D
表示在位移100H至110H间的上述两处有41H。又如:
-S C3:100 L
11 41“AB”E
<Enter>
表示在当前代码段位移100H至111H处寻找连续4个字节内容为41H、41H、42H、0EH的起始单元地址。
* 16. 执行并显示系统环境命令T
格式:T [=<地址>] [<条数>]
功能:执行由指定地址起始的、由<条数>指定的若干条命令。其中<地址>的缺省值是当前IP值,<条数>的缺省值是一条。
例如:
-T <Enter>
执行当前指令并显示状态
-T 10 <Enter>
从当前指令始执行10H条指令
* 17. 反汇编命令U
格式:U [<地址>/<地址范围>]
上式等价于:
(1) U
<地址>
(2) U
<地址范围>
(3) U
功能:将指定范围内的代码以汇编语句形式显示,同时显示地址及代码。注意,反汇编时一定确认指令的起始地址后再作,否则将得不到正确结果。地址及范围的缺省值是上次U指令后下一地址的值。这样可以连续反汇编。
* 18. 写盘命令W
格式:W <地址> <盘号> <起始逻辑扇区>
<所写逻辑扇区数n>
功能:与L命令不同的地方是将内存从<地址>起始的一片单元内容写入指定扇区。只有W而没有参数时,与N命令配合使用将文件写盘。
注:要求读者对其中打'*'的DEBUG命令必须能熟练使用。
第三节 在DEBUG环境下执行汇编指令
本节从几个典型例子出发,通过上机实习,引导读者学会使用DEBUG调试程序运行汇编语言程序,以便读者在以后的学习中能够有一个熟练的调试和运行手段。
在进入DEBUG的提示符‘
-’之后,用户可以通过DEBUG的命令输入汇编源程序,并用相应命令将其汇编成机器语言程序;然后调试并运行该程序。
例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
<Enter>,即
C:\DOS>DEBUG <Enter>
屏幕显示: -
‘-’号是进入DEBUG的提示符,在该提示符下可键入任意DEBUG命令。现在用A命令送程序如下:
(2)送程序并汇编
-A 100 <Enter>
169C:0100 MOV DL,33 <Enter>
169C:0102 MOV AH,2 <Enter>
169C:0104 INT 21 <Enter>
169C:0106 INT 20 <Enter>
169C:0108 <Enter>
- <Enter>
至此程序已送完,汇编成机器指令,顺序存放于CS段100H起始的8个存储单元。
如果在汇编后想看一下机器指令是什么样子的话,方法之一是可以用反汇编命令U作如下操作:
(3)反汇编
-U 100 108 <Enter>
169C:0100
B233
MOV DL,33
169C:0102
B402
MOV AH,02
169C:0104
CD21
INT 21
169C:0106
CD20
INT 20
169C:0108
-
右边是汇编指令,中间是该汇编指令的机器码,左边是存放该条指令的内存单元地址。
(4)运行程序
-G <Enter>
3
Program terminated normally
-
(5)写COM文件
-R BX <Enter>
BX 0000
: <Enter>
-R CX <Enter>
CX 0000
:A <Enter>
-N EXCOM.COM <Enter>
-W <Enter>
-
其中(BX)*10000H+(CX)用于指定所写的字节数,(BX)为该数的高16位,(CX)为该数的低16位。因此,上面的过程实际上是要将A个字节写入文件EXCOM.COM。
(6)送机器指令程序
-E 200 B2 33 B4 02 CD 21 CD 20
<Enter>
-
(7)显示内存
-D 200 208 <Enter>
169C:0200
B2 33 B4 02 CD 21 CD 20-61
. 3 . . . ! . . a
-
(8)执行机器指令程序
-G=200 <Enter>
3
Program terminated normally
-
(9)退出DEBUG返回DOS,执行EXCOM.COM文件
-Q
C:\DOS>EXCOM <Enter>
3
C:\DOS>
例2 进入DEBUG,用A命令送字节数据加法程序,用R命令显示状态,并用T命令单条执行
(1)进入并用A命令写入汇编源程序
C:\DOS>DEBUG <Enter>
-A <Enter>
1392:0100
MOV AH,3 <Enter>
1392:0102
MOV AL,2 <Enter>
1392:0104
ADD AL,AH <Enter>
1392:0106
INT 20 <Enter>
1392:0108 <Enter>
-
(2)用R命令显示寄存器状态
-R <Enter>
AX=0000
BX=0000
CX=0000
DX=0000
SP=0000
BP=0000
SI=0000
DI=0000 DS=1392
ES=1392
SS=1392
CS=1392
IP=0100
NV
UP
EI
PL
NZ
NA
PO
NC
1392:0100
B403
MOV AH,03
-
(3)用G命令执行,但看不到计算结果。
-G <Enter>
Program
terminated
normally
-
(4)用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
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
CD02
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 <Enter>
C:\DOS>
例3 在DEBUG下运行下述程序,查看执行结果,并将其作为可执行文件存入A盘。
MOV AX,0FEH
;被乘数0FEH送AX
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号功能调用,结束程序返回DOS。
该程序运行结果是将0FEH乘以14H,结果放在DS段第300H—301H号内存单元中。
(1)进入DEBUG,显示300H至301H号内存单元内容
C:\DOS>DEBUG <Enter>
-D 300 301 <Enter>
1392:0300 00 00
. .
-
(2)用A命令装入程序段并汇编
-A <Enter>
1392:0100
MOV AX,0FE <Enter>
1392:0102
MOV CL,2 <Enter>
1392:0104
SHL AX,CL <Enter>
1392:0106
MOV BX,AX <Enter>
1392:0108
MOV CL,2
<Enter>
1392:010A
SHL AX,CL <Enter>
1392:010C
ADD AX,BX <Enter>
1392:010E
MOV [300],AX <Enter>
1392:0111
MOV AH,4C <Enter>
1392:0113
INT 21 <Enter>
1392:0116 <Enter>
-
(3)用G命令执行到断点处(程序正常结束前)停止
-T=100,8 <Enter>
AX=13D8
BX=3F80
CX=0000
DX=0000
SP=0000
BP=0000
SI=0000
DI=0000
DS=1392
ES=1392
SS=1392
CS=1392
IP=0111
NV UP DI PL NZ NA PO
NC
1392:0111 B44C
MOV AH,4C
-
(4)用D命令显示300H至301H的内容(最终结果)
-D 300 301 <Enter>
1392:0300
D8 13
..
-
(5)用R命令指定写盘文件长度
-R BX <Enter>
BX 3F80
:0 <Enter>
-R CX <Enter>
CX 0000
:16 <Enter>
-
(6)用N命令命名写盘文件
-N A:YWZCHF.COM <Enter>
(7)用W命令写盘
-W <Enter>
-
(8)用Q命令退出DEBUG环境,返回DOS
-Q <Enter>
C:\DOS>
(9)在DOS环境运行YWZCHF.COM
C:\DOS>A:YWZCHF <Enter>
C:\DOS>
(10)将YWZCHF.COM装入内存运行
C:\DOS>DEBUG <Enter>
-N A:YWZCHF.COM <Enter>
-L <Enter>
-T=100,8 <Enter>
AX=13D8
BX=3F80
CX=0000
DX=0000
SP=0000
BP=0000
SI=0000
DI=0000
DS=1392
ES=1392
SS=1392
CS=1392
IP=0111
NV UP DI PL NZ NA PO
NC
1392:0111 B44C
MOV AH,4C
-D 300 301 <Enter>
1392:0300
D8 13
..
(11)用Q命令退出DEBUG环境,返回DOS
-Q <Enter>
C:\DOS>
例4
在DEBUG环境下,送入一个加法源程序并汇编成可执行代码;将其作为可执行文件JIAFA.COM存储到A盘;在DOS命令行执行可执行文件JIAFA.COM;进入DEBUG,将可执行文件JIAFA.COM装入内存CS:100H处运行,并用T命令查看运算结果。
C:\DOS>debug <Enter>
-A <Enter>
169C:0100 MOV AX,8A6D <Enter>
169C:0103 ADD AX,0382 <Enter>
169C:0106 MOV [0200],AX <Enter>
169C:0109 MOV AH,4C <Enter>
169C:010B INT 21 <Enter>
169C:010D <Enter>
-R BX <Enter>
BX 0000
: <Enter>
-R CX <Enter>
CX 0000
:D <Enter>
-N A:JIAFA.COM <Enter>
-W <Enter>
-Q <Enter>
C:\DOS>
C:\DOS>DEBUG <Enter>
-N A:JIAFA.COM <Enter>
-L <Enter>
-G <Enter>
Program terminated normally
-T=100,3 <Enter>
AX=8DEF
BX=0000
CX=0000
DX=0000
SP=0000
BP=0000
SI=0000
DI=0000
DS=1392
ES=1392
SS=1392
CS=1392
IP=0109
NV
UP
DI
PL
NZ
NA
PO
NC
1392:0111 B4 4C
MOV AH,4C
-D 200 201 <Enter>
169C:0200 EF 8D
..
-Q <Enter>
C:\DOS>
第四节 使用DEBUG调试和运行可执行文件
事实上,在第三节例题中已经对使用DEBUG命令调试和运行可执行文件有所接触。本节只需对使用DEBUG调试和运行可执行文件的一般步骤做一介绍,并通过一个含有错误的程序来对程序调试进行实践。
用户程序经过编辑、汇编、连接后得到一个可执行文件(.EXE),这时借助于调试程序DEBUG对用户程序进行调试,查看程序是否能完成预定功能。对于初学者,如何选用DEBUG中各命令,有效地调试与运行程序,需要一个学习过程。在初次使用DEBUG时,可参照下列步骤进行。
1.调用DEBUG,装入用户程序
可以在调用DEBUG是直接装入用户程序可执行文件,也可以在进入DEBUG环境后使用N命令和L命令装入用户程序可执行文件。无论用哪种方法,装入用户程序可执行文件时,一定要指定文件全名(即文件名和扩展名)。
2.观察寄存器初始状态
程序装入内存后,用R命令查看寄存器内容。从各段寄存器现在的内容,便能了解用户程序各逻辑段(代码段,堆栈段等)在内存的分布及其段基值。R命令亦显示了各通用寄存器和标志寄存器的初始值,显示的第三行就是即将执行的第一条指令。
3.以单步工作方式开始运行程序
首先用T命令顺序执行用户程序的前几条指令,直到段寄存器DS和/或ES已预置为用户的数据段。在用T命令执行程序时,每执行一条指令,显示指令执行后寄存器的变化情况,以便用户查看指令执行结果。
4.观察用户程序数据段初始内容
在第3步执行后DS和/或ES已指向用户程序的数据段和附加段,这时用D命令可查看用户程序的原始数据。
5.继续以单步工作方式运行程序
对于初学者,一般编写的程序比较短,用T命令逐条执行指令,可清楚地了解程序的执行过程:现在执行的是什么指令,执行后的结果在哪里(寄存器,存储单元)?所得结果是否正确?…等等。在逐次使用T命令时,若有需要,可选用D命令了解某些内存单元的变化情况。
用T命令逐条执行程序时,如遇上用户程序中的软中断指令INT(如INT
21H),这时,通常不要用单步工作方式执行INT指令。因为系统提供的软中断指令INT是以中断处理子程序形式实现功能调用,且这种处理子程序常常是较长的。若用T命令去执行INT指令,那么将跳转到相应的功能调用于程序中,要退出该子程序需要化费较多时间。如果既要执行INT指令,又要跳过这段功能调用子程序,则应使用连续工作方式(G命令),且设置断点,其断点应为INT指令的下一条指令。例如要以单步工作方式执行下面一段程序:
10B0:0022
MOV
DX,0010
10B0:0026
MOV
AH,09
10B0:0028
INT
21
10B0:002A
MOV
CX,00
当用T命令完成“MOV
AH,09”指令后,应使用G命令:
-G
002A <Enter>
这样,以连续工作方式实现功能调用后,即暂停在偏移量为002A的“MOV
CX,00”指令处(未执行),如同用单步工作方式完成INT指令的执行一样。
6.连续工作方式运行程序
在用单步工作方式运行程序后,可再用连续工作方式从头开始运行程序,查看运行结果。在用G命令时,注意指定运行程序的起始地址。若G命令中未指定起始地址,就隐含为从当前CS:IP指向的指令开始。
7.修改程序和数据
经过上面几步后,若发现程序有错,则需要适当进行修改。这时,如果仅需作个别修改,可在DEBUG状态下,使用A命令。这种修改仅仅是临时修改内存中的可执行文件,未涉及源程序。当确认修改正确后,应返回至编辑程序,修改源程序,然后再汇编、连接。
为了确认用户程序的正确性,常常需用几组不同的原始数据去运行程序,查看是否都能获得正确结果。这时,可用E命令在用户程序的数据段和附加段中修改原始数据,然后再用T命令或G命令运行程序,查看运行结果,直到各组数据都能获得正确结果为止。
8.运用断点调试程序
如果已确认程序是正确的,在连续工作方式下,可快速地运行程序;如果已知程序运行结果不正确,用G命令运行程序,中途不停,很难查找错误。改用T命令,虽然可以随意暂停程序的执行,但是运行速度慢,如果运用断点,可快速查找错误。这里的“断点”是程序连续运行时要求暂停的指令位置(地址),用要求暂停的一条指令首字节地址表示。当程序连续运行到这断点地址时,程序就暂停,并显示现在各寄存器内容和下面将要执行的指令(即断点处指令)。为了准确设置断点,可用反汇编命令U
察看源程序。运用断点,可以很快地查找出错误发生在哪一个程序段内,缩小查找错误的范围。然后在预计出错的范围内,再用T命令仔细观察程序运行情况,确定出错原因和位置,完成程序的调试。
例5
现有一个双字加法源程序如下,其中存在错误。现假设已汇编、连结生成了可执行文件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
;取第二个数的首地址
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
;进入功能调用,返回DOS
ORG 200H
;从200H处开始存放下列数据
DD 12345678h,654387A9h,0h
;被加数、加数、和
Code ENDS
END start
调试过程:
(1)进入DEBUG并装入可执行文件SZJiaFa.EXE
C:\DOS>DEBUG SZJiaFa.EXE<Enter>
-
(2)观察寄存器初始状态
-R <Enter>
AX=0000
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0000
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 <Enter>
AX=18A2
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0000
DI=0000
DS=1892
ES=1892
SS=18A2
CS=18A2
IP=0103
NV UP EI PL NZ NA PO NC
18A2:0103 8ED8
MOV
DS,AX
-T <Enter>
AX=18A2
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0000
DI=0000
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=0105
NV UP EI PL NZ NA PO NC
18A2:0105 BE0002
MOV
SI,0200
(4) 观察用户程序数据段初始内容
-D 200 20F <Enter>
18A2:0200
78 56 34 12 A9 87 43 65-00 00 00 00 00 74 13 50
xV4...Ce.....t.P
-
(5) 连续工作方式运行程序至返回DOS前(设断点),查看运行结果。为此,现使用U命令反汇编。
-U 100 <Enter>
18A2:0100 B8A218
MOV
AX,18A2
18A2:0103 8ED8
MOV
DS,AX
18A2:0105 BE0002
MOV
SI,0200
18A2:0108 8B04
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:011B B8004C
MOV
AX,4C00
18A2:011E CD21
INT
21
-
可见,要执行10条指令,至011B处停止
-G=100,011B <Enter>
AX=7777
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0200
DI=0204
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=011B
NV UP EI PL NZ NA PE NC
18A2:011B B8004C
MOV
AX,4C00
-D 200 20F <Enter>
18A2:0200
78 56 34 12 A9 87 43 65-21 DE 77 77 43 43
83 06
xV4...Ce!.wwCC..
-
和为7777DE21H,正确。
(6) 再取一组数据,查看运行结果。为此,首先用E命令修改数据。
-E 200 CD,AB,78,56,90,EF,34,12 <Enter>
-D 200 20F <Enter>
18A2:0200
CD AB 78 56 90 EF 34 12-21 DE 77 77 43 43
83 06
..xV..4.!.wwCC..
-G=100,11B <Enter>
AX=68AC
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0200
DI=0204
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=011B
NV UP EI PL NZ NA PE NC
18A2:011B B8004C
MOV
AX,4C00
-D 200 20F <Enter>
18A2:0200
CD AB 78 56 90 EF 34 12-5D 9B AC 68 43 43
83 06
..xV..4.]..hCC..
-
和为68AC9B5DH,错误。说明程序有问题。
(7) 再将断点设在完成低位字加法后,查看运行结果。
-G=100,112 <Enter>
AX=9B5D
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0200
DI=0204
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=0112
NV UP EI NG NZ NA PO CY
18A2:0112 8B4402
MOV
AX,[SI+02]
DS:0202=5678
-D 200 20F <Enter>
18A2:0200
CD AB 78 56 90 EF 34 12-5D 9B AC 68 43 43
83 06
..xV..4.]..hCC..
-
低位和为9B5D,正确。说明错误可能出在后面
(8) 使用T命令从刚才的断点处向后单步调试,查看运行结果。
-T=112 <Enter>
AX=5678
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0200
DI=0204
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=0115
NV UP EI NG NZ NA PO CY
18A2:0115 034502
ADD
AX,[DI+02]
DS:0206=1234
-T <Enter>
AX=68AC
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0200
DI=0204
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=0118
NV UP EI PL NZ NA PE NC
18A2:0118 89440A
MOV
[SI+0A],AX
DS:020A=68AC
-
AX寄存器的结果为68AC,而应为68AD。可见是本条加法指令使用错误,这里应使用带进位加法指令。
(9)使用A命令装入正确指令后再次运行,察看结果。
-A 115 <Enter>
18A2:0115 ADC AX,[DI+02] <Enter>
18A2:0118 <Enter>
-G=100,11B <Enter>
AX=68AD
BX=0000
CX=020C
DX=0000
SP=0000
BP=0000
SI=0200
DI=0204
DS=18A2
ES=1892
SS=18A2
CS=18A2
IP=011B
NV UP EI PL NZ NA PO NC
18A2:011B B8004C
MOV
AX,4C00
-D 200 20F <Enter>
18A2:0200
CD AB 78 56 90 EF 34 12-5D 9B AD 68 43 43
83 06
..xV..4.]..hCC..
-
和为68AD9B5DH,正确。对于这样一个简单程序一般来说不会再有问题。退出后修改源程序即可。
(10)退出
-Q <Enter>
C:\DOS>
需要说明的是此程序很简单,只需使用T命令逐条单步调试即可。本例采用的调试方法似乎过于繁琐,但这是为了说明程序调试的一般方法,以便读者调试复杂程序时借鉴。