前面我成功加载了第一个OS,下面我将重点分析bochs加载OS时,寄存器都做了什么?
在使用选项6启动bochs的时候,在终端输入:<bochs:1>b 0x7c00,它表示在07c000地址处设置断点,因为引导扇区是从这里开始的。然后继续输入:<bochs:2>c,表示继续执行指令。完成这两条命令,将会看到终端命令窗口显示如下信息。
Nextat t=0
(0)[0x00000000fffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b ; ea5be000f0
<bochs:1>b 0x7c00
<bochs:2>c
00000003305i[BIOS] $Revision: 1.247 $ $Date: 2010/04/04 19:33:50 $
00000318057i[KBD ] reset-disable command received
00000442371i[VBIOS]VGABios $Id$
00000442442i[VGA ] VBE known Display Interface b0c0
00000442474i[VGA ] VBE known Display Interface b0c5
00000443143i[VBIOS]VBE Bios $Id$
00000600000i[XGUI] charmap update. Font Height is 16
00000760659i[BIOS] Starting rombios32
00000761138i[BIOS] Shutdown flag 0
00000761777i[BIOS] ram_size=0x02000000
00000762239i[BIOS] ram_end=32MB
00000802861i[BIOS] Found 1 cpu(s)
00000819037i[BIOS] bios_table_addr: 0x000fbc18 end=0x000fcc00
00000831660i[BIOS] bios_table_cur_addr: 0x000fbc18
00012943044i[BIOS] Booting from 0000:7c00
(0)Breakpoint 1, 0x00007c00 in ?? ()
Nextat t=12943105
(0)[0x0000000000007c00] 0000:7c00 (unk. ctxt): mov ax, cs ; 8cc8
<bochs:3>
可以看到,当我们在0x7c00设置断点时,代码执行到此处将会停止。同时终端命令窗口还显示了下一条命令,如:
(0)[0x0000000000007c00] 0000:7c00 (unk. ctxt): mov ax, cs ; 8cc8
注意[0x0000000000007c00],表示指令的地址,即加载程序的地方(还记得org07c00h吗?)。此时,可以输入命令,查看寄存器信息。(在《Orange's...》中使用dump_cpu,这个命令在bochs2.3.5以上版本中没有)
<bochs:3>info cpu
eax:0x0000aa55 43605
ecx:0x00090000 589824
edx:0x00000000 0
ebx:0x00000000 0
esp:0x0000ffd6 65494
ebp:0x00000000 0
esi:0x000e478c 935820
edi:0x0000ffac 65452
eip:0x00007c00
eflags0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf
可以看到eip指向0x7c00,表示执行从这个地方开始。这也是为什么代码清单要是用:org07c00h
<bochs:4>sreg
es:0x0000,dh=0x00009300, dl=0x0000ffff, valid=1
Datasegment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
cs:0x0000,dh=0x00009300, dl=0x0000ffff, valid=1
Datasegment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ss:0x0000,dh=0x00009300, dl=0x0000ffff, valid=7
Datasegment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ds:0x0000,dh=0x00009300, dl=0x0000ffff, valid=1
Datasegment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
fs:0x0000,dh=0x00009300, dl=0x0000ffff, valid=1
Datasegment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000,dh=0x00009300, dl=0x0000ffff, valid=1
Datasegment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000,dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000,dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x000fb997,limit=0x30
idtr:base=0x00000000,limit=0x3ff
此时段寄存器cs、es、ds、gs等都为0。执行下一条指令(执行我编写的代码),看看寄存器状态。
<bochs:5>n
Nextat t=12943102
(0)[0x0000000000007c02] 0000:7c02 (unk. ctxt): mov ds, ax ; 8ed8
<bochs:6>r
eax:0x00000000 0
ecx:0x00090000 589824
edx:0x00000000 0
ebx:0x00000000 0
esp:0x0000ffd6 65494
ebp:0x00000000 0
esi:0x000e478c 935820
edi:0x0000ffac 65452
eip:0x00007c02
eflags0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF z
可以看到粗体标识的地方为执行:movax cs后的改变情况。同时下一条指令地址变为:[0x0000000000007c02],表示mov指令占用2个地址。后面的2条指令将改变寄存器ds、es。
<bochs:7>n
Nextat t=12943103
(0)[0x0000000000007c04] 0000:7c04 (unk. ctxt): mov es, ax ; 8ec0
……
<bochs:8>n
Nextat t=12943104
(0)[0x0000000000007c06] 0000:7c06 (unk. ctxt):call .+2 (0x00007c0b) ; e80200
此时下一条指令为:call.+2 (0x00007c0b),其中0x00007c0b表示要跳转的地址。继续执行,n将会跳出方法继续。方法中将会调用int 10中断在显示器上显示字符。
<bochs:9>n
Next at t=12954683
(0)[0x0000000000007c09]0000:7c09 (unk. ctxt): jmp .-2 (0x00007c09)
从这句可以看出$表示当前地址。
<bochs:10> n
Next at t=12954684
(0) [0x0000000000007c09] 0000:7c09(unk. ctxt): jmp .-2 (0x00007c09) ; ebfe
因为跳转地址为执行语句地址,所以陷入无限循环。