11

在研究一些简单的 os 源代码时,我对一个简单的汇编问题感到困惑。

在这个网站:http ://wiki.osdev.org/Babystep7下面的代码是从实模式切换到保护模式

mov  eax, cr0
or al,1
mov  cr0, eax

我知道如何从实模式切换到保护模式。
但我的问题是,既然程序还处于实模式,它怎么能使用 32 位寄存器或指令呢?

是否可以在实模式下使用 32 位寄存器/指令?

4

5 回答 5

19

当处理器在实模式下运行时(因为它是在启动后立即运行的),它默认为 16 位代码。但是,这并不意味着您不能使用 32 位指令。

有一个“操作数大小覆盖”前缀 (66h) 可以更改单个指令的默认模式。当此前缀与在 16 位实模式下执行的指令一起使用时,它会将指令切换到 32 位。相反,当此前缀与在 32 位保护模式下执行的指令一起使用时,它会将指令切换为 16 位。(类似的前缀 67h 用于覆盖地址大小。)

然后,使用此前缀允许您在 16 位实模式下使用 32 位寄存器。当您在汇编 16 位代码时尝试将 32 位操作数与指令一起使用时,您的汇编器几乎肯定会自动发出此前缀。

不幸的是,64 位指令没有这样的覆盖前缀,因此这些指令不能在实模式下使用。您需要切换到“长模式”以允许这些。

于 2011-08-02T22:48:21.580 回答
4

据我了解,实模式不会影响您可以在 CPU 上运行的命令,但会影响 CPU 内存引用命令的解释方式。

所以,是的,您可以使用eax,但您将无法获得[eax]存储单元。

请参阅英特尔手册中的相关部分。

于 2011-08-02T19:38:58.350 回答
0

对于简单的寻址,操作数和指令大小前缀效果很好。我曾经为 Windows(3.1 和更高版本到 9x)编写的 16 位保护(最初为实数)模式应用程序可以使用 Windows 内存 API 分配 >64K 的内存区域,问题是如何使用它。在任何情况下,使用(远)指针重击和提到的前缀我的应用程序很好地利用了 40MB 区域,即使它以 16 位模式运行。

如果您尝试类似的操作,请记住指令大小前缀启用了与 16 位不兼容的 32 位指令集。16 位通常不关心您是处于实模式还是受保护模式,除非您正在执行段算术。因此,您需要使用 emit 编写 32 位操作的代码(至少我是这样做的),因为您的编译器可能不会在没有大喊血腥谋杀的情况下生成它们。

于 2012-05-22T18:32:12.460 回答
-2

您也许可以使用LoadAll 操作码 0F07h,它为您提供 16 位实模式下的 32 位访问。

于 2012-06-05T07:26:33.043 回答
-3

据我所知,在实模式下,您不能使用 32 位寄存器。在 32 位控制寄存器 CR0 中,实模式和保护模式是通过查看 CR0 (PE) 的第一位来确定的。在此代码中,您更改最后一行 (mov cr0,eax) 中的 PE。我想,在这一行之后,你不能再使用 32 位寄存器引用了。

于 2011-08-02T19:57:48.053 回答