windows - x86 32 位汇编代码是否有效 x86 64 位汇编代码?

标签 windows assembly binary x86

Is all x86 32-bit assembly code valid x86 64-bit assembly code?



我想知道 32 位汇编代码是否是 64 位汇编代码的子集,即每个 32 位汇编代码都可以在 64 位环境中运行?

我想答案是肯定的,因为 64 位 Windows 能够执行 32 位程序,但后来我看到 64 位处理器支持 32 位兼容模式?

如果不是,请提供一个不是有效 64 位汇编代码的 32 位汇编代码的小例子,并解释 64 位处理器如何执行 32 位汇编代码。

最佳答案

现代 x86 CPU 具有三种主要操作模式(此描述已简化):

  • 在实模式下,CPU 在禁用分页和分段的情况下执行 16 位代码。代码中的内存地址是指物理地址,段寄存器的内容被移位并添加到地址中以形成有效地址。
  • 在保护模式下,CPU 根据 CS(代码段)寄存器中的段选择器执行 16 位或 32 位代码。启用分段,可以(通常是)启用分页。程序可以通过跳转到适当的段来在 16 位和 32 位代码之间切换。 CPU 可以进入子模式虚拟 8086 模式以从 protected 模式操作系统内部模拟单个进程的实模式。
  • 在长模式下,CPU 执行 64 位代码。大多数情况下禁用分段,启用分页。 CPU 可以进入子模式兼容模式以从为长模式编写的操作系统内执行 16 位和 32 位保护模式代码。兼容模式是通过远跳转到具有适当位设置的 CS 选择器来进入的。虚拟 8086 模式不可用。

  • 维基百科有一个不错的表 x86-64 operating modes包括传统模式和实模式,以及长模式的所有 3 个子模式。在主流的 x86-64 操作系统下,启动后 CPU 内核将始终处于长模式,根据 32 位或 64 位用户空间在不同的子模式之间切换。 (不包括系统管理模式中断......)

    现在 16 位、32 位和 64 位模式有什么区别?
    16 位和 32 位模式基本上是一样的,除了以下区别:
  • 在 16 位模式下,默认地址和操作数宽度为 16 位。您可以分别使用 0x67 和 0x66 前缀将这些更改为单个指令的 32 位。在 32 位模式下,情况正好相反。
  • 在 16 位模式下,指令指针被截断为 16 位,跳转到高于 65536 的地址会导致奇怪的结果。
  • VEX/EVEX 编码指令(包括 AVX、AVX2、BMI、BMI2 和 AVX512 指令集的指令)不会在真实或虚拟 8086 模式下解码(尽管它们在 16 位保护模式下可用)。
  • 16 位模式比 32 位模式具有更少的寻址模式,但如果需要,可以在每条指令的基础上覆盖到 32 位寻址模式。

  • 现在,64 位模式有些不同。大多数指令的行为就像在 32 位模式下一样,但有以下区别:
  • 还有八个名为 r8、r9、...、r15 的附加寄存器。每个寄存器都可以用作字节、字、双字或 qword 寄存器。 REX 前缀系列(0x40 到 0x4f)对操作数是指旧寄存器还是新寄存器进行编码。八个额外的 SSE/AVX 寄存器 xmm8、xmm9、...、xmm15 也可用。
  • 您只能推送/弹出 64 位和 16 位数量(尽管您不应该执行后者),不能推送/弹出 32 位数量。
  • 单字节 inc regdec reg指令不可用,它们的指令空间已重新用于 REX 前缀。两字节 inc r/mdec r/m仍然可用,所以 inc regdec reg仍然可以编码。
  • 存在一种新的指令指针相对寻址模式,使用 32 位模式必须使用的 2 种冗余方式中较短的一种来编码 [disp32]绝对地址。
  • 默认地址宽度为 64 位,可以通过 0x67 前缀选择 32 位地址宽度。 16 位寻址不可用。
  • 默认操作数宽度为 32 位。可以通过 0x66 前缀选择 16 位宽度,可以通过适当的 REX 前缀选择 64 位宽度,而与您使用的寄存器无关。
  • 无法使用 ah , bh , ch , 和 dh在需要 REX 前缀的指令中。 REX 前缀导致这些寄存器编号改为表示寄存器的低 8 位 si , di , sp , 和 bp .
  • 写入 64 位寄存器的低 32 位会清除高 32 位,避免乱序 exec 的错误依赖。 (写入 8 位或 16 位部分寄存器仍然与 64 位旧值合并。)
  • 由于分段不起作用,除 fs 外,分段覆盖是无意义的无操作和 gs覆盖 (0x64, 0x65) 用于支持线程本地存储 (TLS)。
  • 此外,许多专门处理分段的指令不可用。它们是:push/pop seg (除了 push/pop fs/gs ),arpl , call far (只有 0xff 编码有效),les , lds , jmp far (只有 0xff 编码有效),
  • 处理十进制算术的指令不可用,它们是:daa , das , aaa , aas , aam , aad ,
  • 此外,以下说明不可用:bound (很少使用),pusha/popa (不适用于附加寄存器),salc (未记录),
  • 0x80 的 0x82 指令别名无效。
  • 在早期的 amd64 CPU 上,lahfsahf不可用。

  • 这基本上就是全部!

    关于windows - x86 32 位汇编代码是否有效 x86 64 位汇编代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44089163/

    相关文章:

    windows - 安装boost.log(使用代码块12.11 + gcc 4.7.1的Windows 7)

    javascript - Web Assembly 编译 C 文件时出现内联汇编语言错误

    binary - 为什么我们不使用 base64 而不是十六进制?

    c - c中的二分查找-必须找出键的所有数组位置

    python - 让 Python 响应 Windows 时区变化

    windows - 创建新目录并导航到其中(Windows CMD)

    c++ - 关于交叉编译的查询,从Windows到Linux以及从Linux到Windows,

    assembly - 直接和间接寻址以及偏移量

    c - 处理器如何知道断点?

    binary - Erlang 二进制分割