1

我正在编写一些实模式代码并使用 32 位寄存器来执行此操作(使用 0x66 前缀)。

我一直在查看英特尔的手册,但找不到我要查找的信息。请参阅: http: //www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html(我已经浏览了第 1 卷第 1-7 章,以及第 2 卷的具体说明)

英特尔是否保证实模式代码中以下代码的特定行为?它与保护模式代码相同吗?

mov eax, <some constant>
mov ebx, <some constant>
add ax, bx ; Are the top bits of ax zero'd, sign extended or left?
mov ax, <some constant> ; Does this leave top 16bits unchanged?
; From what I can tell, the top 16bits are unchanged, but where is this documented?

注意:我并不关注具体实现的行为方式(即检查它的代码——除非每个实现都始终行为相同),而英特尔已经记录了这种行为。

相关:x86_64 寄存器 rax/eax/ax/al 覆盖完整的寄存器内容

有何不同:这个问题特别与实模式操作有关,以及来自链接问题的观察结果在实模式下是否有效。

谁能帮我找到在哪里可以找到实模式代码的文档?

4

2 回答 2

1

Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1: Basic Architecture的第 3.4.1 节或多或少记录了 16 位和 8 位备用寄存器名称仅访问其各自子部分的事实:

如图 3-5 所示,通用寄存器的低 16 位直接映射到 8086 和 Intel 286 处理器中的寄存器集,可以用名称 AX、BX、CX、DX、BP、SI 来引用、DI 和 SP。EAX、EBX、ECX 和 EDX 寄存器的低两个字节中的每一个都可以通过名称 AH、BH、CH 和 DH(高字节)和 AL、BL、CL 和 DL(低字节)来引用。

图 3-5

由于文档没有将这些备用寄存器描述为访问寄存器指定部分以外的任何内容,因此没有理由假设它们会访问。另请注意,第 3.4.1 节适用于处理器的所有操作模式(64 位模式除外),因此它也包括实模式。

第 3.4.1.1 节介绍了 64 位模式下发生的情况,您链接的帖子中描述的行为来自:

在 64 位模式下,操作数大小决定目标通用寄存器中的有效位数:
  • 64 位操作数在目标通用寄存器中生成 64 位结果。
  • 32 位操作数生成 32 位结果,在目标通用寄存器中零扩展为 64 位结果。
  • 8 位和 16 位操作数生成 8 位或 16 位结果。目标通用寄存器的高 56 位或 48 位(分别)不被操作修改。如果 8 位或 16 位操作的结果用于 64 位地址计算,则将寄存器显式符号扩展为完整的 64 位。

值得注意的是,8 位和 16 位备用寄存器在 64 位模式下的工作方式与在其他模式下的工作方式相同。

最后,即使处理器不会在您不期望的情况下隐式擦除寄存器的高 16 位,您也不一定要依赖您正在执行的环境来不这样做。在 MS-DOS 下,使用 32 位寄存器的高 16 位并不总是安全的,因为你永远不知道什么时候调用、中断服务程序或 TSR 会改变它们。各种调用约定和接口只定义了哪些 16 位寄存器被保留和修改,他们很少提到高 16 位发生了什么。

于 2014-09-23T06:54:59.180 回答
0

前 16 位的内容保持不变。零扩展( MOVZX)和符号扩展(MOVSX )有单独的指令。我确信在某处记录了 ax 指的是 eax 寄存器的低 16 位,在这种情况下,零扩展将是 x86_64 中的“非默认”行为。x86_64 文档中也清楚地说明了这种行为。

于 2014-09-23T06:19:41.460 回答