首页 > 代码库 > Orange'S初始化段寄存器

Orange'S初始化段寄存器

最近开始看《Orange‘S:一个操作系统的实现》,但因为不了解汇编,看第一个启动扇区的代码时就有疑惑:

1. 为了把cs中的值复制到ds和es中,首先需要将cs中的值复制到ax中,为什么不能直接复制?

2. mov ax, cs; mov ds, ax; mov es, ax;这三句初始化段寄存器的语句的意义是什么?

 1         org     07c00h 2         mov     ax,     cs 3         mov     ds,     ax 4         mov     es,     ax 5         call    DispStr 6         jmp     $ 7 DispStr: 8         mov     ax,     BootMessage 9         mov     bp,     ax10         mov     cx,     1611         mov     ax,     01301h12         mov     bx,     000ch13         mov     dl,     014         int     10h15         ret16 BootMessage:    db      "Hello, OS World!"17         times   510-($-$$)      db      018         dw      0xaa55

查了一些资料,对这两个问题有了一个基本的认识,但非常具体的细节因为不了解汇编还是不能解释。

对于问题1,intel x86架构就不允许mov的操作数为两个段寄存器,从nasm支持的操作中也找不到mov reg_sreg reg_sreg,至于为什么不支持,intel x86_64架构手册太繁杂了,就没找。

对于问题2,ds和es寄存器都是用来指示数据段位置的,所以在程序开始时,应该把它们初始化为正确的段地址,这样在程序中我们才可以正确地找到数据。但在小程序中,数据段和代码段一般都是同一个段,所以我们把cs中的值复制到ds和es中也就正确地初始化了ds和es。(所以基于此我猜测程序载入时cs会自动初始化为正确的代码段位置,下面对字符串的操作也应该会涉及到ds和es。找不到很明确的资料,反汇编boot.bin后下面的汇编我也不是很明白。)但是,这是在之前段寄存器还用来存储段位置的时候,现在在x86体系下,寄存器的位数已经足够寻址整个内存,所以段寄存器也就不再需要存储段位置。

我们可以在bochs中调试这段启动扇区代码,在x86_64的硬件架构上,cs,ds,es中的值始终是0。

es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedcs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedfs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedgs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

然后我们可以将初始化段寄存器的语句删除,重新编译后在虚拟机中运行,可以看到程序成功运行,初始化段寄存器语句的有无不影响程序在x86_64架构上的运行。

Orange'S初始化段寄存器