在研究一些简单的os源代码时,我对一个简单的汇编问题感到困惑。
在本网站中:http://wiki.osdev.org/Babystep7以下代码是从实模式切换到保护模式
mov eax, cr0
or al,1
mov cr0, eax
我知道如何从真实模式切换到保护模式 但我的问题是,由于程序仍然处于实模式,它如何使用32位寄存器或指令?
是否可以在实模式下使用32位寄存器/指令?
答案 0 :(得分:7)
当处理器以实模式运行时(因为它在启动后立即运行),它默认为16位代码。但是,这 not 意味着您无法使用32位指令。
有一个“操作数大小覆盖”前缀(66h),用于更改单个指令的默认模式。当此前缀与在16位实模式下执行的指令一起使用时,它会将指令切换为32位。相反,当此前缀与在32位保护模式下执行的指令一起使用时,它会将指令切换为16位。 (类似的前缀67h用于覆盖地址大小。)
然后,使用此前缀允许您在16位实模式下使用32位寄存器。当你在组装16位代码时尝试使用带有指令的32位操作数时,你的汇编器几乎肯定会自动发出这个前缀。
不幸的是,64位指令没有这样的覆盖前缀,因此不能在实模式下使用。您需要切换到“长模式”以允许这些。
答案 1 :(得分:5)
据我了解,实模式不会影响您可以在CPU上运行的命令,但它会影响CPU内存引用命令的解释方式。
所以,是的,您可以使用eax
,但是您将无法获得[eax]
内存单元格。
参见Intel's Manual中的相关部分。
答案 2 :(得分:0)
据我所知,在实模式下,你不能使用32位寄存器。 在32位控制寄存器CR0中,实模式和保护模式通过查看CR0(PE)的第一位来确定。在此代码中,您更改最后一行中的PE(mov cr0,eax)。 我想,在这一行之后,你不能再使用32位寄存器引用了。
答案 3 :(得分:0)
对于简单寻址,操作数和指令大小前缀工作得非常好。我曾经为Windows(3.1及更高版本到9x)编写的16位受保护(初始实时)模式应用程序可以使用Windows内存API分配> 64K内存区域,问题是如何使用它。在任何情况下使用(远)指针thunking和提到的前缀我的应用程序很好地利用了40MB区域,即使它以16位模式运行。
如果你尝试类似的东西,请记住指令大小前缀使能与16位不兼容的32位指令集。除非您正在进行分段算术,否则16位通常不关心您是处于实际模式还是保护模式。所以你需要使用emit来处理代码(至少我做过)32位操作,因为你的编译器可能不会在没有大肆宣传血腥谋杀的情况下生成它们。
答案 4 :(得分:0)
存在32位实模式,称为unreal mode。在那些时候,它被用来获得对整个地址空间的访问,而没有使用选择器和整个保护模式开销的麻烦。
答案 5 :(得分:0)
你可以使用LoadAll 操作码0F07h ,它可以在16位实模式下提供32位访问。