18.1 引言
我们已经实现了一个运行在保护模式下的操作系统,然而,读者朋友也许不会满足:如今早已是多核CPU,64位操作系统的时代,而我们的操作系统仅仅是单核CPU,32位的。因此,从本章开始,我们将在32位单核操作系统的基础上,将其升级为一个64位多核操作系统。
18.2 准备工作
我们仍然使用bochs
虚拟机作为操作系统的运行和调试环境。但其编译命令需要增加一些选项:
- 对于
bochs
:./configure --prefix=... --enable-x86-64 --enable-smp && make -jN && make install
- 对于
bochsdbg
:./configure --prefix=... --enable-debugger --enable-x86-64 --enable-smp && make -jN && make install
新增的--enable-x86-64
选项用于启用64位模式;--enable-smp
选项用于启用多处理器模式。
此外,bochsdbg
的-rc
参数是一个很实用的功能,其可以使bochsdbg
在启动时自动执行一串调试命令,建议读者根据需要自行配置这个参数。
18.3 64位寄存器
64位CPU的通用寄存器宽度是64位的,不仅如此,其还新增了8个通用寄存器r8 ~ r15
,并拓展了现有寄存器的用法:现在,所有的寄存器都有8、16、32、64位版本。这些寄存器如下表所示:
64位版本 | 32位版本 | 16位版本 | 8位版本 |
---|---|---|---|
rax | eax | ax | al/ah |
rbx | ebx | bx | bl/bh |
rcx | ecx | cx | cl/ch |
rdx | edx | dx | dl/dh |
rsi | esi | si | sil |
rdi | edi | di | dil |
rbp | ebp | bp | bpl |
rsp | esp | sp | spl |
r8 | r8d | r8w | r8b |
r9 | r9d | r9w | r9b |
r10 | r10d | r10w | r10b |
r11 | r11d | r11w | r11b |
r12 | r12d | r12w | r12b |
r13 | r13d | r13w | r13b |
r14 | r14d | r14w | r14b |
r15 | r15d | r15w | r15b |
64位CPU有一个特殊设定:当向一个32位寄存器传送时,其高32位将被自动清零。也就是说,不需要也不存在这样的指令:movzx 64位寄存器, 32位寄存器
;然而,movsx 64位寄存器, 32位寄存器
与此设定不矛盾,故仍然存在。
标志寄存器也拓展至64位,被称为rflags
。然而,由于其低32位都还没用完,因此拓展出的高32位均为保留位。
指令指针寄存器也拓展至64位,被称为rip
。
18.4 64位立即数
由于机器语言层面的限制,CPU对64位立即数的支持非常差,以至于只需要以下规则就能描述:
mov 64位寄存器, 64位立即数
是唯一支持64位立即数的指令- 其他指令如果强行使用64位立即数,也只会取其低32位
也就是说,很多非常依赖立即数的指令,如内存访问,加减法,位运算等,都不能使用64位立即数,而是需要先使用mov
指令进行周转。
18.5 RIP相对寻址
64位CPU新增了一种内存访问模式,被称为RIP相对寻址。具体来说:在nasm语法中,[标号]
和[abs 标号]
表示的是普通的内存寻址模式,此时,标号的值就是内存地址;[rel 标号]
表示的是新增的RIP相对寻址,此时,该指令会被编译器转换为[rip + 标号相对于rip的偏移量]
。这样做的好处在于:64位模式下,直接使用[标号]
是有风险的,因为标号很有可能是一个超过32位的立即数,不过,由于标号往往离rip
比较近,相对偏移量较小,故不会超过32位的限制。
在nasm中,可以通过声明[default rel]
将所有的[标号]
都视为[rel 标号]
。
需要注意的是,RIP相对寻址只适用于[标号]
这种形式,其他形式,如:[寄存器 + 标号]
,[64位立即数]
等,都是不适用于RIP相对寻址的,这是因为这些指令都无法确定地址与rip
的相对偏移量。
本章讨论了64位CPU的寄存器和内存寻址,64位CPU的其他特点将在后续章节中讨论。从下一章开始,我们将正式开始实现64位操作系统。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。