汇编实验一
本次实验主要是熟悉 debug 工具的使用。
第一个,是将一段程序写入内存逐条执行,并观察 CS 和 IP 的变化。
(注:在计算机中,所有数据都是二进制,如何区分哪些是指令哪些是数据呢?靠的是几个寄存器,指向指令的寄存器是 CS和IP,指向数据的寄存器是 DS 和 [地址] 。CS 和 IP 指向的内存,那么计算机会把里面的内容理解成指令,而 DS 和 [地址] 指向的内存,计算机会把它当成数据。在本文中,图是依次向下的,只是碍于篇幅长度的原因,对应只截取相应的一部分。)
有两个命令可以将指令写入内存:E 命令和 A 命令。我分别做了一次。首先我用 E 命令写入。E 我把它理解成 edit 的首字母,意思就是编辑。使用的时候语法格式是-e 地址<回车>或者-e 地址 数据<回车>。第一种,debug 会把当前地址的内容显示出来,并等待修改,如果修改,则写入修改值,若不修改,则直接回车。当然如果你想继续修改,就按空格,debug 会继续显示下一个地址单元的内容,并等待修改,如图所示。(这种方式适合在你想用机器码写入程序时,一次性输入,但由于 debug 一行的字符个数限制,无法全部写入的时候使用。单个单个连续写入,就不会受字符的限制。)

附上一张我写入的程序的机器码的图。

第二种,debug 会从给定地址开始,把你给的数据一个一个往下写入,长度为数据的字节长度。如图所示。

A 命令的语法格式:-a [地址] 。如果给了地址,debug 从给定的地址开始写入程序,如果不给,则会读取 CS 和 IP 的值来充当地址。如图所示。
在前面的图中可以知道:当前 CS 和 IP 的值分别为:073f 和 0100。(注:如果写完程序了,可以回车结束,虽然 debug 会显示当前地址,但它并没有被修改。如图中的073f:0103。a命令中IP 的变化,并不会影响寄存器 IP。)

附上我写入的一段程序。对应机器码就是上面用 E 命令输入的机器码。
(注:可以看到图上,-a 之后,地址为上一次的地址,为什么呢?是因为:之前,IP 被我们修改过了。实际上,每次我们写入指令之后,IP 的值会自动根据输入的字节长度计算并修改,为的是下一次读取或写入数据做准备。)

接下来,我们查看一下我们之前写入的程序。我们用 D 命令来查看它。然后我们来修改073f:0108 这个内存单元。
D 命令的语法格式:-d [地址] [长度] 。 其中地址有两种写法:段地址:偏移地址 偏移地址 和 偏移地址 偏移地址 。 如果有段地址,那么就从给定段地址上的偏移地址开始,到后一个偏移地址结束。若不给段地址,会用 CS 的值代替。长度格式:L+数字。如果不给长度且没有给定地址范围,则会从当前的 IP 或给定偏移地址,连续显示128个字节。如图所示。(使用时请注意 IP 的变化,但这里的 IP 变动,并不会影响寄存器 IP 。)
注:图的右边,有一个点阵。每个点或字符对应一个内存地址单元。如果这个单元中的内容能够在 ASCII 码表中查到,则显示对应字符,否则用点代替。
现在,我们来修改一下 073f:0108 这个内存单元。先查看一下,然后修改它。如图所示。

接下来,我们来看看之前写入的程序变了哪。我们来反汇编一下,把机器码翻译成汇编指令。
用到的命令是 U 命令。语法格式为:-u [地址] 。不给地址,则用CS 和 IP 代替。如图所示。

其实,变化的就是原本的2000,变为了4000。可以对照着前面的图看一下。
还有一个 R 命令。用来查看寄存器。语法格式:-r [寄存器] 。给出寄存器,则会显示给定寄存器的内容,并等待修改。寄存器缺省,则会显示所有寄存器及对应的内容。如图所示。
注:给出寄存器时,命令与寄存器之间有空格和没有空格,作用等价。

第二个,是将3个指令写入2000:0 开始的内存单元,利用他们计算2的8次方。如图所示。

下面介绍两个运行命令,-t 和 -g。 t命令(trace)作用是单步调试。一个指令一个指令执行。而g命令则是一次执行,不显示中间寄存器的值,直接显示运行完后所有寄存器的值。
g 命令的格式: -g=偏移地址1 偏移地址2 或 -g=偏移地址 或 -g 偏移地址 或 -g 。第一种,从偏移地址1一直执行到偏移地址2之前(不包括偏移地址2)。第二种,从偏移地址开始执行,知道程序结束或遇到 INT。第三种,从当前偏移地址执行到偏移地址之前。第四种,从 CS:IP 开始执行到程序结束或遇到 INT。
t 命令的格式:-t [偏移地址] 。给偏移地址,则从偏移地址开始单步执行。否则用IP代替。
首先修改 CS 和 IP,使其指向2000:0000。这里有两种方法,但有区别。一个使用 r 命令,此方法会直接修改寄存器的值,立即生效(使用缺省的 A 命令,写入的内存显示却还是原来的值,执行过代码之后才会正常,建议使用-a 段地址:偏移地址 。下图就是个例子,如此说来 应该是 BUG)。另一个使用 jmp 语句,但需要执行之后,才会修改 CS 和 IP 的值。 mov 语句只能修改 CS 的值并且只可以用合法的寄存器进行赋值,而不支持修改 IP 的值。如图所示。
注:对于 jmp 语句,语法格式为:jmp [段地址]:偏移地址 。执行之后,会修改 CS 和 IP 的值。段地址缺省,则会用 CS 的值代替,相当于只修改了 IP 的值。偏移地址的值,也可以用某个合法寄存器代替。


由于计算计算2的8次方,目前没有使用计数器,直接用 g 命令不好控制,所以我们用 t 命令一步步执行。由于篇幅的问题,中间过程省略,只给出开头和结尾的图。


图中ax 的值为100,即是答案,因为是十六进制,所以需要转换一下。1*16的2次方+0*16的1次方+0*16的1次方=256。
第三个,要求查看内存地址 FFF00 H~ FFFFF H 中的某几个单元,找到主板的生产日期并尝试改变它。如图所示。

结果很自然,不可能成功。因为,主板日期是写在 主板上的ROM 里的,ROM,准确的说应该是 EPROM,不支持这样子直接修改,以我的目前知道的,在软件层面上,是不支持直接修改的,只有用专门的软件或者用专门的设备。
第四个,向内存 B8100H 写入数据,如: -e b810:0 01 01 02 02 03 03 04 04 。如图所示。

为了显示效果,我重开了 debug 。得到这两张图。最后得出结论: 两个两个一组,每组第一个控制显示的字符,第二个控制颜色。


最后总结一下:
通过这次实验,我学会了debug 工具的基本使用,加深了对内存地址的了解,也明白了,计算机是怎么运作的,如何区分指令和数据的,高级语言中的循环是怎么实现的等等。原来计算机就是这么简单,但是却能让这个世界变得不一样,原因最后可能还是归功于聪明的人类吧。

浙公网安备 33010602011771号