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位版本
raxeaxaxal/ah
rbxebxbxbl/bh
rcxecxcxcl/ch
rdxedxdxdl/dh
rsiesisisil
rdiedididil
rbpebpbpbpl
rspespspspl
r8r8dr8wr8b
r9r9dr9wr9b
r10r10dr10wr10b
r11r11dr11wr11b
r12r12dr12wr12b
r13r13dr13wr13b
r14r14dr14wr14b
r15r15dr15wr15b

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位操作系统。


樱雨楼
26 声望1 粉丝

Stay Gold