user-0 提问: 《自己动手编写操作系统》中的第4章读取扇区的示例程序似乎无法正确运行

回复:
user: user-0
content: 先记录一个小情况。 今天再次添加一个打印，目的仍然是把wRootDirSizeForLoop的值打印出来，对之前的DispStr1进行了少许修改，主要是添加了对es附值为0的语句，函数的调用如下：  LABEL_SEARCH_IN_ROOT_DIR_BEGIN:         mov     ax, word [wRootDirSizeForLoop]         add     ax, 0x30         mov     [StringBuf], ax         call DispStr1  由于我没有把wRootDirSizeForLoop的值转换成可显示的字符串，所以这里我对这个数字加上了0x30以便能够显示出来，当然超过9的就暂不管它是否可以正常显示了。 其中的StringBuf定义如下：  StringBuf               db      "tempbuf "   DispStr1的函数如下：  DispStr1:         push    es         mov     ax, 0         mov     es, ax         mov     dh, [StringBuf]         sub     dh, 0x30         ; 这一行会改变显示效果 	mov	ax, StringBuf 	mov	bp, ax			; ┓ 	mov	cx, 8            	; CX = 串长度 	mov	ax, 01301h		; AH = 13,  AL = 01h 	mov	bx, 0007h		; 页号为0(BH = 0) 黑底白字(BL = 07h) 	mov	dl, 0 	int	10h			; int 10h 	pop     es 	ret  其中注意对dh的操作，如果我不对dh附值，即dh值为0时，最终的打印如下:  打印全部集中在第一行的开始位置。 如果dh被附值，如代码所示(注意减去0x30是因为在调用函数的时候加了0x30)，则打印结果如下:  这样就可以清楚 地看到值确实在一次次地减小了。  本次记录有两点： 1. 在显示之前，需要清空es的值，否则显示的内容是空 2. 如果要改变显示输出的行，改变dh的值为对应行号即可

user: user-0
content: 今天再试，一样，bochs还是可以正常通过，即打印 NO LOADER，昨天和今天，vmware都仍然还是不可以

user: user-0
content: 我不知道是怎么回事，有两个使我糊涂的情况： 1. 就像上面说的那些情况，时好时坏，我把后面的dx、cx变量也附什给wDigBuf就没有出现过问题。这个问题暂时先不用管它了，反正也能跑出结果了。 2. 如果我直接运行，它就什么也没有打印，如果我仔细地单步运行一整次，关键似乎是要每次在  cmp    word [wRootDirSizeForLoop], 0  这一行断点停住，它就能跑出结果为NO LOADER，然后我再重新启动不用断点也会有这个结果了(有这个结果才是正常的，因为我没有把loader写入进来)，晕死了，这个在两台电脑上都是一样的情况，我真糊涂了

user: user-1
content: 引用 7 楼 jszj 的回复:call DispStr1 这一行是我添加的，它没有内容打印出来，可能还是我写的不对，这一行暂不追究。  今天下午上网上搜索了一下： http://www.cnblogs.com/hongzg1982/articles/2116643.html 说明了如何调试这种程序，采用bochs，终于可以单步运行了。 我用的是2.6.8版本的。 现在基本上发现似乎是dx、cx的计数总是不对，循环了多遍，这两个寄存器的值硬是没有减小！对应的打印如下： (0) [0x000000007c84] 0000:7c84 (unk, ctxt): dec dx                                   ;4a 我想后面的那个4a应该就是dx的值，如果是，那我发现每次循环到这里，这个值一直不变！所以这个搜索的循环就没办法退出来，晕死了。有用过的大侠出来指点一二 我打印寄存器的值，似乎看不到dx、cx  另外一个命令：  rcx rdx后面 就是cx dx的值吧

user: user-0
content: 似乎看不到，如下所示：  这一语句已经把0x31送入到了AL中，但在显示的寄存器中却看不到有哪个是0x31的值

user: user-1
content: 引用 14 楼 jszj 的回复:有点糊涂了，我再把wDigBuf的会子值改为  mov     word [wDigBuf], SectorNoOfRootDirectory  也能成功了，这不是在耍我吗？Bochs!  你比原来多执行了一条指令嘛，看来我的猜测是对的：显示的是准备但还没有执行的指令

user: user-0
content: 引用 12 楼 wang0635 的回复:注意，显示的指令是刚刚执行过的那一条呢，还是下一条？如果是后者，就没有问题了 这个还真没有注意呢

user: user-0
content: 有点糊涂了，我再把wDigBuf的会子值改为  mov     word [wDigBuf], SectorNoOfRootDirectory  也能成功了，这不是在耍我吗？Bochs!

user: user-0
content: 再试了一次，把附值方式修改成个数字：  mov word [wSectorNo], SectorNoOfRootDirectory mov word [wDigBuf], 17  结果就附值成功了：   和上面的对比的结果，结论是为什么一个变量不能同时给另外两个变量附值？

user: user-1
content: 注意，显示的指令是刚刚执行过的那一条呢，还是下一条？如果是后者，就没有问题了

user: user-0
content: 刚刚只把两个附值的语句调换了一下顺序，即：  mov     word [wDigBuf], SectorNoOfRootDirectory mov	word [wSectorNo], SectorNoOfRootDirectory  结果wSectorNo附值失败了：  原来是第二个附值失败，和变量没啥关系。 那这又是咋回事呢？奇怪了

user: user-0
content: 为了把值打印出来，新定义了一个变量wDigBuf，其形式和wSectorNo完成一样：  然后在开始的位置同wSectorNo一样附值：  结果wSectorNo附值成功，而新变量wDigBuf不成功：  这是什么情况？好奇怪

user: user-2
content: 好像是可以的，有人做过，你再仔细研究研究！

user: user-0
content: 引用 3 楼 zhao4zhong1 的回复:楼主要不学学怎么使用WinDbg或Turbo Debug远程连接调试实体DOS或虚拟DOS机的启动过程？ 仅是建议，因为我也没实际做过。 暂时对这个兴趣不太大，呵呵 如果要弄，估计还得有很多工具什么需要准备的，相当麻烦 我准备依照前面一个章节中打印内存内容的办法来试试

user: user-0
content: call DispStr1 这一行是我添加的，它没有内容打印出来，可能还是我写的不对，这一行暂不追究。  今天下午上网上搜索了一下： http://www.cnblogs.com/hongzg1982/articles/2116643.html 说明了如何调试这种程序，采用bochs，终于可以单步运行了。 我用的是2.6.8版本的。 现在基本上发现似乎是dx、cx的计数总是不对，循环了多遍，这两个寄存器的值硬是没有减小！对应的打印如下： (0) [0x000000007c84] 0000:7c84 (unk, ctxt): dec dx                                   ;4a 我想后面的那个4a应该就是dx的值，如果是，那我发现每次循环到这里，这个值一直不变！所以这个搜索的循环就没办法退出来，晕死了。有用过的大侠出来指点一二 我打印寄存器的值，似乎看不到dx、cx  另外一个命令：

user: user-3
content: 写汇编代码啊？  call DispStr1 正常返回了吗。

user: user-4
content: 楼主要不学学怎么使用WinDbg或Turbo Debug远程连接调试实体DOS或虚拟DOS机的启动过程？ 仅是建议，因为我也没实际做过。

user: user-0
content: 引用 1 楼 zhao4zhong1 的回复:（Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 下载了Turb Debugger，但似乎用不好。情况如下 需要在dos运行它(tb)，这不是关键，关键是编译出来的程序需要在dos下运行而不能在windows下运行。这个编译本身没有问题，很容易，但编译出来.com文件后要把它放到虚拟机的dos中，这个vpc无法访问我的主机windows，所以没有办法运行.com文件，而只能编译成.bin写入磁盘映像文件中，然后由vpc加载此映像文件并运行其中的程序。这种情况下，这个tb似乎就没法用了。 所以，我才想加个打印把变量的值打印出来看看

user: user-4
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）