附录B TD.EXE的简要使用说明
TD.EXE(简称TD)是一个具有窗口界面的程序调试器.利用TD,用户能够调试已有的可执行程序(后缀为EXE);用户也可以在TD中直接输入程序指令,编写简单的程序(在这种情况下,用户每输入一条指令,TD就立即将输入的指令汇编成机器指令代码).作为入门指导,下面简单介绍一下TD的使用方法,更详细深入的使用说明请参考相关资料.
一 如何启动TD
1. 在DOS窗口中启动TD
(1) 仅启动TD而不载入要调试的程序。
转到TD.EXE所在的目录(假定为C:\\ASM),在DOS提示符下键入以下命令(用户只要输入带下划线的部分,"↙"表示回车键,下同):
C:\ASM>TD↙
用这种方法启动TD,TD会显示一个版权对话框,这时按回车键即可关掉该对话框。 (2)启动TD并同时载入要调试的程序。
转到TD.EXE所在的目录,在DOS提示符下键入以下命令(假定要调试的程序名为HELLO.EXE):
C:\\ASM>TD HELLO.EXE↙
若建立可执行文件时未生成符号名表,TD启动后会显示“Program has no symbol table”的提示窗口,这时按回车键即可关掉该窗口。
2.在Windows中启动TD
⑴仅启动TD而不载入要调试的程序。 双击TD.EXE文件名, Windows就会打开一个DOS窗口并启动TD。启动TD后会显示一个版权对话框,这时按回车键即可关掉该窗口。
⑵启动TD并同时载入要调试的程序。
把要调试的可执行文件拖到TD.EXE文件名上, Window就会打开一个DOS窗口并启动TD,然后TD会把该可执行文件自动载入内存供用户调试。若建立可执行文件时未生成符号名表,TD启动后会显示“Program has no symbol table” 的提示窗口,这时按回车键即可关掉该窗口。
二 TD中的数制
TD支持各种进位记数制,但通常情况下屏幕上显示的机器指令码﹑内存地址及内容﹑寄存器内容等均按十六进制显示(数值后省略”H”)。在TD的很多操作中,需要用户输入一些数据﹑地址等,在输入时应遵循计算机中数的记数制标识规范:
十进制数后面加’D’或’d’,如119d﹑85d等; 八进制数后面加’O’或’o’,如134o﹑77o等; 二进制数后面加’B’或’b’,如10010001b等;
十六进制数后面加’H’或’h’,如38h﹑0a5h﹑0ffh等。 如果在输入的数后面没有用记数标识字母来标识其记数制,TD默认该数为十六进制数。但应注意,如果十六进制数的第一个数字为’a’~’f’,则前面加0,以区别于符号和名字。
TD允许在常数前面加正负号。例如,十六进制数的-12可以输入为-12d,十六进制数的-5a可以输入为-5ah,TD自动会把输入的带正负号的数换成十六进制补码数。只有一个例外,当数据区的显示格式为字节,若要修改存储单元的内容则不允许用带有正负号的数,而只能按手工转换成补码后再输入。
本书中所有的实验在输入程序或数据时,若没有特别的说明,都可按十六进制数进行输入,若程序中需要输入负数,可按上述规则进行输入。
三 TD的用户界面
1.CPU窗口
TD启动后呈现的是一个具有窗口形式的用户界面,见图1,它称为CPU窗口。CPU窗口显示了CPU和内存的整个状态。利用CPU窗口可以:
代码区 数据区 寄存器区 堆栈区 标志位区
图1
·在代码区内使用嵌入汇编,输入指令或程序进行临时性修改。
·存取数据区中任何数据结构下的字节,并以多种格式显示或改变它们。 ·检查和改变寄存器(包括标志寄存器)的内容。
CPU窗口分为5个区域:代码区、寄存区、标志区、数据区和堆栈区。 在5个区域中,光标所在区域称为当前区域,用户可以使用Tab键或Shift+Tab键切换当前区域,也可以在相应的区域中单击鼠标左键选中某区为当前区。光标在各个区域中显示形式稍有不同,在代码区、寄存区、标志区和堆栈区呈现为一个反白条,在存储器区为下划线形状。
在图1中,CPU窗口上边框的左边显示的是处理器的类型(8086、80286、80386、80486等,对于80486以上的CPU均显示为80486)。上边框的中间靠右处显示了当前指令所访问的内存单元的地址及内容。再往右的’1’表示此CPU窗口是第一个CPU窗口,TD允许同时打开多个CPU窗口。
CPU窗口中的代码区用于显示指令地址,指令的机器代码以及相应的汇编指令;寄存器区用于显示CPU寄存器当前的内容;标志区用于显示CPU的8个标志位当前的状态;数据区用于显示用户指定的一块内存区的数据(十六进制);堆栈区用于显示堆栈当前的内容。
在代码区和堆栈区分别显示一个特殊标志( ),称为箭标。代码区中的箭标指示出当前程序指令的位置(CS:IP),堆栈区中的箭标指示出当前堆栈指针位置(SS:SP)。
2.全局菜单介绍
CPU窗口的上面为TD的全局菜单条,可用“ALT键+菜单项首字符”打开菜单项对应的下拉子菜单。在子菜单中用上、下游标键选择所需的功能,按回车键即可执行选择的功能。为简化操作,某些常用的子菜单项后标出了对应的快捷键。下面简单介绍一下常用的菜单命令,详细的说明请查阅相关资料。
(1)File菜单—文件操作。
Open 载入可执行程序文件准备调试 Change dir 改变当前目录
Get info 显示被调试程序的信息
DOS shell 执行DOS命令解释器(用EXIT命令退回到TD) Quit 退出TD(Alt+X) (2)Edit菜单—文本编辑。
Copy 复制当前光标所在内存单元的内容到粘贴板(Shift+F3) Paste 把粘贴板的内容粘贴到当前光标所在内存单元(Shift+F4) (3)View菜单---打开一个信息查看窗口. Breakpoints 断点信息 Stack 堆栈段内容 Watches 被监视对象信息 Variables 变量信息 Moduble 模块信息 File 文件内容
CPU 打开一个新的CPU窗口 Dump 数据段内容 Registers 寄存器内容 (4)Run菜单---执行。
Run 从CS:IP开始运行程序直到程序结束(F9) Go to cursor 从CS:IP开始运行程序到光标处(F4)
Trace into 单步跟踪执行(对CALL指令将跟踪进入子程序),F7键 Step over 单步跟踪执行(对CALL指令将执行完子程序才停下),F8键 Execute to 执行到指定位置(Alt+F9)
Until return 执行当前子程序直到退出(Alt+F8) (5)Breakpoints菜单---断点功能
Toggle 在当前光标处设置/清除断点(F2) At 在指定处设置断点(Alt+F2) Delete all 清除所有断点 (6)Data菜单---数据查看.
Inspector 打开观察器以查看指定的变量或表达式 Evaluate/Modify 计算和显示表达式的值
Add watch 增加一个新的表达式到观察器窗口 (7)Option菜单---杂项.
Display options 设置屏幕显示的外观 Path for source 指定原文件查找目录 Save options 保存当前选项 (8)Window菜单---窗口操作
Zoom 放大/还原当前窗口(F5) Next 转到下一窗口(F6)
Next Pane 转到当前窗口的下一区域(Tab) Size/Move 改变窗口大小/移动窗口(Ctrl+F5) Close 关闭当前窗口(Alt+F3)
User screen 查看用户程序的显示(Alt+F5)
3.功能键提示条
菜单中的很多命令都可以使用功能键来简化操作。功能键分为三组:F1~F10功能键,Alt+F1~Alt+F10功能键以及Ctrl功能键(Ctrl功能键实际上就是代码区的局部菜单)。CPU窗口下面的提示条中显示了这三组功能键对应的功能。通常情况下提示条中显示的是F1~F10功能键的功能。按住Alt键不放,提示条中将显示Alt+F1~Alt+F10功能键的功能。按住Ctrl键不放,提示条中将显示Ctrl功能键的功能。表B-1列出了各功能键对应的功能。
表B-1
功能键 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 功能 帮助 设/清断点 查看模块 运行到光标 放大窗口 下一窗口 跟踪进入 单步跟踪 执行程序 激活菜单 功能键 Alt+F1 Alt+F2 Alt+F3 Alt+F4 Alt+F5 Alt+F6 Alt+F7 Alt+F8 Alt+F9 Alt+F10 功能 帮助 设置断点 关闭窗口 Undo跟踪 用户屏幕 Undo关窗 指令跟踪 跟踪到返回 执行到某处 局部菜单 功能键 Ctrl+G Ctrl+O Ctrl+F Ctrl+C Ctrl+P Ctrl+S Ctrl+V Ctrl+M Ctrl+N 功能 定位到指定地址 定位到CS:IP 定位到指令目的地址 定位到调用者 定位到前一个地址 查找指定的指令 查看源代码 选择代码显示方式 更新CS:IP
4.局部菜单
TD的CPU窗口中,每一个区域都有一个局部菜单,局部菜单提供了对本区域进行操作的各个命令。在当前区域中按Alt+F10键即可激活本区的局部菜单。代码区﹑数据区﹑堆栈区和寄存器区的局部菜单见图2~图5所示。标志区的局部菜单非常简单,故没有再给出其图示。对局部菜单各个命令的解释将在下面几节中分别进行说明。
图2
图3
图4
图5
四 代码区的操作
代码区用来显示代码(程序)的地址﹑代码的机器指令和代码的反汇编指令。本区中显示的反汇编指令依赖于所指定的程序起始地址。TD自动反汇编代码区的机器代码并显示对应的汇编指令。
每条反汇编指令的最左端是地址,如果段地址与CS段寄存器的内容相同,则只显示字母”CS”和偏移量(CS:YYYY),否则显示完整的十六进制的段地址和偏移地址(XXXX:YYYY)。地址与反汇编指令之间显示的是指令的机器码。如果代码区当前光标所在指令用了一个内存单元地址,则该内存单元地址和内存单元的当前内容显示在CPU窗口顶部边框的右边,这样不仅可以看到指令操作码,还可以看到指令要访问的内存单元的内容。
1. 输入并汇编一条指令
有时我们需要在代码区临时输入一些指令。TD提供了及时汇编功能,允许用户在TD中直接输入指令(但直接输入的指令都是临时性的,不能保存到磁盘上)。直接输入的步骤如下:
(1) 使用方向键把光标移到期望的地址处。
(2) 打开指令编辑窗口。有两种方法:一是直接输入汇编指令,在输入汇编指令的同时屏幕上就会自动弹出指令的临时编辑窗口;二是激活代码区局部菜单(见下一小节),选择其中的汇编命令,屏幕上也会自动弹出指令的临时编辑窗口。
(3) 在临时编辑窗口中输入/编辑指令,每输入完一条指令,按回车,输入的指令即可出现在光标处,同时光标自动下移一行,以便输入下一条指令。注意,临时编辑窗口中曾经输入过的指令均可重复使用,,只要在临时编辑窗口中用方向键把光标定位到所需的指令处,按回车即可。如果临时编辑窗口中没有完全相同的指令,但只要有相似的指令,就可对其进行编辑后重复使用。
2. 代码区局部菜单
当代码区为当前区域时(若代码区不是当前区域,可连续按Tab键或Shift+Tab键使代码区成为当前区域),按Alt+F10组合键即可激活代码区局部菜单,代码区局部菜单的外观见图2。下面介绍一下各菜单项的功能。
(1) Goto(转到指定位置)
此命令可在代码区显示任意指定地址开始的指定序列。用户可以键入当前被调试程序以外的地址以检查ROM、BIOS、DOS及其他驻留程序。此命令要求用户提供要显示的代码起始地址。使用Previous命令可以恢复到本命令使用前的代码区位置。
(2) Origin( 回到起始位置)
从CS:IP指向的程序位置开始显示。在移动光标使屏幕滚动后想返回起始位置时可使用此命令。使用Previous命令可以恢复到本命令使用前的代码区位置。
(3) Follow(追踪指令转移位置)
从当前指令所要转向的目的地址处开始显示。使用本命令后,整个代码区从新地址处开始显示。对于条件转移指令(JE、JNZ、LOOP、JCXZ等),无论条件满足与否,都能追踪到其目的地址。也可以对CALL、JMP及INT指令进行追踪。使用Previous命令可以恢复到本命令使用前的代码区位置。
(4) Caller(转到调用者)
从调用当前子程序的CALL指令处开始显示。本命令用于找出当前显示的子程序在何处被调用。使用Previous命令可以恢复到本命令使用前的代码区位置。
(5) Previous(返回到前一次显示位置) 如果上一条命令改变了显示地址,本命令能恢复上一条命令被使用前的显示地址。注意光标键、PageUp、PageDown不会改变显示地址。若重复使用该命令,则在当前显示地址和前一次显示地址之间切换。
(6) Search(搜索)
本命令用于搜索指令或字节列表。注意,本命令只能搜索那些不改变内存内容的字另,如:
PUSH DX
POP [DI+4] ADD AX,100
若搜索以下指令可能会产生意想不到的结果:
JE 123 CALL MYFUNC LOOP 100
(7) ViewSource(查看源代码) 本命令打开源模块窗口,显示与当前反汇编指令相应的源代码。如果代码区的指令序列没有源程序代码,则本命令不起作用,
(8) Mixed(混合)
本命令用于选择指令与代码的显示方式,有三个选择: No 只显示反汇编指令,不显示源代码行。 Yes 如果当前模块为该机语言源模块,应使用此选择。源代码行被显示在第一条反汇编指令之前。
Both 当前模块为汇编语言源模块,应使用此选择。在有源代码行的地方就显示该源代码行,否则显示汇编指令。
(9) New CS:IP(设置CS:IP为当前指令行的地址) 本命令把CS:IP设置为当前指令所在的地址,以便使程序从当前指令处开始执行。用这种方法可以执行任意一段指令序列,或者跳过那些不希望执行的程序段。注意,不要使用本命令把CS:IP设置为当前子程序以外的地址,否则有可能引起整个程序崩溃。
(10) Assemble(即时汇编)
本命令可即时汇编一条指令,以代替当前行的那条指令。注意,若新汇编的指令与当前行的指令长度不同,其后面机器代码的反汇编显示会发生变化。
也可以直接在当前行出输入一条汇编指令来激活此命令。 (11) I/O(输入/输出)
本命令用于对I/O端口进行读写,选择此命令后,会再弹出下一级子菜单,如图6所示。子菜单中的命令解释如下:
① In byte(输入字节)
用于从I/O端口输入一个字节,用户需提供端口地址。 ② Out byte(输出字节)
用于往I/O端口输出一个字节,用户需提供端口地址。 ③ Read word(输入字)
用于从I/O端口输入一个字,用户需提供端口地址。 ④ Write word(输出字) 用于往IO端口输出一个字,。 用户需提供端口地址。
图6
五 寄存器区和标志区的操作
寄存器区显示了CPU各寄存器的当前内容。标志区显示了八个CPU标志位的当前状态,表2列出了各标志位在该区的缩写字母。
表B-2
标志区字母 c z s o 标志位名称 进位(Carry) 全零(Zero) 符号(Sign) 溢出(Overflow) 标志区字母 p a i d 标志位名称 奇偶(Parity) 辅助进位(Auxiliary carry) 中断允许(Interrupt enable) 方向(Direction)
1. 寄存器区局部菜单
当寄存器区为当前区域时(若寄存器区不是当前区域,可连续按下Tab键或Shift+Tab键使寄存器区成为当前区域),按下Alt+F10组合键即可激活寄存器区局部菜单,寄存器区的局部菜单的外观见图5。下面介绍一下各菜单项的功能。
(1) Increment(加1)
本命令用于把当前寄存器的内容加一。 (2) Decrement(减1)
本命令用于把当前寄存器的内容减一。 (3) Zero(清零)
本命令用于把当前寄存器的内容清零。
(4)Change(修改)
本命令用于修改当前寄存器的内容。选择此命令后,屏幕上会弹出一个输入框,在输入框中键入新的值,然后回车,这个新的值就会取代原来该寄存器的内容。
修改寄存器的内容还有一个更简单的变通方法,即把光标移到所需的寄存器上,然后直接键入新的值。
(4) Register 32-bit(32位寄存器)
按32位格式显示CPU寄存器的内容(默认为16为格式)。在286以下的CPU或实方式时只需使用16位显示格式即可。
2. 修改标志位的内容
用局部菜单的命令修改标志位的内容比较繁琐。实际上只要把光标定位到要修改的标志位上按回车键或空格键即可使标志位的值在0、1之间变化。
六 数据区的操作
数据区显示了从指定地址开始的内存单元内容。每行左边按十六进制显示段地址和偏移地址(XXXX:YYYY)。若段地址与当前的DS寄存器内容相同,则显示”DS”和偏移量(DS:YYYY)。地址的右边根据”DISPLAY AS”局部菜单命令所设置的格式显示一个或多个数据项。对字节(Byte)格式,每行显示8B;对字格式(Word),每行显示4个字;对浮点格式(Comp、Float、Real、Double、Extended),每行显示1个浮点数;对长字格式(Long),每行显示2个长字。
当以字节方式显示数据时,每行的最右边显示相应的ASCⅡ字符,TD能显示所有字节值所对应的ASCⅡ字符。
1. 显示/修改数据区的内容
在默认的情况下,TD在数据区显示从当前指令所访问的内存地址开始的存储区域内容。但用户也可以用局部菜单中的“Goto”命令显示任意指定地址开始的内存区域的内容。TD还提供了让用户修改存储单元呢的功能,用户可以很方便地把任意一个内存单元的内容修改为所期望的值。但要注意,若修改了系统使用的内存区域,将会产生不可预料的结果,甚至会导致系统崩溃。修改内存单元内容的步骤如下:
⑴ 用局部菜单中的“Goto”命令并结合使用方向键把光标移到期望的地址单元处(注意数据区的光标是一个下划线)。
⑵ 打开数据编辑窗口。有两种方法:一是直接输入数据,在输入数据的同时屏幕上就会自动弹出数据编辑窗口。二是激活数据区局部菜单(见下一小节),选择其中的“Change“命令,屏幕上也会弹出数据编辑窗口。
⑶在数据编辑窗口中输入所需的数据,输入完后,按回车键,输入的数据就会替代光标处的原始数据。注意,数据编辑窗口中曾经输入过的数据均可重复使用,只要在数据编辑窗口中用方向键把光标定位到所需的数据处,按回车即可。
2.数据区局部菜单
当前数据区为当前区域时(若数据区不是当前区域,可连续按Tab键或Shift+Tab键使数据区成为当前区域),按Alt+F10组合键即可激活数据区局部菜单,数据区局部菜单的外观见图3,下面给出各菜单项的功能描述。
(1)Goto(转到指定位置)
此命令可把任意指定地址开始的存储区域的内容显示在CPU窗口的数据区中。除了可以显示用户程序的数据区外,还可以显示BIOS区、DOS区、驻留程序区或用户程序外的任意地址区域。此命令要求用户提供要显示的起始地址。
(2)Search(搜索)
此命令允许用户从光标所指的内存地址开始搜索一个特定的字符串。用户必须输入一个要搜索的字节列表。搜索从低地址向高地址进行。
(3)Next(下一个)
搜索下一个匹配的字节串(由Search命令指定的)。 (4)Change(修改)
本命令用于修改当前光标处的存储单元的内容,选择此命令后,屏幕上会弹出一个输入框,在输入框中键入新的值,然后回车,这个新的值就会取代原来该单元的内容。
修改存储单元的内容还有一个更简单的方法,即把光标移到所要求的存储单元位置上,然后直接键入新的值。
(5)Follow(遍历)
本命令可以根据存储单元的内容转到相应地址处并显示其内容(即把当前存储单元的内容当作一个内存地址看待)。此命令有下一级子菜单,如图7所示。子菜单中的命令解释如下:
图7
① Near code(代码区近跳转)。本子菜单命令将数据区中光标所指的一个字作为当前代码段的新的偏移量,使代码区定位到新地址处并显示新内容。
② Far code(代码区远跳转)。本子菜单命令将数据区中光标所指的一个双字作为新地址(段值和偏移量),使代码区定位到新地址处并显示新内容。
③ Offset to data(数据区进跳转)。本子菜单命令将光标所指的一个字作为数据区的新的偏移量,使数据区定位到以该字为偏移量的新地址处并显示。
④ Segment: Offset to data(数据区远跳转)。本子菜单命令将光标所指的一个双字作为数据区的新的起始地址,使数据区定位到以该双子为起始地址的位置并显示。
⑤ Base segment:0 to data(数据区新段)。本子菜单命令将光标所指的一个字作为数据段的新段址,使数据区定位到以该字为段址,以0为偏移量的位置并显示。
(6)Previous(返回到前一次显示位置)
即把数据区恢复到上一条命令使用前的地址处显示,上一条命令如果确实修改了显示地址(如Goto命),本命令才有效。注意,而光标键、PageUp、PageDown键并不能修改显示起始地址。
TD在堆栈中保存了最近用过的五个显示起始地址,所以多次使用了Follow命令或Goto命令后,本命令仍能让用户返回到最初的显示起始位置。
(7)Display as(显示方式)
本命令用于选择数据区的数据显示格式。共有8种格式,描述如下: ①Byte 按字节(十六进制)进行显示。 ②Word 按字(十六进制)进行显示。
③Long 按长整型数(十六进制)进行显示。 ④Comp 按8字节整数(十进制)进行显示。 ⑤Float 按短浮点数(科学记数法)进行显示。 ⑥Real 按6字节浮点数(科学记数法)进行显示。 ⑦Double 按8字节浮点数(科学记数法)进行显示。 ⑧Extended 按10字节浮点数(科学记数法)进行显示。 (8)Block(块操作)
本命令用于进行内存块的操作,包括移动、清除和设置内存块初值、从磁盘中读内容到内存块或写内存块内容到磁盘中。本命令有下一级子菜单,如图8所示。其子菜单中的命令解释如下:
图8
① Clear(块清零)。把整个内存块的内容全部清零,要求输入块的起始地址和块的字节数。
② Move(块移动)。把一个内存块的内容复制到另一个内存块。要求输入源块起始地址、
目标块起始地址和源块的字节数。
③ Set(块初始化)。把整个内存块的内容设置为指定的同一个值。要求输入起始地址、块的字节数和所要设置的值。
④ 读取(Read)。读文件内容到内存块中。要求输入文件名、内存块起始地址和要读的字节数。
⑤ 写入(Write)。写内存块内容到文件中。要求输入文件名、内存块起始地址和要写的字节数。
七 堆栈区的操作
当堆栈区为当前区域时(若堆栈区不是当前区域,可连续按Tab键或Shift+Tab键使堆栈区成为当区域),按Alt+F10组合键即可激活堆栈区局部菜单,堆栈区局部菜单的外观见图4。堆栈区局部菜单中各菜单项的功能与数据区局部菜单的通明功能完全一样,只是其操作对象为堆栈区,故此不在赘述。
因篇幅问题不能全部显示,请点此查看更多更全内容