用机器指令和汇编指令编程(一)
Debug的使用
什么是Debug
Debug
是Dos
、Windows
提供的实模式(8086
方式)程序的调试工具,可以使用它来查看CPU
各种寄存器中的内容、内存的情况和在机器码级跟踪程序的运行。
但是debug
命令在64
位操作系统下是不能使用的。在cmd
中输入debug
,会提示:不是内部或外部命令,也不是运行的程序或批处理文件。
使用DOSBox在Win7_64下搭建汇编环境
DEBUG.EXE
,EDIT.COM
,MASM.EXE
,LINK.EXE
等汇编工具,一般在32
位的Windows
操作系统下有自带,但是在64
位操作系统下并没有提供,并且将32
位系统下的汇编工具拷贝到64
位系统下并不能使用,为了解决这个问题,使用DOSBox
工具来使用它们。
下载DOSBox
,然后安装即可。准备DEBUG.EXE
,EDIT.COM
,MASM.EXE
,LINK.EXE
等汇编工具。
DOSBox
安装完成后,打开发现它的提示符为Z:\>
,这是DOSBox
里的虚拟盘,为了使用我需要更改到我自己的盘符,但是如果采用和cmd
下的方式直接切换盘符,会提示我需要挂载的信息。
比如我要将G:\AssemblyTools
作为我的汇编测试目录,那么需要执行mount G G:\AssemblyTools
命令,G
盘符也就虚拟成了本机的G:\AssemblyTools
目录,将DEBUG.EXE
等一系列汇编工具拷贝至该目录下。当我在DOSBox
下切换到G
盘下时,实际上就是切换到了G:\AssemblyTools
下,因此也就可以直接使用汇编工具了。
Debug功能
- 用
Debug
的R
命令查看、改变CPU
寄存器的内容。 - 用
Debug
的D
命令查看内存中的内容。 - 用
Debug
的E
命令改变内存中的内容。 - 用
Debug
的U
命令将内存中的机器指令翻译成汇编指令。 - 用
Debug
的T
命令执行一条机器指令。 - 用
Debug
的A
命令以汇编指令的格式在内存中写入一条机器指令。
查看和改变CPU寄存器的内容
使用R
命令查看寄存器的内容,注意CS
和IP
的值,CS=073FH
,IP=0100H
,也就是说内存073FH:0100H
处的指令为CPU
当前要读取并执行的指令。在所有寄存器的下方,Debug
还列出了CS:IP
所指向的内存单元处所存放的机器码,并将它翻译成汇编指令。
还可以使用R
命令来改变寄存器中的内容,比如AX
中的值,可用R
命令后加寄存器名来进行,输入r ax
后按Enter
键,将出现:
作为输入提示,在后面输入要写入的数据后按Enter
键,即完成了对AX
寄存器内容的修改。
查看内存中的内容
使用D
命令,可以查看内存中的内容,如果我想知道内存FFFF0H
处的内容,可以使用d 段地址:偏移地址
的格式来查看。
要查看内存FFFF0
处的内容,首先将这个地址表示为段地址:偏移地址
的格式,使用d 段地址:偏移地址
的格式,Debug
将列出指定内存单元开始的128
个内存单元的内容。
Debug
将输出3
部分内容。
- 中间是从指定地址开始的
128
个内存单元的内容,用十六进制的格式输出,每行的输出从16
的整数倍的地址开始,最多输出16
个单元的内容。可以看到,内存FFFFH:0000H
单元中的内容是EA
,内存FFFFH:0010H
单元中的内容为60
。每行中间有一个-
,它将每行的输出分为两个部分,分别是前8
个单元和后8
个单元。 - 左边是每行的起始地址。
- 右边是每个内存单元中的数据对应的可显示的
ASCII
码字符。如果没有对于的ASCII
字符,使用.
来代替。
改变内存中的内容
可以使用E
命令来改变内存中的内容,比如,要将内存1000H:0000H
至1000H:0009H
单元中的内容分别写为0
、1
、2
、3
、4
、5
、6
、7
、8
、9
,可以使用e 起始地址 数据 数据...
的格式进行修改。
也可以采用提问的方式一个一个地改写内存中的内容。输入e 1000:0
,按Enter
键,Debug
显示起始地址1000:0
和第一单元的原始内容00
,然后光标停在.
的后面提示输入想要写入的数据,此时有两个选择,一是输入数据,然后按空格键,即用刚才输入的数据替换内存单元的内容,二是不输入数据,直接按空格,即不改写当前内存单元。所有改写输入完毕后按Enter
,结束操作。
也可以向内存中写入字符串。比如,用E
命令从内存1000H:0000H
开始写入:整数1
、字符串a+b
、整数2
、字符串tinylcy
。
至于向内存中写入机器码,因为机器码也是数据,当然也可以用E
命令将机器码写入内存,比如我要从内存1000H:0000H
单元开始写入这样一段机器码。
b80100 mov ax,0001
b90200 mov cx,0002
01c8 add ax,cx
用E
命令向从1000H:0000H
开始的内存单元中写入了8
个字节的机器码。然后使用D
命令查看内存1000H:0000H
至1000H:001FH
中的数据。
使用U
命令查看写入的或内存中原有的机器码所对应的汇编指令,比如使用U
命令将从1000H:0000H
开始的内存单元中的内容翻译成汇编指令,并显示出来。
U
命令的显示输出可以分为3
部分,每一条机器指令的地址、机器指令、机器指令所对应的汇编指令。
1000H:0000H
处存放的是写入的机器码b8 01 00
所组成的机器指令,对应的汇编指令是mov ax,0001
。1000H:0003H
处存放的是写入的机器码b9 02 00
所组成的机器指令,对应的汇编指令是mov cx,0002
。1000H:0006H
处存放的是写入的机器码01 c8
所组成的机器指令,对应的汇编指令是add ax,cx
。
由此,可以再次感受到内存中的数据和代码没有任何区别,关键在于如何解释。
使用Debug
的T
命令来执行写入的机器码,T
命令可以执行一条或多条指令。如果仅仅是简单的使用T
命令,执行的是CS:IP
指向的指令。查看当前的寄存器状态,可以看到CS=073FH
,IP=0100H
,指向内存073FH:0100H
。若要使用T
命令控制CPU
执行1000H:0000H
单元的指令,需要先让CS:IP
指向1000H:0000H
,因此,使用R
命令修改CS
、IP
中的内容,使得CS:IP
先指向1000H:0000H
。
完成上述步骤之后,就可以使用T
命令执行刚才写入的指令了。指令T
命令之后,CPU
执行CS:IP
指向的指令,那么1000H:0000H
处的指令b8 01 00(mov ax, 0001)
得到执行。注意,指令执行后,AX
中的内容被修改为1
,IP
改变为IP+3
(因为mov ax, 0001
的指令长度为3
字节),CS:IP
指向下一跳指令,继续使用T
命令执行下面的指令。最终AX
中的内容为3
,CX
中的内容为2
。
使用E
命令可以直接向内存中写入机器指令,但是这样做不方便。为此,Debug
提供了A
命令,可以直接以汇编的形式写入指令。
首先使用A
命令,以汇编语言向从1000H:0000H
开始的内存单元中写入了几条指令,然后用D
命令查看内存中的内容。可以看到Debug
将这些汇编指令翻译成对应的机器指令,将它们的机器码存入内存。接着,可以使用T
命令执行内存中的这段机器码。
总结
- 查看、修改
CPU
中寄存器的内容:R
命令。 - 查看内存中的内容:
D
命令。 - 修改内存中的内容:
E
命令(可以写入数据、指令,在内存中,它们实际上没有区别)。 - 将内存中的机器指令解释为汇编指令:
U
命令。 - 执行
CS:IP
指向的内存单元处的指令:T
命令。 - 以汇编指令的形式向内存中写入指令:
A
命令。