如果 x86-64 中没有兼容模式开关,我能保证不会遇到非 64 位指令吗?

Am I guaranteed to not encounter non-64-bit instructions if there are no compatibility mode switches in x86-64?

我知道 64 位程序理论上可以通过将 CS 更改为 来切换到 32 位模式,我认为这也适用于切换到 16 位模式。

  1. 如果我 运行 一个我知道的 64 位程序没有兼容性开关,我能保证不会 运行 进入非 64 位指令吗?

  2. 我知道 66 和 67 十六进制前缀可以在 16 位和 32 位模式之间切换指令 (pg 36),但是这些前缀不会在 64 位模式下显示,正确?

  3. 如果我错了,我在 64 位执行中可能会遇到哪些非 64 位指令?

我的目标是编写一个 x86-64 解码器,我想知道仅处理 64 位指令案例是否足以满足我的用例(64 位程序)。

机器代码的每个字节序列要么解码为指令,要么引发 #UD 非法指令异常。对于 64 位模式下的 CPU,这意味着如果它们没有出错,它们将被解码为 64 位模式指令。另见 (不,不是一般情况)。

如果它是编译器发出的正常程序,它的机器代码中不太可能有任何非法指令,除非有人使用内联汇编,或者使用你的程序反汇编非代码部分。或者是一个将部分指令放在实际跳转目标之前的混淆程序,因此简单的反汇编程序会混淆并使用与实际不同的指令边界进行解码 运行。 x86机器码是字节流,不能自同步。

TL:DR: 在正常程序中,是的,反汇编时遇到的每个字节序列都是有效的 64 位模式指令。


6667 切换 模式 ,它们只是切换该指令的操作数大小。例如66 40 90 仍然是 64 位模式下的 REX 前缀(对于后面的 NOP 指令)。所以它只是一个 nop (xchg ax,ax),不会像在 32 位 模式 中那样覆盖它进行解码,如 inc ax / xchg eax,eax.

尝试先用 nasm -felf32 组装然后反汇编 db 0x66, 0x40, 0x90,然后用 nasm -felf64 看看同一个序列在 64 位模式下是如何解码的,而不是在 32 位模式下 模式.

许多指令编码在 32 位和 64 位模式下都是相同的,因为它们共享相同的默认操作数大小(对于非堆栈指令)。例如b8 39 30 00 00 mov eax,0x3039 是 32 位或 64 位模式下 mov eax, 12345 的代码。

(当你说“64位指令”时,我希望你不是指64位操作数大小,因为事实并非如此。所有操作数大小对于大多数指令,从 8 位到 64 位都可以在 64 位模式下进行编码。)


是的,可以安全地假设用户-space 程序不会通过远 jmp 来切换模式。除非你在 Windows,否则 WOW64 DLL 出于某种原因会这样做,而不是直接调用内核。 (Linux 有 32 位用户-space 使用 sysenter 或其他直接系统调用)。