高分请问:编写activex控件时为什么无法进行调试(debug)? 使用VC自带的ACTIVEX控件调试器 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 DEBUG主要命令 DEBUG是为汇编语言设计的一种高度工具,它通过单步、设置断点等方式为汇编语言程序员提供了非常有效的调试手段。一、DEBUG程序的调用 在DOS的提示符下,可键入命令: C:\DEBUG [D:][PATH][FILENAME[.EXT]][PARM1][PARM2] 其中,文件名是被调试文件的名字。如用户键入文件,则DEBUG将指定的文件装入存储器中,用户可对其进行调试。如果未键入文件名,则用户可以用当前存储器的内容工作,或者用DEBUG命令N和L把需要的文件装入存储器后再进行调试。命令中的D指定驱动器PATH为路径,PARM1和PARM2则为运行被调试文件时所需要的命令参数。 在DEBUG程序调入后,将出现提示符,此时就可用DEBUG命令来调试程序。二、DEBUG的主要命令 1、显示存储单元的命令D(DUMP),格式为: _D[address]或_D[range] 例如,按指定范围显示存储单元内容的方法为: -d100 12018E4:0100 c7 06 04 02 38 01 c7 06-06 02 00 02 c7 06 08 02 G...8.G.....G...18E$:0110 02 02 bb 04 02 e8 02 00-CD 20 50 51 56 57 8B 37 ..;..h..M PQVW. 718E4:0120 8B 其中0100至0120是DEBUG显示的单元内容,左边用十六进制表示每个字节,右边用ASCII字符表示每个字节,·表示不可显示的字符。这里没有指定段地址,D命令自动显示DS段的内容。如果只指定首地址,则显示从首地址开始的80个字节的内容。如果完全没有指定地址,则显示上一个D命令显示的最后一个单元后的内容。2、修改存储单元内容的命令有两种。 ·输入命令E(ENTER),有两种格式如下:第一种格式可以用给定的内容表来替代指定范围的存储单元内容。命令格式为: -E address [list]例如,-E DS:100 F3'XYZ'8D 其中F3,'X','Y','Z'和各占一个字节,该命令可以用这五个字节来替代存储单元DS:0100到0104的原先的内容。 第二种格式则是采用逐个单元相继修改的方法。命令格式为: -E address例如,-E DS:100 则可能显示为: 18E4:0100 89.- 如果需要把该单元的内容修改为78,则用户可以直接键入78,再按“空格”键可接着显示下一个单元的内容,如下: 18E4:0100 89.78 1B.- 这样,用户可以不断修改相继单元的内容,直到用ENTER键结束该命令为止。 ·填写命令F(FILL),其格式为: -F range list例如:-F 4BA:0100 5 F3'XYZ'8D 使04BA:0100~0104单元包含指定的五个字节的内容。如果list中的字节数超过指定的范围,则忽略超过的项;如果list的字节数小于指定的范围,则重复使用list填入,直到填满指定的所有单元为止。3)检查和修改寄存器内容的命令R(register),它有三种格式如下: ·显示CPU内所有寄存器内容和标志位状态,其格式为: -R例如,-r AX=0000 BX=0000 CX=010A DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=18E4 ES=18E4 SS=18E4 CS=18E4 IP=0100 NV UP DI PL NZ NA PO NC 18E4:0100 C70604023801 MOV WORD PTR [0204],0138 DS:0204=0000 ·显示和修改某个寄存器内容,其格式为: -R register name例如,键入 -R AX 系统将响应如下: AX F1F4 :即AX寄存器的当前内容为F1F4,如不修改则按ENTER键,否则,可键入欲修改的内容,如: -R bx BX 0369 :059F则把BX寄存器的内容修改为059F。 ·显示和修改标志位状态,命令格式为: -RF系统将响应,如: OV DN EI NG ZR AC PE CY- 此时,如不修改其内容可按ENTER键,否则,可键入欲修改的内容,如: OV DN EI NG ZR AC PE CY-PONZDINV 即可,可见键入的顺序可以是任意的。4)运行命令G,其格式为: -G[=address1][address2[address3…]] 其中,地址1指定了运行的起始地址,如不指定则从当前的CS:IP开始运行。后面的地址均为断点地址,当指令执行到断点时,就停止执行并显示当前所有寄存器及标志位的内容,和下一条将要执行的指令。5)跟踪命令T(Trace),有两种格式: ·逐条指令跟踪 -T [=address] 从指定地址起执行一条指令后停下来,显示所有寄存器内容及标志位的值。如未指定地址则从当前的CS:IP开始执行。 ·多条指令跟踪 -T [=address][value] 从指定地址起执行n条指令后停下来,n由value指定。6)汇编命令A(Assemble),其格式为: -A[address] 该命令允许键入汇编语言语句,并能把它们汇编成机器代码,相继地存放在从指定地址开始的存储区中。必须注意:DEBUG把键入的数字均看成十六进制数,所以如要键入十进制数,则其后应加以说明,如100D。7)反汇编命令U(Unassemble)有两种格式。 ·从指定地址开始,反汇编32个字节,其格式为: -U[address]例如: -u100 18E4:0100 C70604023801 MOV WORD PTR[0204],0138 18E4:0106 C70606020002 MOV WORD PTR[0206],0200 18E4:010C C70606020202 MOV WORD PTR[0208],0202 18E4:0112 BBO4O2 MOV BX,0204 18E4:0115 E80200 CALL 011A 18E4:0118 CD20 INT 20 18E4:011A 50 PUSH AX 18E4:011B 51 PUSH CX 18E4:011C 56 PUSH SI 18E4:011D 57 PUSH DI 18E4:011E 8B37 MOV SI,[BX]如果地址被省略,则从上一个U命令的最后一条指令的下一个单元开始显示32个字节。 ·对指定范围内的存储单元进行反汇编,格式为: -U[range]例如: -u100 10c 18E4:0100 C70604023801 MOV WORD PTR[0204],0138 18E4:0106 C70606020002 MOV WORD PTR[0206],0200 18E4:010C C70606020202 MOV WORD PTR[0208],0202或 -u100 112 18E4:0100 C70604023801 MOV WORD PTR[0204],0138 18E4:0106 C70606020002 MOV WORD PTR[0206],0200 18E4:010C C70606020202 MOV WORD PTR[0208],0202 可见这两种格式是等效的。8)命名命令N(Name),其格式为: -N filespecs [filespecs]命令把两个文件标识符格式化在CS:5CH和CS:6CH的两个文件控制块中,以便在其后用L或W命令把文件装入存盘。filespecs的格式可以是:[d:][path] filename[.ext]例如, -N myprog -L -可把文件myprog装入存储器。9)装入命令(Load),有两种功能。 ·把磁盘上指定扇区范围的内容装入到存储器从指定地址开始的区域中。其格式为: -L[address[drive sector sector] ·装入指定文件,其格式为: -L[address]此命令装入已在CS:5CH中格式化了文件控制块所指定的文件。如未指定地址,则装入CS:0100开始的存储区中。10)写命令W(Write),有两种功能。 ·把数据写入磁盘的指定扇区。其格式为: -W address drive sector sector ·把数据写入指定的文件中。其格式为: -W[address]此命令把指定的存储区中的数据写入由CS:5CH处的文件控制块所指定的文件中。如未指定地址则数据从CS:0100开始。要写入文件的字节数应先放入BX和CX中。11)退出DEBUG命令Q(Quit),其格式为: -Q它退出DEBUG,返回DOS。本命令并无存盘功能,如需存盘应先使用W命令。 问 题 : 初 学 者 问 一 个 低 级 问 题 ,执 行 debug -a 后 ,如 果 有 一 行 输 入 错 误 ,如 何 更 改 这 一 行 ? 回答: 加 入 进 行 如 下 输 入 : D:\PWIN95\Desktop>debug -a 2129:0100 mov ax, 200 2129:0103 mov bx ,200 2129:0106 mov cx, 200 2129:0109 此 时 , 发 现 mov bx, 200一 句 错 误 , 应 为 mov bx, 20, 可 以 敲 回 车 返 回 “ -” 状 态 , 然 后 输 入 : -a 103 2129:0103 mov bx, 20 如 果 多 或 者 少 若 干 行 , 不 必 重 新 输 入 , 可 以 用 M命 令 移 动 后 面 的 程 序 来 去 掉 或 者 增 加 程 序 空 间 。 DEBUG.EXE指令说明DEBUG [执行文件名] [执行该文件的外带参数] a [sta] 编写汇编语言程序的指令,sta为启始地址 c sta end sta2 比较两个储存单元,sta为第一储存单元的启始地址,而end为第一储存单元结束地址,sta2为第二储存单元的启始地址 c sta lnn sta2 比较两储存单元,sta为第一储存单元启始地址,而nn为欲比较的长度大小,sta2为第二储存单元启始地址 d [sta] [end] 显示某指定范围储存单元至屏幕(sta:启始、end:结束) d [sta] [lnn] 显示某指范围块储存单元至屏幕(sta:启始、nn:长度) e [sta] 修改储存单元中某一个byte的资料,sta为地址 e [sta] [data] 修改储存单元中某一个byte的资料,data为新资料 g [end] 执行程序,直至结束地址(end)或程序结束时 g=sta [end] 执行从启始(sta)直至结束(end)或程序结束时 r [reg] 显示所有存储器內容或修改某指定存储器(reg)值 t [num] 单步执行,num指定一次执行几步(预设1) t=sta [num] 单步执行,从sta起始,num指定执行几步(预设1) n filename 为目前正在编辑或除错的文件命名 w [sta] 储存文件,写入cx个bytes的资料至n指定的文件名 w sta dri sec num 将sta资料写入dri磁盘的第sec磁区共写num个磁区 l [sta] 载入文件,读出n指定文件,档名的资料至sta地址中 l sta dri sec num 读出dri磁盘的第sec磁区的资料至sta共读num个磁区 q 离开debug,返回DOS u [sta] [end] 反汇编,从sta至end u [sta] [lnn] 反汇编,从sta,共反汇编nn个bytes m sta end sta2 将第一储存单元的数据搬至第二储存单元中 m sta lnn sta2 将第一储存单元的数据搬至第二储存单元中 f sta end data 将一段资料(data)存入某指定的储存单元区 f sta lnn data 将nn个bytes的资料存入某指定的储存单元区 s sta end data 搜寻data资料在指定地址內,data不限长度 s sta lnn data 搜寻data资料在指定地址內,data不限长度 h data data2 计算两个资料的和与差并显示在屏幕上 i inport 由输入埠输入并显示一个byte o outport 由输出埠输出一个byte值 下载更详细的debug使用指南(英文版)18k DEBUG的使用方法二原作者:[email protected] (John Gianni)译者:[email protected](marcal) 新闻组:comp.lang.asm.x86我有两个理由发表这些文章: 1)给别人带来帮助: 用去我的一点时间就可以使到很多的朋友节省时间。译者注:我翻译的水平不高。但翻译的目的是问了我们中国人也可以有多一点电脑高手,这样我们就可以早一点成为一个真正的强国。 2)同时我也将获得收益 一些关于FAT/directory/data-sector-lookup的知识我也需要帮助。译者注:我也一样希望高手指正我翻译有误的地方。以下就是正文了,你可以尝试一下(如果你发现问题,那么写信告诉我)如何除错和汇编你的第一个PC x86汇编语言程序呢? 以下这些简单的解释可以让一个汇编语言新手使用DEBUG: 0)在使用时,如何快速获得debug的使用帮助呢。1)让我们开始工作吧,例如:显示BIOS的日期。2)在你的电脑的COMMANG.COM文件里搜寻“IBM”这几个字符。3) 一位十六进制数的运算。4) 检查 x86寄存器内容。5)我们来编写我们的第一个用机械语言编写的程序-打印一个字符。6) 我们现在用汇编语言指令来做和例5一样的事情。7)现在,我们不但要编写一个汇编程序,而且我们还要把它存盘。8) 现在,我们试一试查看一个已经编好的程序。9)你可以用DEBUG的计算功能计算程序的长度。10)另一种显示在屏幕上字符串的方法。11)让我们试一试反复输出。12)我们现在把两个程序连接起来。13) 让我们逐步运行这个刚刚修补的程序。14)如果一开始的命令不是跳转命令,那么可能就要用这种方法了.。 --------------------------------------------------------------------------------以下所有的命令都是可以运行在WIN9x的MS-DOS方式下的。进入MS-DOS的方式有:[开始][程序][MS-DOS方式][开始][运行][打开]COMMAND[确定]或者你可以双击它:C:\Windows\Command.com --------------------------------------------------------------------------------0)在使用时,如何快速获得debug的使用帮助呢以下PROMPT>表示目录提示符:一般为:C:\WINDOWS\COMMANDPROMPT> DEBUG /?<按回车press the enter key now>怎样?出错了吧。显示如下C:\WINDOWS>DEBUG/?Runs Debug, a program testing and editing tool.DEBUG [[drive:][path]filename [testfile-parameters]][drive:][path]filename Specifies the file you want to test.testfile-parameters Specifies command-line information required bythe file you want to test.After Debug starts, type ? to display a list of debugging commands.因为错了所以它给你显示一些提示。留意到最后一句了吗?现在我们再来试一试:PROMPT> DEBUG<按回车> (注意, DEBUG程序的命令是在一条横线“-”后出现的。)-?<在出现的横线后面输入?再回车> (下面的内容是按字母顺序排列的)(注意:Note: Don't type the dash or comments -- just the ?)显示如下,但是没有中文的哦,中文是我加上去的。 汇编assemble A [address]比较compare C range address倾倒dump D [range]进入enter E address [list]填充fill F range list进行go G [=address] [addresses]十六进制hex H value1 value2输入input I port装载load L [address] [drive] [firstsector] [number]移动move M range address命名name N [pathname] [arglist]输出output O port byte进行proceed P [=address] [number]离开quit Q纪录register R [register]搜寻search S range list描述trace T [=address] [value]反汇编unassemble U [range]写write W [address] [drive] [firstsector] [number]分配扩展内存allocate expanded memory XA [#pages]释放扩展内存deallocate expanded memory XD [handle]map expanded memory pages XM [Lpage] [Ppage] [handle]display expanded memory status XS-q<按回车> (这是退出DEBUG回到DOS状态)This quits out of debug, returning to the DOS prompt)Tested examples below walk the user thru the following debug examples:在下面的例子里读者必须明白以下几条DEBUG命令。-D 显示一定范围内存的内容Display the contents of an area of memory-Q 退出DEBUG程序Quit the debug program-S 搜寻Search for whatever-H 十六进制的运算Hex arithmatic-R 显示或者改变一个或者多个寄存器的内容Display or change the contents of one or more registers-E 输入数据进入内存,在一个详细的地址里Enter data into memory, beginning at a specific location-G 运行现在在内存里的程序。Go run the executable program in memory-U 反汇编,把我们不认识的机械代码变为我们可以认识汇编语言符号Unassemble machine code into symbolic code-T 描述一条指令的用法。Trace the contents of one instruction-P 进行或者执行一个相关的指令Proceed, or execute a set of related instructions-A 编译,把汇编命令变为机械代码Assemble symbolic instructions into machine code-N 命名一个程序Name a program-W 把一个已经命名的程序写进磁盘Write the named program onto disk-L 把程序装载进内存Load the named program back into memory返回目录 -------------------------------------------------------------------------------- 1)让我们开始工作吧,例如:显示BIOS的日期(以下PROMPT>表示目录提示符:一般为:C:\WINDOWS\COMMAND\)PROMPT> DEBUG<按回车> -D FFFF:0006 L 8<按回车> (显示 FFFFh, 偏移地址 6h, 长度 8 bytes) 在作者的电脑上这里显示为 "1/10/96." 译者的电脑显示“ FFFF:0000 37 2F-30 36 2F 30 30 00 7/06/00.”相信作者的电脑里也是用这种格式显示的。这里显示出来的是使用者BIOS的日期,有兴趣的话可以重新开机看看,注意开机时的显示。-Q<按回车> (退出DEBUG) 思考:当只按DEBUG的时候,编辑的是什么?为什么可以找到BIOS的日期?(译者这里也不是很清楚所以请大家知道的也留言给斑竹,改正。译者认为可能是内存的真实物理地址。)返回目录 --------------------------------------------------------------------------------2)在你的电脑的COMMANG.COM文件里搜寻“IBM”这几个字符下面的“C:\Win95\”是根据每不电脑不同的。像译者的电脑里就是“C:\WINDOWS”PROMPT> DEBUG C:\Win95\Command.com<按回车>-S 0 L FFFF "IBM"<按回车>(从0开始搜寻"IBM",搜寻FFFFh多个单元格)-Q<按回车> (退出DEBUG) 以下是译者做的: C:\WINDOWS>DEBUG C:\WINDOWS\COMMAND.COM-S 0 L FFFF "IBM"-S 0 L FFFF "COMMAND"12A7:008D12A7:04F712A7:387012A7:38BE12A7:38DD-S 0 L FFFF "PATH"12A7:38AD12A7:CCB712A7:CF55-S 0 L FFFF "COMSPEC"12A7:38D412A7:3A4D12A7:CCC4-QC:\WINDOWS>(注意:搜寻是要区分大小写的)(你可以看到上面是没有找到“IBM”的, 可以试一试"PATH" , "COMSPEC" , "COMMAND")(注意: 这种方法用在查找加密资料和已被删除的资料等方面时是十分有用的)返回目录 --------------------------------------------------------------------------------3) 一位十六进制数的运算:PROMPT> DEBUG<按回车>-H 9 1<按回车> (加减两个十六进制的数, 9h+1h=Ah & 9h-1h=8h)结果是显示: 000A 0008-Q<按回车> (退出DEBUG) C:\WINDOWS>debug-h 9 1000A 0008-qC:\WINDOWS>返回目录 --------------------------------------------------------------------------------4) 检查x86寄存器内容PROMPT> DEBUG<按回车>-R<按回车> (显示x86寄存器内容)-Q<按回车> (退出DEBUG) C:\WINDOWS>debug-RAX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC127C:0100 043C ADD AL,3C-Q下面是对寄存器的简单介绍: 数据存储器在本类中,一般讲的AH就是AX的前八位,AL就是AX的后八位,后面的以此类推。AX Accumulator;作为累加器,所以它是算术运算的主要寄存器。另外所有的I/O指令都使用这一寄存器与外部设备传送信息。BX Base register;可以作为通用寄存器使用,此外在计算存储器地址时,它经常用作基地址寄存器。CX Counting register;可以作为通用寄存器使用,此外在循环(LOOP)和串处理指令中作隐含的计数器。DX Data register;可以作为通用寄存器使用,一般在作双字长运算时,把DX和AX组合在一起存放一个双字长数,DX用来存放高位字。此外,对某些I/O操作,DX可用来存放I/O的端口地址。 指针及变址寄存器BP Base pointers register ;机制指针寄存器SI Source index register ;堆栈指针寄存器DI Destiny index register ;目的变址寄存器SP Battery pointer register ;堆栈指针寄存器段寄存器CS Code segment register ;代码段寄存器,存放正在运行的程序指令DS Data segment register ;数据段寄存器,存放当前运行程序所用的数据SS Battery segment register ;堆栈段寄存器,定义了堆栈所在区域ES Extra segment register ;附加段寄存器,存放附加的数据,是一个辅助性的数据区,控制寄存器IP Next instruction pointer register;指令指针寄存器,它用来存放代码段中的偏移地址,在程序运行的过程中,它始终指向下一条指令的首地址,它与CS寄存器联用确定下一条指令的物理地址F Flag register;标志寄存器 “NV UP EI PL NZ NA PO NC”就是了,也有人称之为PSW Program Status Wold程序状态寄存器 (这里有一点必须讲明白的现在在,其实从奔腾开始这些寄存器(除了所有段寄存器,标志寄存器 )都是32位的。并且加多了两个16位段寄存器FS,GS。dos下面看到这些寄存器是16位的。要看32位寄存器可以使用soft-ice。对于FS,GS的作用我也不是很清楚,希望有高手指点,谢谢。) 返回目录 --------------------------------------------------------------------------------5)我们来编写我们的第一个用机械语言编写的程序-打印一个字符(这里用机械语言的主要原因是考虑到有一些用户不懂汇编命令,现在就要让他有一个认识计算机程序实质是一些数字) PROMPT> DEBUG<按回车>-E 100<按回车> (在偏移地址为100的地方输入机械指令程序)B4<按空格>02<按空格> (在AX寄存器的前八位存入02)B2<按空格>41<按空格> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对着表改改数字试一试)CD<按空格>21<按空格> (当AH=02时这是DOS显示输出的中断号)CD<按空格>20<按回车> (退出DOS)-G<按回车> (程序运行,并在屏幕上显示出“A”)程序运行完以后你将看到"Program terminated normally"(程序正常结束了).-U 100<按回车> (我们把它反汇编,就是把机械命令变为汇编语言指令) 107F:0100 B402 MOV AH,02 :0102 B2 MOV DL,41 :0104 CD21 INT 21 :0106 CD20 INT 20 (下面会有一堆无用的东西)(对了,你的段地址可能与我的段地址CS=107F不同哦)-R<按回车> (让我们来看看寄存器的值; IP==100h, AX==0000h, DX==0000h) 好极了,我们看到电脑又做好了准备下一次运行程序了。-T<按回车> (执行第一步操作... IP=>102h, AX=>0200h,指令指针寄存器指向下一条命令,AX的值被改变。-T<按回车> (执行第二步操作... IP=>104h, , DX=>0041h,指令指针寄存器指向下一条命令,DX的值被改变。-P<按回车> (继续执行 INT 21,IP=>106h, AX=>02h,)-P<按回车> (继续执行INT 20)-Q<按回车> (退出DEBUG)(注意:你必须小心使用"T".因为如果你在程序完结以后继续执行这条命令,因为我们无法预知下面的指令是什么,所以我们也无法预知它可能带来的后果)C:\WINDOWS>DEBUG-E 100127C:0100 B4.B4 02.02 B2.B2 41.41 CD.CD 21.21 CD.CD 20.20-GAProgram terminated normally-U 100127C:0100 B402 MOV AH,02127C:0102 B241 MOV DL,41127C:0104 CD21 INT 21127C:0106 CD20 INT 20127C:0108 C706F1E30900 MOV WORD PTR [E3F1],0009127C:010E EB59 JMP 0169127C:0110 57 PUSH DI127C:0111 BFF1E3 MOV DI,E3F1127C:0114 8BDF MOV BX,DI127C:0116 06 PUSH ES127C:0117 0E PUSH CS127C:0118 07 POP ES127C:0119 32D2 XOR DL,DL127C:011B EB34 JMP 0151127C:011D 006B12 ADD [BP+DI+12],CH-RAX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC127C:0100 B402 MOV AH,02-TAX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000DS=127C ES=127C SS=127C CS=127C IP=0102 NV UP EI PL NZ NA PO NC127C:0102 B241 MOV DL,41-TAX=0200 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000DS=127C ES=127C SS=127C CS=127C IP=0104 NV UP EI PL NZ NA PO NC127C:0104 CD21 INT 21-PAAX=0241 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000DS=127C ES=127C SS=127C CS=127C IP=0106 NV UP EI PL NZ NA PO NC127C:0106 CD20 INT 20-PProgram terminated normally-QC:\WINDOWS> 返回目录 --------------------------------------------------------------------------------6) 我们现在用汇编语言指令来做和例5一样的事情 PROMPT> DEBUG<按回车>-A 100<按回车> (在偏移地址为100的地方输入汇编语言程序) MOV AH,02<按回车> (选用DOS的02号功能调用,显示输出) MOV DL,<按回车> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对着表改改数字试一试) INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"A") INT 20<按回车> (退出DOS)<按回车> (结束汇编语言编程状态,回到DEBUG命令状态)-G =100<按回车> (运行程序,其实可以不要“=100”因为一般默认启始位置是100)-Q<按回车> (退出DEBUG) C:\WINDOWS>DEBUG-A 100127C:0100 MOV AH,02127C:0102 MOV DL,41127C:0104 INT 21127C:0106 INT 20127C:0108-GAProgram terminated normally-Q返回目录--------------------------------------------------------------------------------7) 现在,我们不但要编写一个汇编程序,而且我们还要把它存盘 (下面这个程序就要比原来的程序复杂一点了-显示输出:"ABC") PROMPT> DEBUG<按回车>(运行DEBUG程序;系统默认启始IP寄存器值为100h)-A 100<按回车> (用汇编语言编写一个程序,启始地址是100h) MOV AH,02<按回车> (选择DOS的02号功能调用, 显示输出) MOV DL,<按回车> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码)INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"A") MOV DL,42<按回车> (在DX寄存器的后八位存入41h,41h就是大写B的ASCII码) INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"B") MOV DL,43<按回车> (在DX寄存器的后八位存入41h,41h就是大写C的ASCII码) INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"C") INT 20<按回车> (程序结束,退出DEBUG)<按回车> (结束汇编命令输入,回到DEBUG命令输入)-R BX<按回车> (查看寄存器BX的值):0000<按回车> (设置BX为0000h,这是程序的结尾地址是BX:CX) (注意,只要BX = 0000, 文件的大小就小于 < 64 Kb.)-R CX<按回车> (设置CX为Fh,这是程序的长度:16位):0010<按回车> (现在我们可以把这个16字节的程序写入硬盘了)-N printabc.com<按回车> (将要存盘的程序命名)-W<按回车> (把这十六字节写到文件里面)-Q<按回车> (退出DEBUG)PROMPT> DIR printabc.com<按回车> 这里将会报告这个文件的大小是16字节 (10h 字节).PROMPT> printabc.com<按回车> 会马上在屏幕上打印出"ABC"C:\WINDOWS>DEBUG-A 100127C:0100 MOV AH,02127C:0102 MOV DL,41127C:0104 INT 21127C:0106 MOV DL,42127C:0108 INT 21127C:010A MOV DL,43127C:010C INT 21127C:010E INT 20127C:0110-RAX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC127C:0100 B402 MOV AH,02-R BXBX 0000:-R CXCX 0000:0010-N PRINTABC.COM-WWriting 00010 bytes-QC:\WINDOWS>DIR PRINTABC.COMVolume in drive C has no label Volume Serial Number is 28FB-70BA Directory of C:\WINDOWSPRINTABC COM 16 03-21-01 11:02 PRINTABC.COM 1 file(s) 16 bytes 0 dir(s) 557,711,360 bytes freeC:\WINDOWS>PRINTABCABCC:\WINDOWS> 这里可以有人告诉我,为什么要存入是BX:CX代表程序长度吗?(写信给译者,谢谢)返回目录--------------------------------------------------------------------------------8) 现在,我们试一试查看一个已经编好的程序: PROMPT> DEBUG<按回车>(运行DEBUG程序在CS:IP = CS:0100h)-N printabc.com<按回车> (告诉电脑你想装载的程序名)-L<按回车> (装载那个名字的程序进入内存)-U 100 L 10<按回车> (从偏移地址100开始反汇编16位字节)-R<按回车> (现在看看寄存器里面的内容) 注意:DEBUG本身是没有自动纪录文件大小的。-G (运行被命名的程序,打印"ABC") 你将看到"ABC",然后是"Program terminated normally")C:\WINDOWS>DEBUG-N PRINTABC.COM-L-U 100 L 1012A4:0100 B402 MOV AH,0212A4:0102 B241 MOV DL,4112A4:0104 CD21 INT 2112A4:0106 B242 MOV DL,4212A4:0108 CD21 INT 2112A4:010A B243 MOV DL,4312A4:010C CD21 INT 2112A4:010E CD20 INT 20-RAX=0000 BX=0000 CX=0010 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000DS=12A4 ES=12A4 SS=12A4 CS=12A4 IP=0100 NV UP EI PL NZ NA PO NC12A4:0100 B402 MOV AH,02-GABCProgram terminated normally返回目录--------------------------------------------------------------------------------9)你可以用DEBUG的计算功能计算程序的长度。 一开始的时候你的程序初始地址是在0100h: 107F:0100 MOV AH,02 <--这就是 100h你的程序的最后一行在010Eh: 107F:010E INT 20 <--最后一行然后,最后一条命令的下一行的地址是0110h: 107F:0110 <--这就是110h所以,从0110h里减去100h我们得到得长度是10h 字节. PROMPT> DEBUG<按回车>-H 110 100<按回车> (这条命令将运算110h+100h和110h-100h)0210 0010<按回车> (汇报 110h-100h=0010h; 16-byte 程序长度16位)-Q<按回车> (退出DEBUG) C:\WINDOWS>debug-H 110 1000210 0010-Q返回目录-------------------------------------------------------------------------------- 10)另一种显示在屏幕上字符串的方法注意:在你输入数据的时候,按"-"键将会可以让你回退一格。 PROMPT> DEBUG<按回车>-E 200<按回车> (从偏移地址200开始。输入"Hello,World")48<按空格>65<按空格> (输入48h (H)和65h (e))6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))57<按空格>6F<按空格> (输入57h (W)和6Fh (o))72<按空格>6C<按空格> (输入72h (r)和6Ch (l))64<按空格>24<按空格> (输入64h (d)和24h ($))<按回车> ("Hello,World" 已经输入完毕)-D 200<按回车> (显示你刚刚输入的内容: 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ... HELLO,WORLD$...)-A 100<按回车> (用汇编语言写一个新程序在IP-100h处开始) MOV AH,09<按回车> (选择DOS的09号功能调用,显示字符串) MOV DX,0200<按回车> (把输出地址(200h),放进寄存器) INT 21<按回车> (执行DOS功能调用,显示"Hello,World") INT 20<按回车> (退出程序回到DOS状态)<按回车> (结束汇编语言输入,回到DEBUG输入状态)-G<按回车> (从 CS:IP开始运行程序, 就是从107F:0100h开始执行程序) 现在,我们可以把这个程序保存进一硬盘-D 100<按回车> (纪录:程序的起始点在100h)-D 200<按回车> (纪录:程序数据单元的结束点是在020Bh)-H 20B 100<按回车> (运算 20Bh-100h=10Bh;程序长度267字节)-R BX<按回车> (检查BX寄存器的值):0000<按回车> (设置BX为0000h,程序的长度是BX:CX,实际上你可以把和CX写到一起,即实际长度为:0000010Bh,这样些的目的是使你可以计算更大的程序的长度)-R CX<按回车> (设置CX 为010Bh, 这就是这个程序的长度了):010B<按回车> (现在你可以把这个108字节的程序写入硬盘了)-N printhw.com<按回车> (将要写入硬盘的程序命名)-W<按回车> (把这10Bh 即267个字节写入文件)-Q<按回车> (退出DEBUG)PROMPT> DIR printhw.com<按回车> 将会汇报程序的长度是267字节(10Bh字节).PROMPT> printhw.com<按回车> 运行这个程序,这将会在屏幕上显示出"Hello,World" : C:\WINDOWS>DEBUG-E 200127C:0200 2C.48 D5.65 BA.6C FF.6C FF.6F B8.2C 00.57 AE.6F127C:0208 CD.72 2F.6C 3C.64 00.24 C3.-D 200127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... .127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7..127C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6.........127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y.........-A 100127C:0100 MOV AH,09127C:0102 MOV DX,0200127C:0105 INT 21127C:0107 INT 20127C:0109-GHello,WorldProgram terminated normally-D200127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... .127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7..27C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6.........127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y.........-H 20B 100030B 010B-R BXBX 0000:-R CXCX 0000:010B-N PRINTHW.COM-WWriting 0010B bytes-QC:\WINDOWS>DIR PRINTHW.COM Volume in drive C has no labelVolume Serial Number is 28FB-70BA Directory of C:\WINDOWSPRINTHW COM 267 03-22-01 11:53 PRINTHW.COM 1 file(s) 267 bytes 0 dir(s) 555,089,920 bytes free返回目录--------------------------------------------------------------------------------11)让我们试一试反复输出:PROMPT> DEBUG<按回车>-A 100<按回车> (用汇编语言写一个新的程序,起始地址是100h) JMP 125<按回车> (从102h接跳到125h) <按回车> (结束输入汇编命令。译者注:这里是为了例12做准备)-E 102 'Hello World' 0d 0a '$'<按回车> (把字符串输入内存)-A 125<按回车> (从125h开始继续编写我们的汇编语言程序) MOV DX,0102<按回车> (把字符串的首地址(102h)放入DX寄存器) MOV CX,0005<按回车> (指定这条指令将被显示5次) MOV AH,09<按回车> (选择DOS的09号功能调用, 显示字符串) INT 21<按回车> (执行DOS的功能调用, 显示"Hello, World") DEC CX<按回车> (每次运行到这里CX都减去1)JCXZ 0134<按回车> (如果计数器CX=0,那么跳到地址0134h) JMP 012D<按回车> (其他情况下,即CX≠O时跳到012Dh) INT 20<按回车> (程序退出DOS状态)<按回车> (结束汇编语言程序输入,回到DEBUG)-U 100<按回车> (从地址100h 开始反汇编)-U<按回车> (继续执行反汇编指令,直至你看到INT 20)-H 0136 100<按回车> (运算程序长度为36h)-U 100 L 36<按回车> ( 从100h反汇编到136h ,来确认你的计算)-R BX<按回车> (查看寄存器BX的值):0000<按回车> (设置BX为0000h)-R CX<按回车> (把CX 设置为36h, 这就是程序长度36字节):0036<按回车> (现在你可以把这36字节写入文件了)-N printhw5.com<按回车>(命名我,我们要写入的文件名)-W<按回车> (把这36字节的内容写进新文件)-G<按回车> (运行程序,在屏幕上显示”Hello-World “)-Q<按回车> (退出DEBUG)PROMPT> DIR printhw5.com<按回车> 将会汇报文件大小为54字节,换算为十六进制就是36h字节PROMPT> printhw5.com<按回车> 将在屏幕上显示五次"Hello World"返回目录--------------------------------------------------------------------------------12)我们现在把两个程序连接起来。 我们现在把printhw.com做为修补程序 写进printhw5.com, 新版本的printhw5 将先执行原来的printhw.com再执行原来的printhw5.comPROMPT> COPY printhw5.com printhw5.bak<按回车> 首先,备份printhw5.com,以后可以用于比较PROMPT> DIR printhw5.com<按回车> 现在,查看到得仍然是以前的54字节(36h 字节)PROMPT> DEBUG printhw5.com<按回车>-R<按回车> (现在查看仍然是BX:CX=0000 0036h bytes)-U 100<按回车> (查看到最后的是 EB 23 (JMP 0125))-H 100 36<按回车> (最后的指令是在 100h+36h=136h)-H 136 1<按回车> (下一个可用的存储器位置是136h+1h=137h) 现在你拥有足够的资料,去修补那个程序-E 110<按回车> (把"Hello,World"输入内存)48<按空格>65<按空格> (输入48h (H)和65h (e))6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))57<按空格>6F<按空格> (输入57h (W)和6Fh (o))72<按空格>6C<按空格> (输入72h (r)和6Ch (l))64<按空格>24<按空格> (输入64h (d)和24h ($))<按回车> (停止输入"Hello,World")-D 110<按回车> (显示更才输入内存的数据: 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ...HELLO,WORLD$...)-A 100<按回车> (在IP地址的(100h)开始夺取原来的程序的控制权,原来这里是”JMP 125”) JMP 137<按回车> (代替原来运行的程序首先运行我们现在的修补程序)<按回车> (结束汇编命令输入,回到DEBUG命令输入)-A 137<按回车> (在下面的可用通奸编译这个修补程序) MOV AH,09<按回车> (选择DOS的09号功能调用,显示输出) MOV DX,110<按回车> (把我们要输出的字段的首地址(110h)给DX寄存器) INT 21<按回车> (执行DOS 的功能调用,显示"Hello,World") JMP 0125<按回车> (这里用跳转到原程序来代替退出到DOS命令(INT 20))<按回车> (结束汇编命令输入,回到DEBUG命令输入) -U 125<按回车> (确认一下源程序没有被我们误改了,如果无改了就马上退出DEBUG重新来过)-U 100 L 1<按回车> (确认已经使程序跳转到我们的修补程序地址137h)-D 110 L C<按回车> (确认数据区已经有了我们想要的数据)-U 137<按回车> (确认我们的新程序已经输入了) 现在我们可以把这个小程序存入硬盘了: (注意:在现在整个程序的最后一条命令"JMP 0125" 的后面一条的地址是0140h)-H 0140h 100<按回车> (计算140h-100h=40h; 答案是我们现在有一个长度为64字节的小程序)-RBX<按回车> (检查BX寄存器的值是否为”0”):<按回车> (如果BX是0000h那么就不需要改动啦)-RCX<按回车> (要把CX改为40h。这是我们的程序的长度):40<按回车> (现在你可以把这0000:0040h个字节的小程序放入硬盘啦)-W<按回车> (覆盖我们的原程序)-G<按回车> (尝试运行我们的新程序)-Q<按回车> (退出DEBUG回到DOS) PROMPT> DIR printhw5.com<按回车> 现在你再看就发现文章大小不再是54字节, 变成了64字节.PROMPT> printhw5.com<按回车> 现在是首先在屏幕上打印 "Hello,World"一次,然后再打印"Hello,World" 5 次(译者注:这里其实可以在编程的时候换一换内容试一试.返回目录--------------------------------------------------------------------------------13) 让我们逐步运行这个刚刚修补的程序:PROMPT> DEBUG printhw5.com<按回车>-R<按回车> (第1步:地址0100h内容是 EB35 "JMP 0137")-T<按回车> (第2步:地址0137h内容是B409 "MOV AH,09")-T<按回车> (第3步:地址0139h内容是BA1001 "MOV DX,0110")-T<按回车> (第4步:地址0139h内容是CD21 "INT 21")-P<按回车> (运行第5:"Hello,World"地址013Eh内容是EBE5 "JMP 0125")-T<按回车> (到这里控制权已经回到了原程序) 如果你想的话,你可以一步一步的执行完全部程序;方法就是一直按”T”,直至到达下一个功能调用运行完成后。到那时按一个"P"就可以继续按"T".返回目录--------------------------------------------------------------------------------14)如果一开始的命令不是跳转命令,那么可能就要用这种方法了:例如:如果我们想叫程序printhw 先打印”ABC”,就要获取控制权了。然后打印”ABC”的程序把控制权给回原来的printhw. 在这个事例里 ,printhw在100h的地址有两字节的程序;不能象上面那样简单的替代(一个JMP代替另一个JMP)就完事。解决办法就是使用NOP命令。PROMPT> DIR printhw.com<按回车> 将汇报程序的长度为267字节(10Bh 字节).PROMPT> DEBUG printhw.com<按回车>-R<按回车> (IP=100h 并且printhw's 的文件大小=BX:CX=0000:010Bh)-U 100<按回车> (第一条指令B4 09 (MOV AH,09)是两个字节的) (第二条命令是三个字节的 BA 00 02 (MOV DX,0200))-H 100 10B<按回车> (最后一条printhw的指令是在100h+10Bh=20Bh) (DOS的INT 21功能调用是在105h开始的) 现在你有足够的资料输入你的程序了!-A 100<按回车> (要在printhw 的IP开始位置就夺取程序的控制权) JMP 20B<按回车> (跳到20Bh增加一个程序) NOP<按回车> (用空指令填充直至你去到下一条完整的指令)NOP<按回车> (你可以用它来覆盖你不想只执行的原程序命令 ,而不改变原来的地址。但是在这里我们只需要两个NOP) 译者注:为了使大家更加明白所以我将各条命令对应的机械命令的长度写在下面 B409 MOV AH,09 BA0002 MOV DX,0200 E90301 JMP 020B 90 NOP 这样我们就很清楚的看到JMP 020B的长度比MOV AH,09多了1个字节,但是MOV DX,0200有是3个字节,而NOP是空指令,是不执行任何操作的,它只是占1个字节。所以我们现在把前两条指令用一个JMP 020B和两个NOP代替。后面再加上去。<按回车> (结束汇编命令回到DEBUG命令输入)-U 100<按回车> (看一看前面我们做了些什么) (注意DOS INT 21中断任然是在 IP=105h的地方开始)-A 20B<按回车> (现在把我们的原程序写在后面) MOV AH,02<按回车> (选择DOS 的 2号功能调用, 字符显示输出) MOV DL,41<按回车> (在DL寄存器存入”A”的ASCII码41h) INT 21<按回车> (执行DOS 的功能调用,显示字符"A") MOV DL,42<按回车> (在DL寄存器存入”B”的ASCII码42h) INT 21<按回车> (执行DOS 的功能调用,显示字符"B") MOV DL,43<按回车> (在DL寄存器存入”C”的ASCII码43h) INT 21<按回车> (执行DOS 的功能调用,显示字符"C") MOV AH,09<按回车> (现在重新输入原来在100h的程序指令) MOV DX,0200<按回车> (现在要打扫寄存器了,还原原来的200h的值) JMP 105<按回车> (跳到INT 21指令的位置105h)<按回车> (请注意一下你这里最后的地址是0221h)-H 221 100<按回车> (计算221h-100h=121h 就是289字节的程序)-R CX<按回车> (把CX的值设为121h, 这就设定了程序的新长度):0121<按回车> (现在用121h (也就是289字节)覆盖原值)-W<按回车> (把这289个字节写回原程序)-Q<按回车> (退出DEBUG) PROMPT> DIR printhw.com<按回车> 现在在看就会是新程序的长度289字节而不是,267字节)现在在屏幕上先出现"ABC"再出现"Hello,World"返回目录 关于在VC2008加载菜单,以下代码 F7正常,F5崩溃 关于多人视频会议系统 怎么设定父窗口 改变框架类的View 新学习MFC,免费接各种小型程序制作。顶者有分。 关于myicq的问题,紧急求救! codeproject问题! 请教高手!!!debug版本好使而release版本就不好使? 几个巨菜的问题!得分的好机会! 如何知道一个字符串代表的路径是否存在? 怎么修改动态的,在程序里面修改菜单项的名字, MCSD和MCSE先学哪一个比较好??
一、DEBUG程序的调用
在DOS的提示符下,可键入命令:
C:\DEBUG [D:][PATH][FILENAME[.EXT]][PARM1][PARM2]
其中,文件名是被调试文件的名字。如用户键入文件,则DEBUG将指定的文件装入存储器中,用户可对其进行调试。如果未键入文件名,则用户可以用当前存储器的内容工作,或者用DEBUG命令N和L把需要的文件装入存储器后再进行调试。命令中的D指定驱动器PATH为路径,PARM1和PARM2则为运行被调试文件时所需要的命令参数。
在DEBUG程序调入后,将出现提示符,此时就可用DEBUG命令来调试程序。
二、DEBUG的主要命令
1、显示存储单元的命令D(DUMP),格式为:
_D[address]或_D[range]
例如,按指定范围显示存储单元内容的方法为:
-d100 120
18E4:0100 c7 06 04 02 38 01 c7 06-06 02 00 02 c7 06 08 02 G...8.G.....G...
18E$:0110 02 02 bb 04 02 e8 02 00-CD 20 50 51 56 57 8B 37 ..;..h..M PQVW.
7
18E4:0120 8B
其中0100至0120是DEBUG显示的单元内容,左边用十六进制表示每个字节,右边用ASCII字符表示每个字节,·表示不可显示的字符。这里没有指定段地址,D命令自动显示DS段的内容。如果只指定首地址,则显示从首地址开始的80个字节的内容。如果完全没有指定地址,则显示上一个D命令显示的最后一个单元后的内容。
2、修改存储单元内容的命令有两种。
·输入命令E(ENTER),有两种格式如下:第一种格式可以用给定的内容表来替代指定范围的存储单元内容。命令格式为:
-E address [list]
例如,-E DS:100 F3'XYZ'8D
其中F3,'X','Y','Z'和各占一个字节,该命令可以用这五个字节来替代存储单元DS:0100到0104的原先的内容。
第二种格式则是采用逐个单元相继修改的方法。命令格式为:
-E address
例如,-E DS:100
则可能显示为:
18E4:0100 89.-
如果需要把该单元的内容修改为78,则用户可以直接键入78,再按“空格”键可接着显示下一个单元的内容,如下:
18E4:0100 89.78 1B.-
这样,用户可以不断修改相继单元的内容,直到用ENTER键结束该命令为止。
·填写命令F(FILL),其格式为:
-F range list
例如:-F 4BA:0100 5 F3'XYZ'8D
使04BA:0100~0104单元包含指定的五个字节的内容。如果list中的字节数超过指定的范围,则忽略超过的项;如果list的字节数小于指定的范围,则重复使用list填入,直到填满指定的所有单元为止。
3)检查和修改寄存器内容的命令R(register),它有三种格式如下:
·显示CPU内所有寄存器内容和标志位状态,其格式为:
-R
例如,-r
AX=0000 BX=0000 CX=010A DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=18E4 ES=18E4 SS=18E4 CS=18E4 IP=0100 NV UP DI PL NZ NA PO NC
18E4:0100 C70604023801 MOV WORD PTR [0204],0138 DS:0204=0000
·显示和修改某个寄存器内容,其格式为:
-R register name
例如,键入
-R AX
系统将响应如下:
AX F1F4
:
即AX寄存器的当前内容为F1F4,如不修改则按ENTER键,否则,可键入欲修改的内容,如:
-R bx
BX 0369
:059F
则把BX寄存器的内容修改为059F。
·显示和修改标志位状态,命令格式为:
-RF系统将响应,如:
OV DN EI NG ZR AC PE CY-
此时,如不修改其内容可按ENTER键,否则,可键入欲修改的内容,如:
OV DN EI NG ZR AC PE CY-PONZDINV
即可,可见键入的顺序可以是任意的。
4)运行命令G,其格式为:
-G[=address1][address2[address3…]]
其中,地址1指定了运行的起始地址,如不指定则从当前的CS:IP开始运行。后面的地址均为断点地址,当指令执行到断点时,就停止执行并显示当前所有寄存器及标志位的内容,和下一条将要执行的指令。
5)跟踪命令T(Trace),有两种格式:
·逐条指令跟踪
-T [=address]
从指定地址起执行一条指令后停下来,显示所有寄存器内容及标志位的值。如未指定地址则从当前的CS:IP开始执行。
·多条指令跟踪
-T [=address][value]
从指定地址起执行n条指令后停下来,n由value指定。
6)汇编命令A(Assemble),其格式为:
-A[address]
该命令允许键入汇编语言语句,并能把它们汇编成机器代码,相继地存放在从指定地址开始的存储区中。必须注意:DEBUG把键入的数字均看成十六进制数,所以如要键入十进制数,则其后应加以说明,如100D。
7)反汇编命令U(Unassemble)有两种格式。
·从指定地址开始,反汇编32个字节,其格式为:
-U[address]
例如:
-u100
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
18E4:0112 BBO4O2 MOV BX,0204
18E4:0115 E80200 CALL 011A
18E4:0118 CD20 INT 20
18E4:011A 50 PUSH AX
18E4:011B 51 PUSH CX
18E4:011C 56 PUSH SI
18E4:011D 57 PUSH DI
18E4:011E 8B37 MOV SI,[BX]
如果地址被省略,则从上一个U命令的最后一条指令的下一个单元开始显示32个字节。
·对指定范围内的存储单元进行反汇编,格式为:
-U[range]
例如:
-u100 10c
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
或
-u100 112
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
可见这两种格式是等效的。
8)命名命令N(Name),其格式为:
-N filespecs [filespecs]
命令把两个文件标识符格式化在CS:5CH和CS:6CH的两个文件控制块中,以便在其后用L或W命令把文件装入存盘。filespecs的格式可以是:
[d:][path] filename[.ext]
例如,
-N myprog
-L
-
可把文件myprog装入存储器。
9)装入命令(Load),有两种功能。
·把磁盘上指定扇区范围的内容装入到存储器从指定地址开始的区域中。其格式为:
-L[address[drive sector sector]
·装入指定文件,其格式为:
-L[address]
此命令装入已在CS:5CH中格式化了文件控制块所指定的文件。如未指定地址,则装入CS:0100开始的存储区中。
10)写命令W(Write),有两种功能。
·把数据写入磁盘的指定扇区。其格式为:
-W address drive sector sector
·把数据写入指定的文件中。其格式为:
-W[address]
此命令把指定的存储区中的数据写入由CS:5CH处的文件控制块所指定的文件中。如未指定地址则数据从CS:0100开始。要写入文件的字节数应先放入BX和CX中。
11)退出DEBUG命令Q(Quit),其格式为:
-Q
它退出DEBUG,返回DOS。本命令并无存盘功能,如需存盘应先使用W命令。 问 题 : 初 学 者 问 一 个 低 级 问 题 ,执 行 debug -a 后 ,如 果 有 一 行 输 入 错 误 ,如 何 更 改 这 一 行 ? 回答:
加 入 进 行 如 下 输 入 :
D:\PWIN95\Desktop>debug
-a
2129:0100 mov ax, 200
2129:0103 mov bx ,200
2129:0106 mov cx, 200
2129:0109
此 时 , 发 现 mov bx, 200一 句 错 误 , 应 为 mov bx, 20, 可 以 敲 回 车 返 回 “ -” 状 态 , 然 后 输 入 :
-a 103
2129:0103 mov bx, 20
如 果 多 或 者 少 若 干 行 , 不 必 重 新 输 入 , 可 以 用 M命 令 移 动 后 面 的 程 序 来 去 掉 或 者 增 加 程 序 空 间 。
DEBUG.EXE指令说明DEBUG [执行文件名] [执行该文件的外带参数]
a [sta] 编写汇编语言程序的指令,sta为启始地址
c sta end sta2 比较两个储存单元,sta为第一储存单元的启始地址,而end为第一储存单元结束地址,sta2为第二储存单元的启始地址
c sta lnn sta2 比较两储存单元,sta为第一储存单元启始地址,而nn为欲比较的长度大小,sta2为第二储存单元启始地址
d [sta] [end] 显示某指定范围储存单元至屏幕(sta:启始、end:结束)
d [sta] [lnn] 显示某指范围块储存单元至屏幕(sta:启始、nn:长度)
e [sta] 修改储存单元中某一个byte的资料,sta为地址
e [sta] [data] 修改储存单元中某一个byte的资料,data为新资料
g [end] 执行程序,直至结束地址(end)或程序结束时
g=sta [end] 执行从启始(sta)直至结束(end)或程序结束时
r [reg] 显示所有存储器內容或修改某指定存储器(reg)值
t [num] 单步执行,num指定一次执行几步(预设1)
t=sta [num] 单步执行,从sta起始,num指定执行几步(预设1)
n filename 为目前正在编辑或除错的文件命名
w [sta] 储存文件,写入cx个bytes的资料至n指定的文件名
w sta dri sec num 将sta资料写入dri磁盘的第sec磁区共写num个磁区
l [sta] 载入文件,读出n指定文件,档名的资料至sta地址中
l sta dri sec num 读出dri磁盘的第sec磁区的资料至sta共读num个磁区
q 离开debug,返回DOS
u [sta] [end] 反汇编,从sta至end
u [sta] [lnn] 反汇编,从sta,共反汇编nn个bytes
m sta end sta2 将第一储存单元的数据搬至第二储存单元中
m sta lnn sta2 将第一储存单元的数据搬至第二储存单元中
f sta end data 将一段资料(data)存入某指定的储存单元区
f sta lnn data 将nn个bytes的资料存入某指定的储存单元区
s sta end data 搜寻data资料在指定地址內,data不限长度
s sta lnn data 搜寻data资料在指定地址內,data不限长度
h data data2 计算两个资料的和与差并显示在屏幕上
i inport 由输入埠输入并显示一个byte
o outport 由输出埠输出一个byte值 下载更详细的debug使用指南(英文版)18k
DEBUG的使用方法二原作者:[email protected] (John Gianni)
译者:[email protected](marcal)
新闻组:comp.lang.asm.x86
我有两个理由发表这些文章:
1)给别人带来帮助:
用去我的一点时间就可以使到很多的朋友节省时间。译者注:我翻译的水平不高。但翻译的目的是问了我们中国人也可以有多一点电脑高手,这样我们就可以早一点成为一个真正的强国。
2)同时我也将获得收益
一些关于FAT/directory/data-sector-lookup的知识我也需要帮助。译者注:我也一样希望高手指正我翻译有误的地方。以下就是正文了,你可以尝试一下(如果你发现问题,那么写信告诉我)如何除错和汇编你的第一个PC x86汇编语言程序呢? 以下这些简单的解释可以让一个汇编语言新手使用DEBUG:
0)在使用时,如何快速获得debug的使用帮助呢。
1)让我们开始工作吧,例如:显示BIOS的日期。
2)在你的电脑的COMMANG.COM文件里搜寻“IBM”这几个字符。
3) 一位十六进制数的运算。
4) 检查 x86寄存器内容。
5)我们来编写我们的第一个用机械语言编写的程序-打印一个字符。
6) 我们现在用汇编语言指令来做和例5一样的事情。
7)现在,我们不但要编写一个汇编程序,而且我们还要把它存盘。
8) 现在,我们试一试查看一个已经编好的程序。
9)你可以用DEBUG的计算功能计算程序的长度。
10)另一种显示在屏幕上字符串的方法。
11)让我们试一试反复输出。
12)我们现在把两个程序连接起来。
13) 让我们逐步运行这个刚刚修补的程序。
14)如果一开始的命令不是跳转命令,那么可能就要用这种方法了.。
--------------------------------------------------------------------------------
以下所有的命令都是可以运行在WIN9x的MS-DOS方式下的。
进入MS-DOS的方式有:
[开始][程序][MS-DOS方式][开始][运行][打开]COMMAND[确定]或者你可以双击它:
C:\Windows\Command.com
--------------------------------------------------------------------------------0)在使用时,如何快速获得debug的使用帮助呢
以下PROMPT>表示目录提示符:一般为:C:\WINDOWS\COMMANDPROMPT> DEBUG /?<按回车press the enter key now>
怎样?出错了吧。显示如下
C:\WINDOWS>DEBUG/?
Runs Debug, a program testing and editing tool.DEBUG [[drive:][path]filename [testfile-parameters]][drive:][path]filename Specifies the file you want to test.
testfile-parameters Specifies command-line information required by
the file you want to test.After Debug starts, type ? to display a list of debugging commands.
因为错了所以它给你显示一些提示。留意到最后一句了吗?
现在我们再来试一试:
PROMPT> DEBUG<按回车> (注意, DEBUG程序的命令是在一条横线“-”后出现的。)
-?<在出现的横线后面输入?再回车> (下面的内容是按字母顺序排列的)
(注意:Note: Don't type the dash or comments -- just the ?)
显示如下,但是没有中文的哦,中文是我加上去的。
汇编assemble A [address]
比较compare C range address
倾倒dump D [range]
进入enter E address [list]
填充fill F range list
进行go G [=address] [addresses]
十六进制hex H value1 value2
输入input I port
装载load L [address] [drive] [firstsector] [number]
移动move M range address
命名name N [pathname] [arglist]
输出output O port byte
进行proceed P [=address] [number]
离开quit Q
纪录register R [register]
搜寻search S range list
描述trace T [=address] [value]
反汇编unassemble U [range]
写write W [address] [drive] [firstsector] [number]
分配扩展内存allocate expanded memory XA [#pages]
释放扩展内存deallocate expanded memory XD [handle]
map expanded memory pages XM [Lpage] [Ppage] [handle]
display expanded memory status XS
-q<按回车> (这是退出DEBUG回到DOS状态)This quits out of debug, returning to the DOS prompt)Tested examples below walk the user thru the following debug examples:
在下面的例子里读者必须明白以下几条DEBUG命令。
-D 显示一定范围内存的内容Display the contents of an area of memory
-Q 退出DEBUG程序Quit the debug program
-S 搜寻Search for whatever
-H 十六进制的运算Hex arithmatic
-R 显示或者改变一个或者多个寄存器的内容Display or change the contents of one or more registers
-E 输入数据进入内存,在一个详细的地址里Enter data into memory, beginning at a specific location
-G 运行现在在内存里的程序。Go run the executable program in memory
-U 反汇编,把我们不认识的机械代码变为我们可以认识汇编语言符号Unassemble machine code into symbolic code
-T 描述一条指令的用法。Trace the contents of one instruction
-P 进行或者执行一个相关的指令Proceed, or execute a set of related instructions
-A 编译,把汇编命令变为机械代码Assemble symbolic instructions into machine code
-N 命名一个程序Name a program
-W 把一个已经命名的程序写进磁盘Write the named program onto disk
-L 把程序装载进内存Load the named program back into memory
返回目录
--------------------------------------------------------------------------------
1)让我们开始工作吧,例如:显示BIOS的日期
(以下PROMPT>表示目录提示符:一般为:C:\WINDOWS\COMMAND\)PROMPT> DEBUG<按回车>
-D FFFF:0006 L 8<按回车> (显示 FFFFh, 偏移地址 6h, 长度 8 bytes)
在作者的电脑上这里显示为 "1/10/96."
译者的电脑显示“ FFFF:0000 37 2F-30 36 2F 30 30 00 7/06/00.”相信作者的电脑里也是用这种格式显示的。这里显示出来的是使用者BIOS的日期,有兴趣的话可以重新开机看看,注意开机时的显示。
-Q<按回车> (退出DEBUG) 思考:当只按DEBUG的时候,编辑的是什么?为什么可以找到BIOS的日期?(译者这里也不是很清楚所以请大家知道的也留言给斑竹,改正。译者认为可能是内存的真实物理地址。)
返回目录
--------------------------------------------------------------------------------
2)在你的电脑的COMMANG.COM文件里搜寻“IBM”这几个字符
下面的“C:\Win95\”是根据每不电脑不同的。像译者的电脑里就是“C:\WINDOWS”PROMPT> DEBUG C:\Win95\Command.com<按回车>
-S 0 L FFFF "IBM"<按回车>(从0开始搜寻"IBM",搜寻FFFFh多个单元格)
-Q<按回车> (退出DEBUG) 以下是译者做的: C:\WINDOWS>DEBUG C:\WINDOWS\COMMAND.COM
-S 0 L FFFF "IBM"
-S 0 L FFFF "COMMAND"
12A7:008D
12A7:04F7
12A7:3870
12A7:38BE
12A7:38DD
-S 0 L FFFF "PATH"
12A7:38AD
12A7:CCB7
12A7:CF55
-S 0 L FFFF "COMSPEC"
12A7:38D4
12A7:3A4D
12A7:CCC4
-QC:\WINDOWS>(注意:搜寻是要区分大小写的)
(你可以看到上面是没有找到“IBM”的, 可以试一试"PATH" , "COMSPEC" , "COMMAND")
(注意: 这种方法用在查找加密资料和已被删除的资料等方面时是十分有用的)
返回目录
--------------------------------------------------------------------------------
3) 一位十六进制数的运算:PROMPT> DEBUG<按回车>
-H 9 1<按回车> (加减两个十六进制的数, 9h+1h=Ah & 9h-1h=8h)
结果是显示: 000A 0008
-Q<按回车> (退出DEBUG) C:\WINDOWS>debug
-h 9 1
000A 0008
-q
C:\WINDOWS>
返回目录
--------------------------------------------------------------------------------
4) 检查x86寄存器内容PROMPT> DEBUG<按回车>
-R<按回车> (显示x86寄存器内容)
-Q<按回车> (退出DEBUG) C:\WINDOWS>debug
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 043C ADD AL,3C
-Q
下面是对寄存器的简单介绍:
数据存储器
在本类中,一般讲的AH就是AX的前八位,AL就是AX的后八位,后面的以此类推。
AX Accumulator;作为累加器,所以它是算术运算的主要寄存器。另外所有的I/O指令都使用这一寄存器与外部设备传送信息。
BX Base register;可以作为通用寄存器使用,此外在计算存储器地址时,它经常用作基地址寄存器。
CX Counting register;可以作为通用寄存器使用,此外在循环(LOOP)和串处理指令中作隐含的计数器。
DX Data register;可以作为通用寄存器使用,一般在作双字长运算时,把DX和AX组合在一起存放一个双字长数,DX用来存放高位字。此外,对某些I/O操作,DX可用来存放I/O的端口地址。 指针及变址寄存器
BP Base pointers register ;机制指针寄存器
SI Source index register ;堆栈指针寄存器
DI Destiny index register ;目的变址寄存器
SP Battery pointer register ;堆栈指针寄存器
段寄存器
CS Code segment register ;代码段寄存器,存放正在运行的程序指令
DS Data segment register ;数据段寄存器,存放当前运行程序所用的数据
SS Battery segment register ;堆栈段寄存器,定义了堆栈所在区域
ES Extra segment register ;附加段寄存器,存放附加的数据,是一个辅助性的数据区,控制寄存器
IP Next instruction pointer register;指令指针寄存器,它用来存放代码段中的偏移地址,在程序运行的过程中,它始终指向下一条指令的首地址,它与CS寄存器联用确定下一条指令的物理地址
F Flag register;标志寄存器 “NV UP EI PL NZ NA PO NC”就是了,也有人称之为PSW Program Status Wold程序状态寄存器
(这里有一点必须讲明白的现在在,其实从奔腾开始这些寄存器(除了所有段寄存器,标志寄存器 )都是32位的。并且加多了两个16位段寄存器FS,GS。dos下面看到这些寄存器是16位的。要看32位寄存器可以使用soft-ice。对于FS,GS的作用我也不是很清楚,希望有高手指点,谢谢。) 返回目录
--------------------------------------------------------------------------------
5)我们来编写我们的第一个用机械语言编写的程序-打印一个字符
(这里用机械语言的主要原因是考虑到有一些用户不懂汇编命令,现在就要让他有一个认识计算机程序实质是一些数字)
PROMPT> DEBUG<按回车>
-E 100<按回车> (在偏移地址为100的地方输入机械指令程序)
B4<按空格>02<按空格> (在AX寄存器的前八位存入02)
B2<按空格>41<按空格> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对着表改改数字试一试)
CD<按空格>21<按空格> (当AH=02时这是DOS显示输出的中断号)
CD<按空格>20<按回车> (退出DOS)
-G<按回车> (程序运行,并在屏幕上显示出“A”)
程序运行完以后你将看到"Program terminated normally"(程序正常结束了).
-U 100<按回车> (我们把它反汇编,就是把机械命令变为汇编语言指令)
107F:0100 B402 MOV AH,02
:0102 B2 MOV DL,41
:0104 CD21 INT 21
:0106 CD20 INT 20
(下面会有一堆无用的东西)
(对了,你的段地址可能与我的段地址CS=107F不同哦)
-R<按回车> (让我们来看看寄存器的值; IP==100h, AX==0000h, DX==0000h)
好极了,我们看到电脑又做好了准备下一次运行程序了。
-T<按回车> (执行第一步操作... IP=>102h, AX=>0200h,指令指针寄存器指向下一条命令,AX的值被改变。
-T<按回车> (执行第二步操作... IP=>104h, , DX=>0041h,指令指针寄存器指向下一条命令,DX的值被改变。
-P<按回车> (继续执行 INT 21,IP=>106h, AX=>02h,)
-P<按回车> (继续执行INT 20)
-Q<按回车> (退出DEBUG)
(注意:你必须小心使用"T".因为如果你在程序完结以后继续执行这条命令,因为我们无法预知下面的指令是什么,所以我们也无法预知它可能带来的后果)
C:\WINDOWS>DEBUG
-E 100
127C:0100 B4.B4 02.02 B2.B2 41.41 CD.CD 21.21 CD.CD 20.20
-G
A
Program terminated normally
-U 100
127C:0100 B402 MOV AH,02
127C:0102 B241 MOV DL,41
127C:0104 CD21 INT 21
127C:0106 CD20 INT 20
127C:0108 C706F1E30900 MOV WORD PTR [E3F1],0009
127C:010E EB59 JMP 0169
127C:0110 57 PUSH DI
127C:0111 BFF1E3 MOV DI,E3F1
127C:0114 8BDF MOV BX,DI
127C:0116 06 PUSH ES
127C:0117 0E PUSH CS
127C:0118 07 POP ES
127C:0119 32D2 XOR DL,DL
127C:011B EB34 JMP 0151
127C:011D 006B12 ADD [BP+DI+12],CH
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-TAX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0102 NV UP EI PL NZ NA PO NC
127C:0102 B241 MOV DL,41
-TAX=0200 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0104 NV UP EI PL NZ NA PO NC
127C:0104 CD21 INT 21
-P
A
AX=0241 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0106 NV UP EI PL NZ NA PO NC
127C:0106 CD20 INT 20
-PProgram terminated normally
-QC:\WINDOWS> 返回目录
--------------------------------------------------------------------------------6) 我们现在用汇编语言指令来做和例5一样的事情 PROMPT> DEBUG<按回车>
-A 100<按回车> (在偏移地址为100的地方输入汇编语言程序)
MOV AH,02<按回车> (选用DOS的02号功能调用,显示输出)
MOV DL,<按回车> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对着表改改数字试一试)
INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"A")
INT 20<按回车> (退出DOS)
<按回车> (结束汇编语言编程状态,回到DEBUG命令状态)
-G =100<按回车> (运行程序,其实可以不要“=100”因为一般默认启始位置是100)
-Q<按回车> (退出DEBUG) C:\WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 INT 20
127C:0108
-G
A
Program terminated normally
-Q返回目录
--------------------------------------------------------------------------------7) 现在,我们不但要编写一个汇编程序,而且我们还要把它存盘
(下面这个程序就要比原来的程序复杂一点了-显示输出:"ABC") PROMPT> DEBUG<按回车>(运行DEBUG程序;系统默认启始IP寄存器值为100h)
-A 100<按回车> (用汇编语言编写一个程序,启始地址是100h)
MOV AH,02<按回车> (选择DOS的02号功能调用, 显示输出)
MOV DL,<按回车> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码)
INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"A")
MOV DL,42<按回车> (在DX寄存器的后八位存入41h,41h就是大写B的ASCII码)
INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"B")
MOV DL,43<按回车> (在DX寄存器的后八位存入41h,41h就是大写C的ASCII码)
INT 21<按回车> (当AH=02时这是DOS显示输出的中断号,显示"C")
INT 20<按回车> (程序结束,退出DEBUG)
<按回车> (结束汇编命令输入,回到DEBUG命令输入)
-R BX<按回车> (查看寄存器BX的值)
:0000<按回车> (设置BX为0000h,这是程序的结尾地址是BX:CX)
(注意,只要BX = 0000, 文件的大小就小于 < 64 Kb.)
-R CX<按回车> (设置CX为Fh,这是程序的长度:16位)
:0010<按回车> (现在我们可以把这个16字节的程序写入硬盘了)
-N printabc.com<按回车> (将要存盘的程序命名)
-W<按回车> (把这十六字节写到文件里面)
-Q<按回车> (退出DEBUG)
PROMPT> DIR printabc.com<按回车>
这里将会报告这个文件的大小是16字节 (10h 字节).
PROMPT> printabc.com<按回车>
会马上在屏幕上打印出"ABC"
C:\WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 MOV DL,42
127C:0108 INT 21
127C:010A MOV DL,43
127C:010C INT 21
127C:010E INT 20
127C:0110
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-R BX
BX 0000
:
-R CX
CX 0000
:0010
-N PRINTABC.COM
-W
Writing 00010 bytes
-Q
C:\WINDOWS>DIR PRINTABC.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:\WINDOWS
PRINTABC COM 16 03-21-01 11:02 PRINTABC.COM
1 file(s) 16 bytes
0 dir(s) 557,711,360 bytes free
C:\WINDOWS>PRINTABC
ABC
C:\WINDOWS> 这里可以有人告诉我,为什么要存入是BX:CX代表程序长度吗?(写信给译者,谢谢)返回目录
--------------------------------------------------------------------------------8) 现在,我们试一试查看一个已经编好的程序: PROMPT> DEBUG<按回车>(运行DEBUG程序在CS:IP = CS:0100h)
-N printabc.com<按回车> (告诉电脑你想装载的程序名)
-L<按回车> (装载那个名字的程序进入内存)
-U 100 L 10<按回车> (从偏移地址100开始反汇编16位字节)
-R<按回车> (现在看看寄存器里面的内容)
注意:DEBUG本身是没有自动纪录文件大小的。
-G (运行被命名的程序,打印"ABC")
你将看到"ABC",然后是"Program terminated normally")C:\WINDOWS>DEBUG
-N PRINTABC.COM
-L
-U 100 L 10
12A4:0100 B402 MOV AH,02
12A4:0102 B241 MOV DL,41
12A4:0104 CD21 INT 21
12A4:0106 B242 MOV DL,42
12A4:0108 CD21 INT 21
12A4:010A B243 MOV DL,43
12A4:010C CD21 INT 21
12A4:010E CD20 INT 20
-R
AX=0000 BX=0000 CX=0010 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=12A4 ES=12A4 SS=12A4 CS=12A4 IP=0100 NV UP EI PL NZ NA PO NC
12A4:0100 B402 MOV AH,02
-G
ABC
Program terminated normally返回目录
--------------------------------------------------------------------------------9)你可以用DEBUG的计算功能计算程序的长度。 一开始的时候你的程序初始地址是在0100h:
107F:0100 MOV AH,02 <--这就是 100h
你的程序的最后一行在010Eh:
107F:010E INT 20 <--最后一行
然后,最后一条命令的下一行的地址是0110h:
107F:0110 <--这就是110h
所以,从0110h里减去100h我们得到得长度是10h 字节. PROMPT> DEBUG<按回车>
-H 110 100<按回车> (这条命令将运算110h+100h和110h-100h)
0210 0010<按回车> (汇报 110h-100h=0010h; 16-byte 程序长度16位)
-Q<按回车> (退出DEBUG) C:\WINDOWS>debug
-H 110 100
0210 0010
-Q返回目录
-------------------------------------------------------------------------------- 10)另一种显示在屏幕上字符串的方法注意:在你输入数据的时候,按"-"键将会可以让你回退一格。 PROMPT> DEBUG<按回车>
-E 200<按回车> (从偏移地址200开始。输入"Hello,World")
48<按空格>65<按空格> (输入48h (H)和65h (e))
6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (输入57h (W)和6Fh (o))
72<按空格>6C<按空格> (输入72h (r)和6Ch (l))
64<按空格>24<按空格> (输入64h (d)和24h ($))
<按回车> ("Hello,World" 已经输入完毕)
-D 200<按回车> (显示你刚刚输入的内容:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ... HELLO,WORLD$...)
-A 100<按回车> (用汇编语言写一个新程序在IP-100h处开始)
MOV AH,09<按回车> (选择DOS的09号功能调用,显示字符串)
MOV DX,0200<按回车> (把输出地址(200h),放进寄存器)
INT 21<按回车> (执行DOS功能调用,显示"Hello,World")
INT 20<按回车> (退出程序回到DOS状态)
<按回车> (结束汇编语言输入,回到DEBUG输入状态)
-G<按回车> (从 CS:IP开始运行程序, 就是从107F:0100h开始执行程序) 现在,我们可以把这个程序保存进一硬盘-D 100<按回车> (纪录:程序的起始点在100h)
-D 200<按回车> (纪录:程序数据单元的结束点是在020Bh)
-H 20B 100<按回车> (运算 20Bh-100h=10Bh;程序长度267字节)
-R BX<按回车> (检查BX寄存器的值)
:0000<按回车> (设置BX为0000h,程序的长度是BX:CX,实际上你可以把和CX写到一起,即实际长度为:0000010Bh,这样些的目的是使你可以计算更大的程序的长度)
-R CX<按回车> (设置CX 为010Bh, 这就是这个程序的长度了)
:010B<按回车> (现在你可以把这个108字节的程序写入硬盘了)
-N printhw.com<按回车> (将要写入硬盘的程序命名)
-W<按回车> (把这10Bh 即267个字节写入文件)
-Q<按回车> (退出DEBUG)
PROMPT> DIR printhw.com<按回车>
将会汇报程序的长度是267字节(10Bh字节).
PROMPT> printhw.com<按回车>
运行这个程序,这将会在屏幕上显示出"Hello,World" : C:\WINDOWS>DEBUG
-E 200
127C:0200 2C.48 D5.65 BA.6C FF.6C FF.6F B8.2C 00.57 AE.6F
127C:0208 CD.72 2F.6C 3C.64 00.24 C3.
-D 200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... .
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7..
127C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6.........
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y.........
-A 100
127C:0100 MOV AH,09
127C:0102 MOV DX,0200
127C:0105 INT 21
127C:0107 INT 20
127C:0109
-G
Hello,World
Program terminated normally
-D200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... .
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7..
27C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6.........
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y.........
-H 20B 100
030B 010B
-R BX
BX 0000
:
-R CX
CX 0000
:010B
-N PRINTHW.COM
-W
Writing 0010B bytes
-Q
C:\WINDOWS>DIR PRINTHW.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:\WINDOWS
PRINTHW COM 267 03-22-01 11:53 PRINTHW.COM
1 file(s) 267 bytes
0 dir(s) 555,089,920 bytes free返回目录
--------------------------------------------------------------------------------11)让我们试一试反复输出:PROMPT> DEBUG<按回车>
-A 100<按回车> (用汇编语言写一个新的程序,起始地址是100h)
JMP 125<按回车> (从102h接跳到125h)
<按回车> (结束输入汇编命令。译者注:这里是为了例12做准备)
-E 102 'Hello World' 0d 0a '$'<按回车> (把字符串输入内存)
-A 125<按回车> (从125h开始继续编写我们的汇编语言程序)
MOV DX,0102<按回车> (把字符串的首地址(102h)放入DX寄存器)
MOV CX,0005<按回车> (指定这条指令将被显示5次)
MOV AH,09<按回车> (选择DOS的09号功能调用, 显示字符串)
INT 21<按回车> (执行DOS的功能调用, 显示"Hello, World")
DEC CX<按回车> (每次运行到这里CX都减去1)
JCXZ 0134<按回车> (如果计数器CX=0,那么跳到地址0134h)
JMP 012D<按回车> (其他情况下,即CX≠O时跳到012Dh)
INT 20<按回车> (程序退出DOS状态)
<按回车> (结束汇编语言程序输入,回到DEBUG)
-U 100<按回车> (从地址100h 开始反汇编)
-U<按回车> (继续执行反汇编指令,直至你看到INT 20)
-H 0136 100<按回车> (运算程序长度为36h)
-U 100 L 36<按回车> ( 从100h反汇编到136h ,来确认你的计算)
-R BX<按回车> (查看寄存器BX的值)
:0000<按回车> (设置BX为0000h)
-R CX<按回车> (把CX 设置为36h, 这就是程序长度36字节)
:0036<按回车> (现在你可以把这36字节写入文件了)
-N printhw5.com<按回车>(命名我,我们要写入的文件名)
-W<按回车> (把这36字节的内容写进新文件)
-G<按回车> (运行程序,在屏幕上显示”Hello-World “)
-Q<按回车> (退出DEBUG)
PROMPT> DIR printhw5.com<按回车>
将会汇报文件大小为54字节,换算为十六进制就是36h字节
PROMPT> printhw5.com<按回车>
将在屏幕上显示五次"Hello World"返回目录
--------------------------------------------------------------------------------12)我们现在把两个程序连接起来。 我们现在把printhw.com做为修补程序 写进printhw5.com, 新版本的printhw5 将先执行原来的printhw.com再执行原来的printhw5.comPROMPT> COPY printhw5.com printhw5.bak<按回车>
首先,备份printhw5.com,以后可以用于比较
PROMPT> DIR printhw5.com<按回车>
现在,查看到得仍然是以前的54字节(36h 字节)
PROMPT> DEBUG printhw5.com<按回车>
-R<按回车> (现在查看仍然是BX:CX=0000 0036h bytes)
-U 100<按回车> (查看到最后的是 EB 23 (JMP 0125))
-H 100 36<按回车> (最后的指令是在 100h+36h=136h)
-H 136 1<按回车> (下一个可用的存储器位置是136h+1h=137h)
现在你拥有足够的资料,去修补那个程序
-E 110<按回车> (把"Hello,World"输入内存)
48<按空格>65<按空格> (输入48h (H)和65h (e))
6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (输入57h (W)和6Fh (o))
72<按空格>6C<按空格> (输入72h (r)和6Ch (l))
64<按空格>24<按空格> (输入64h (d)和24h ($))
<按回车> (停止输入"Hello,World")
-D 110<按回车> (显示更才输入内存的数据:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ...HELLO,WORLD$...)
-A 100<按回车> (在IP地址的(100h)开始夺取原来的程序的控制权,原来这里是”JMP 125”)
JMP 137<按回车> (代替原来运行的程序首先运行我们现在的修补程序)
<按回车> (结束汇编命令输入,回到DEBUG命令输入)
-A 137<按回车> (在下面的可用通奸编译这个修补程序)
MOV AH,09<按回车> (选择DOS的09号功能调用,显示输出)
MOV DX,110<按回车> (把我们要输出的字段的首地址(110h)给DX寄存器)
INT 21<按回车> (执行DOS 的功能调用,显示"Hello,World")
JMP 0125<按回车> (这里用跳转到原程序来代替退出到DOS命令(INT 20))
<按回车> (结束汇编命令输入,回到DEBUG命令输入) -U 125<按回车> (确认一下源程序没有被我们误改了,如果无改了就马上退出DEBUG重新来过)
-U 100 L 1<按回车> (确认已经使程序跳转到我们的修补程序地址137h)
-D 110 L C<按回车> (确认数据区已经有了我们想要的数据)
-U 137<按回车> (确认我们的新程序已经输入了) 现在我们可以把这个小程序存入硬盘了:
(注意:在现在整个程序的最后一条命令"JMP 0125" 的后面一条的地址是0140h)
-H 0140h 100<按回车> (计算140h-100h=40h; 答案是我们现在有一个长度为64字节的小程序)
-RBX<按回车> (检查BX寄存器的值是否为”0”)
:<按回车> (如果BX是0000h那么就不需要改动啦)
-RCX<按回车> (要把CX改为40h。这是我们的程序的长度)
:40<按回车> (现在你可以把这0000:0040h个字节的小程序放入硬盘啦)
-W<按回车> (覆盖我们的原程序)
-G<按回车> (尝试运行我们的新程序)
-Q<按回车> (退出DEBUG回到DOS) PROMPT> DIR printhw5.com<按回车>
现在你再看就发现文章大小不再是54字节, 变成了64字节.
PROMPT> printhw5.com<按回车>
现在是首先在屏幕上打印 "Hello,World"一次,然后再打印"Hello,World" 5 次(译者注:这里其实可以在编程的时候换一换内容试一试.返回目录
--------------------------------------------------------------------------------13) 让我们逐步运行这个刚刚修补的程序:PROMPT> DEBUG printhw5.com<按回车>
-R<按回车> (第1步:地址0100h内容是 EB35 "JMP 0137")
-T<按回车> (第2步:地址0137h内容是B409 "MOV AH,09")
-T<按回车> (第3步:地址0139h内容是BA1001 "MOV DX,0110")
-T<按回车> (第4步:地址0139h内容是CD21 "INT 21")
-P<按回车> (运行第5:"Hello,World"地址013Eh内容是EBE5 "JMP 0125")
-T<按回车> (到这里控制权已经回到了原程序)
如果你想的话,你可以一步一步的执行完全部程序;方法就是一直按”T”,直至到达下一个功能调用运行完成后。到那时按一个"P"就可以继续按"T".返回目录
--------------------------------------------------------------------------------14)如果一开始的命令不是跳转命令,那么可能就要用这种方法了:例如:如果我们想叫程序printhw 先打印”ABC”,就要获取控制权了。然后打印”ABC”的程序把控制权给回原来的printhw. 在这个事例里 ,printhw在100h的地址有两字节的程序;
不能象上面那样简单的替代(一个JMP代替另一个JMP)就完事。
解决办法就是使用NOP命令。
PROMPT> DIR printhw.com<按回车>
将汇报程序的长度为267字节(10Bh 字节).PROMPT> DEBUG printhw.com<按回车>
-R<按回车> (IP=100h 并且printhw's 的文件大小=BX:CX=0000:010Bh)
-U 100<按回车> (第一条指令B4 09 (MOV AH,09)是两个字节的)
(第二条命令是三个字节的 BA 00 02 (MOV DX,0200))
-H 100 10B<按回车> (最后一条printhw的指令是在100h+10Bh=20Bh)
(DOS的INT 21功能调用是在105h开始的)
现在你有足够的资料输入你的程序了!
-A 100<按回车> (要在printhw 的IP开始位置就夺取程序的控制权)
JMP 20B<按回车> (跳到20Bh增加一个程序)
NOP<按回车> (用空指令填充直至你去到下一条完整的指令)
NOP<按回车> (你可以用它来覆盖你不想只执行的原程序命令 ,而不改变原来的地址。但是在这里我们只需要两个NOP)
译者注:为了使大家更加明白所以我将各条命令对应的机械命令的长度写在下面
B409 MOV AH,09
BA0002 MOV DX,0200
E90301 JMP 020B
90 NOP
这样我们就很清楚的看到JMP 020B的长度比MOV AH,09多了1个字节,但是MOV DX,0200有是3个字节,而NOP是空指令,是不执行任何操作的,它只是占1个字节。所以我们现在把前两条指令用一个JMP 020B和两个NOP代替。后面再加上去。
<按回车> (结束汇编命令回到DEBUG命令输入)
-U 100<按回车> (看一看前面我们做了些什么)
(注意DOS INT 21中断任然是在 IP=105h的地方开始)
-A 20B<按回车> (现在把我们的原程序写在后面)
MOV AH,02<按回车> (选择DOS 的 2号功能调用, 字符显示输出)
MOV DL,41<按回车> (在DL寄存器存入”A”的ASCII码41h)
INT 21<按回车> (执行DOS 的功能调用,显示字符"A")
MOV DL,42<按回车> (在DL寄存器存入”B”的ASCII码42h)
INT 21<按回车> (执行DOS 的功能调用,显示字符"B")
MOV DL,43<按回车> (在DL寄存器存入”C”的ASCII码43h)
INT 21<按回车> (执行DOS 的功能调用,显示字符"C")
MOV AH,09<按回车> (现在重新输入原来在100h的程序指令)
MOV DX,0200<按回车> (现在要打扫寄存器了,还原原来的200h的值)
JMP 105<按回车> (跳到INT 21指令的位置105h)
<按回车> (请注意一下你这里最后的地址是0221h)
-H 221 100<按回车> (计算221h-100h=121h 就是289字节的程序)
-R CX<按回车> (把CX的值设为121h, 这就设定了程序的新长度)
:0121<按回车> (现在用121h (也就是289字节)覆盖原值)
-W<按回车> (把这289个字节写回原程序)
-Q<按回车> (退出DEBUG) PROMPT> DIR printhw.com<按回车>
现在在看就会是新程序的长度289字节而不是,267字节)
现在在屏幕上先出现"ABC"再出现"Hello,World"返回目录