汇编调试命令debug的详细用法
在学习16位汇编时,debug是常用的调试工具,但很多基本用法,帮助中并未提及。本文中的基本概念是指命令语法中需要提供给命令的参数,在命令帮助中并未提供任何提示。经查资料和试验,特记录如下:
一、基本概念:
DOS5.0之前debug是com格式,从5.0之后就改为exe格式了,本文是指的是DOS6.22中的debug.exe格式。debug可加载exe或com文件,并显示内存中内容或变量值,还可以显示cpu的寄存器值。可以显示可执行文件的机器码(汇编的方式),只支持8086/8088(8087)指令,并且可以通过单步执行汇编代码,检测程序的逻辑错误,并可修改汇编代码或内存数据。
如果想更多支持,可使用DR-DOS7.0自带的debug,可支持到pentium指令级,更多选择:Microsoft的CodeView、Borland的TurboDebug或Debug32等。
1、命令语法:
dos下输入:debug 可执行文件名称,然后进入命令提示符界面(横线-),输入:命令 参数。
例如:
c:\>debug hello.exe(回车)
-?(回车) 显示帮助
-r(回车) 显示cpu寄存器值
2、参数分隔符
debug中参数之间的分隔符可用“空格”或“逗号”,效果一致,如:
-u 100 110等于-u 100,110
-d 0100:0000 0010等于-d 0100:0000,0010
3、value的表示
无论是debug的参数中含有的地址,立即数或汇编代码中的数字,都是十六进制,无需加前缀或后缀,范围只能是0~4位。
字符需要引号,如:'a'
4、debug命令和代码不区分大小写。
5、地址(address)表示
1)完全地址形式(段地址segment:偏移地址offset):段地址可通过段寄存器名称和立即地址表示,如地址可通过DS:0010和0100:0010两种方式表示。
2)默认段地址形式(偏移地址offset):-d 0100(默认段地址是DS)。
3)部分指令,参数中地址的形式是:=address,这是因为参数中可添加多个数值参数,为了区分,其中一个用=address的方式。如:-g =0003 0008(0003代表开始地址,0008代表断点偏移地址)
6、range的写法
参数range有2种写法:
1)开始地址和结束地址,如:
-d 0100:0000 0010(开始地址与结束地址位于同一个段,不能跨段)
-d 0000 0010 (起始都是默认段地址DS)
2)开始地址和长度,如:
-d 0100:0000 L 0080(开始地址和长度,字母L大小写均可)
7、list的写法
用分隔符把各项罗列出来,如-f 0100:0110 1f 2f 3f ff(用数值列表轮流填充)
8、string的表示
'string'或"string"都行,表示一串字符,实质相当于字符list
9、路径path规范
文件的路径可写成完整路径,如当前目录,可省略路径
10、加载汇编代码
可通过debug < hello.asm的方式加载命令行代码,就相当于手动输入每一行(最后必须有Q命令)。当然,debug < hello.asm > output.txt,也可将输出的信息发送到文件output.txt。
;hello.asm文件
a 100
mov ax,5
mov bx,10
add ax,bx
int 20
(blank line)
Q
11、Debug初始状态
Debug加载时,Dos位于内存的最低地址(640K)端,紧接着是Debug,最后是debug载入的程序;
所有段寄存器都设置成可用内存的最低段地址处;
IP设置成0100h(为psp留空间);
当前段的最后256字节留给栈;
BX:CX的值代表载入程序的长度(BX代表高字节,CX代表低字节);
Flag寄存器值:NV UP EI PL NZ NA PO NC
二、命令用法:
首先Q命令,-q(回车),退出debug命令。
1、N(指定文件名称)
语法:n [pathname] [arglist]
pathname指定写出(W)或载入(L)的文件名称(包括路径和文件名),如载入hello.exe。
arglist相当于执行上述hello执行时需要的参数(本例没有),如dir c:\中c:\就是arglist。debug是需要将程序载入后模拟执行的,所以如果执行程序所需参数也要加上。
-N c:\c\hello.exe
-L
也可直接通过debug c:\c\hello.exe载入。
2、R(寄存器操作)
语法:r [register](r和reg之间的空格可以省略)
R显示所有寄存器的值,R reg显示置顶寄存器得值,并可修改其值。reg指16位寄存AX、CS、F(flag寄存器)等,不能操作al,ah非16位寄存器。
-r(显示所有寄存器的值)
-r ax(显示ax的值,并在冒号:处提示输入新值,直接回车则表示不修改)
ax 0000
:
-r f(显示标志寄存器的值,并在断线-处提示输入新值,直接回车则表示不修改)
NV UP EI PL NZ NA PO NC -ZR AC(新值是表示每个标志位的值,顺序不限,值个数不限)
标志位的值对应的代码如下:
标志位 设置1 设置0
--------------- --------------- -------------------
Overflow of = OV (OVerflow) NV [No oVerflow]
Direction df = DN (decrement) UP (increment)
Interrupt if = EI (enabled) DI (disabled)
Sign sf = NG (negative) PL (positive)
Zero zf = ZR [zero] NZ [ Not zero]
Auxiliary Carry af = AC NA [ No AC ]
Parity pf = PE (even) PO (odd)
Carry cf = CY [Carry] NC [ No Carry]
3、D(显示块数据)
语法:d [range]
不指定range,默认当前位置开始(一开始是DS:0000),显示128个字节的数据;可指定range,range语法参考文章开头。
-d 0100:0000 0010(结束地址段地址与开始相同,不能跨段)
-d 0000 0010 (起始都是默认段地址)
-d 0100:0000 L 0080(开始地址和长度)
4、E(修改块数据)
语法:d address [list]
默认段为DS。
如果不指定list就根据提示(提示显示的是当前地址的原数据,原点后输入新数据),从指定地址address开始,逐字节输入数据,每输入一个字节按一次空格进行下一次输入。要停止输入时直接按回车。
或通过list,直接指定数据(用空格隔开)或字符串(单引号或双引号)。
-d 0(从偏移地址0处,手动输入,原数据是0e,圆点.后输入新数据)
4dc5:0000 0e.
-d 0 "hello"(从偏移地址0处,依次数据为字符h e l l o)
-d 0 12 34 56 ef
5、U(反编译)
语法:d [range]
默认段为CS。从指定地址处开始将机器码转换成汇编代码,地址必须是合理的地址(因机器码可以看成数据,也可以看成代码)。
4ddd:0000 B8DC4D mov ax,4DDC
4ddd:0003 8ed8 mov ds,ax
4ddd:0005 B440 mov ax,40
如上代码,此处就不能从0002处开始反汇编,虽然也能解析成代码,但后面的代码都没有意义。
如果range中通过L指定反编译的范围,L后面的数值是大概指字节数,为什么是“大概”,因为指定长度的位置的代码可能没有完全显示当前的指令,需要在向后显示几个字节。
如上代码:u 0000 L 4就需要再向后一个字节,因为该处的代码没显示完。
6、A(输入汇编代码)
语法:a [address]
默认段为CS。
从指定地址address处写汇编代码,只支持8086/8088(8087)指令,也支持db,dw两个伪指令,最后一行直接回车结束汇编代码输入模式。
-a 100
4ddd:1000 mov ax,4ddc
4ddd:1003 mov ds,ax
4ddd:1005 (直接回车结束编辑)
-
-a 110
-4ddd:0110 db "hello" (定义数据)
7、G(输入汇编代码)
语法:g [=address] [addresses]
默认段为CS,不指定参数=address则表示从当前位置,不指定参数addresses则表示执行到程序最后。
=address位起点地址,起点位置要是有效的位置(原因如同u指令);addresses为断点位置,可以指定10个,多个断点间用空格分割。不指定断点则执行到程序最后。
因为2个都是地址,为了区分,前一个加等号=。
断点只一次有效,为什么要指定多个断点呢,因为可能不确定程序的执行方向,多设置几个断点。
程序执行完毕后,再g则退出debug。
-g =0002 0008 0011
从0002处执行,可在0008或0011处中断,先执行到哪就在哪停止,执行完毕后清除断点,下一次g指令时,这些断点无效。
8、P(单步或指定步数)
语法:p [=address] [number]
默认段为CS,不指定参数=address则表示从当前位置,不指定参数number则表示执行1步。
=address位起点地址,起点位置要是有效的位置(原因如同u指令);
number是运行指令的条数,不指定,默认是1条。
p指令遇到子程序或中断程序,直接运行子程序和中断程序,不进入子程序或中断程序内部单步执行,相当于调试高级程序中的Step Over。
9、T(单步或指定步数)
语法:t [=address] [number]
默认段为CS,不指定参数=address则表示从当前位置,不指定参数number则表示执行1步。
=address位起点地址,起点位置要是有效的位置(原因如同u指令);
number是运行指令的条数,不指定,默认是1条。
p指令遇到子程序或中断程序,要单步进入子程序和中断程序内部,相当于调试高级程序中的Step Into。
10、M(复制数据块)
语法:m range address
默认段为DS。
复制range的数据到起始点位address的内存处。如果range用了段前缀,address的段前缀也需指定,否则range和address可能不在一个段。
-m 4ddc:0000 3 5
这里的range所在段是4ddc,adress所在段为ds。
-m 4ddc:0000 0003 4ddc:0005
range和adress在同一个段
11、S(搜索数据块)
语法:s range list
默认段为DS。
搜索到了,显示搜索到的地址,多处显示多处地址。
两种range的写法:
-s fe00:0 L ffff "BIOS"
-s fe00:0 ffff "BIOS"
FE00:0021
FE00:006F
数据区域
-d fe00:0
FE00:0000 41 77 61 72 64 20 53 6F-66 74 77 61 72 65 49 42 Award SoftwareIB
FE00:0010 4D 20 43 4F 4D 50 41 54-49 42 4C 45 20 34 38 36 M COMPATIBLE 486
FE00:0020 20 42 49 4F 53 20 43 4F-50 59 52 49 47 48 54 20 BIOS COPYRIGHT
FE00:0030 41 77 61 72 64 20 53 6F-66 74 77 61 72 65 20 49 Award Software I
FE00:0040 6E 63 2E 6F 66 74 77 61-72 65 20 49 6E 63 2E 20 nc.oftware Inc.
FE00:0050 41 77 03 0C 04 01 01 6F-66 74 77 E9 12 14 20 43 Aw.....oftw... C
FE00:0060 1B 41 77 61 72 64 20 4D-6F 64 75 6C 61 72 20 42 .Award Modular B
FE00:0070 49 4F 53 20 76 34 2E 35-31 50 47 00 DB 32 EC 33 IOS v4.51PG..2.3
12、C(比较数据块)
语法:c range list
默认段为DS。
比较两个数据块的数据是否一致,将不一致的地址和各自的数据显示出来。
13、F(填充数据块)
语法:f range list
默认段为DS。
用list数据填充区域range,如果list的长度小于range的长度,则重复填充。跟MASM中的db 100 dup("ha")方式一致,就是填充50个"ha"。
14、I和O(端口读写)
语法: i port
o port byte(byte的值是16位整数)
对端口进行读写(端口的定义请查阅其他博文),如读取CMOS芯片的小时:
-o 70 04
-i 71
08(当前小时是8)
-
15、H(16位整数的加减)
语法: h value1 value2
计算value1+value2和value1-value2,2个结果同时显示,对标志位不影响。
-h aaa 531
0FDB 0579(前一个是和,后一个是差)
-
16、L(加载数据)
语法:L [address] [drive] [firstsector] [number]
如程序执行完毕,可通过L可再次加载程序,如g指令后可通过L重新开始。
加载有3种形式,BX和CX共同表示文件长度,如文件长123456H字节,BX=0012H,CX=3456H。
L(直接加载N指定的文件到CS:0100)
L DS:200(加载N指定的文件到DS:0200)
L 100 2 A 5(从C盘0Ah逻辑扇区开始加载5个扇区到CS:0100,L address drvie firstSector number,drive从0开始表示A盘,1=B、2=C以此类推,每个扇区521Byte)
MBR储存在C盘0扇区,可加载查看(MBR最后2个字节是55AA,地址为0100+01FF)
17、W(向磁盘写数据)
语法:w [address] [drive] [firstsector] [number]
使用方法基本同L。
BX和CX共同表示文件长度,如文件长123456H字节,BX=0012H,CX=3456H;执行W时需通过R指令设置BX、CX数值。
R BX 0(设置文件长度)
R CX 20(设置文件长度)
W(从CS:0100开始,写20H字节到文件)
W 0(从CS:0000开始,写20H字节到文件)
W DS:200(从DS:0200开始,写20H字节到文件)
W 100 2 0 1(从CS:0100开始,写1个扇区数据,到C盘0逻辑扇区。可以用来写MBR程序到磁盘或软盘)
18、XA、XD、XM、XS(内存操作)
语法:
未完待续...