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

Assembly 是否可以在实模式下使用32位寄存器/指令?,assembly,x86,operating-system,real-mode,Assembly,X86,Operating System,Real Mode,在研究一些简单的操作系统源代码时,我对一个简单的汇编问题感到困惑 在这个网站:下面的代码是从实际模式切换到保护模式 mov eax, cr0 or al,1 mov cr0, eax 我知道如何从实模式切换到保护模式。 但我的问题是,由于程序仍然处于实模式,它如何使用32位寄存器或指令 可以在实模式下使用32位寄存器/指令吗?据我所知,实模式不会影响可以在CPU上运行的命令,但会影响CPU内存引用命令的解释方式 因此,是的,您可以使用eax,但无法获得[eax]存储单元 请参阅中的相关部分

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

在这个网站:下面的代码是从实际模式切换到保护模式

mov  eax, cr0
or al,1
mov  cr0, eax
我知道如何从实模式切换到保护模式。
但我的问题是,由于程序仍然处于实模式,它如何使用32位寄存器或指令


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

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

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


请参阅中的相关部分。

据我所知,在实模式下,您不能使用32位寄存器。 在32位控制寄存器CR0中,实模式和保护模式通过查看CR0的第一位(PE)来确定。在此代码中,您更改最后一行(mov CR0,eax)中的PE。
我猜,在这一行之后,你不能再使用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位访问权限。

我认为您还需要清除预取程序(通常使用jmp到下一个内存位置)。是的。请注意,实模式中的32位寻址模式不会绕过64k(默认)段限制。我认为“……但您将无法获得[eax]内存单元。”不是真的。我的理解是,在实模式中,如果eax的值小于或等于0x0000FFFF,则[eax]是完全有效的访问。当您尝试访问[eax]时,eax的较大值将生成保护故障(但值得注意的是,如果[eax]会生成保护故障,[ax]不需要生成保护故障)。@Orby:
[eax]
是(实/虚)中的有效地址86模式,使用32个前缀字节。如您所述,如果eax中的值超过前64 KiB,则会发生故障。(在“非真实模式”中除外)。但是,
[ax]
在任何模式下都不是有效地址。例如,
[ebx]
[bx]
比较合适,因为两者都是有效地址(分别为a32和a16)。这是不正确的,您可以使用0x66前缀以16位/实模式访问32位寄存器。此操作码几乎没有记录,在大多数现代CPU上,其编码语义已被指令
sysret
取代。