最近开始看《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, ax 10 mov cx, 16 11 mov ax, 01301h 12 mov bx, 000ch 13 mov dl, 0 14 int 10h 15 ret 16 BootMessage: db "Hello, OS World!" 17 times 510-($-$$) db 0 18 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, Accessed cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
然后我们可以将初始化段寄存器的语句删除,重新编译后在虚拟机中运行,可以看到程序成功运行,初始化段寄存器语句的有无不影响程序在x86_64架构上的运行。
Orange'S初始化段寄存器
时间: 2024-11-05 12:25:42