在研究一些简单的 os 源代码时,我对一个简单的汇编问题感到困惑。
在这个网站:http ://wiki.osdev.org/Babystep7下面的代码是从实模式切换到保护模式
mov eax, cr0
or al,1
mov cr0, eax
我知道如何从实模式切换到保护模式。
但我的问题是,既然程序还处于实模式,它怎么能使用 32 位寄存器或指令呢?
是否可以在实模式下使用 32 位寄存器/指令?
在研究一些简单的 os 源代码时,我对一个简单的汇编问题感到困惑。
在这个网站:http ://wiki.osdev.org/Babystep7下面的代码是从实模式切换到保护模式
mov eax, cr0
or al,1
mov cr0, eax
我知道如何从实模式切换到保护模式。
但我的问题是,既然程序还处于实模式,它怎么能使用 32 位寄存器或指令呢?
是否可以在实模式下使用 32 位寄存器/指令?
当处理器在实模式下运行时(因为它是在启动后立即运行的),它默认为 16 位代码。但是,这并不意味着您不能使用 32 位指令。
有一个“操作数大小覆盖”前缀 (66h) 可以更改单个指令的默认模式。当此前缀与在 16 位实模式下执行的指令一起使用时,它会将指令切换到 32 位。相反,当此前缀与在 32 位保护模式下执行的指令一起使用时,它会将指令切换为 16 位。(类似的前缀 67h 用于覆盖地址大小。)
然后,使用此前缀允许您在 16 位实模式下使用 32 位寄存器。当您在汇编 16 位代码时尝试将 32 位操作数与指令一起使用时,您的汇编器几乎肯定会自动发出此前缀。
不幸的是,64 位指令没有这样的覆盖前缀,因此这些指令不能在实模式下使用。您需要切换到“长模式”以允许这些。
对于简单的寻址,操作数和指令大小前缀效果很好。我曾经为 Windows(3.1 和更高版本到 9x)编写的 16 位保护(最初为实数)模式应用程序可以使用 Windows 内存 API 分配 >64K 的内存区域,问题是如何使用它。在任何情况下,使用(远)指针重击和提到的前缀我的应用程序很好地利用了 40MB 区域,即使它以 16 位模式运行。
如果您尝试类似的操作,请记住指令大小前缀启用了与 16 位不兼容的 32 位指令集。16 位通常不关心您是处于实模式还是受保护模式,除非您正在执行段算术。因此,您需要使用 emit 编写 32 位操作的代码(至少我是这样做的),因为您的编译器可能不会在没有大喊血腥谋杀的情况下生成它们。
您也许可以使用LoadAll 操作码 0F07h,它为您提供 16 位实模式下的 32 位访问。
据我所知,在实模式下,您不能使用 32 位寄存器。在 32 位控制寄存器 CR0 中,实模式和保护模式是通过查看 CR0 (PE) 的第一位来确定的。在此代码中,您更改最后一行 (mov cr0,eax) 中的 PE。我想,在这一行之后,你不能再使用 32 位寄存器引用了。