x86 子指令操作码混淆

使用 Turbo Assembler 和 Turbo Debugger 稍微玩了一下,我对操作码感到惊讶。更准确地说,我有一些组装好的二进制文件,Turbo Debugger 在其中反汇编了这个词

29 C3

正确地sub bx, ax. 但是,Turbo Assembler 将完全相同的指令组装sub bx, ax到以下单词中

2B D8

对此感到困惑,我发现这个参考文献指出从寄存器中减去寄存器可能确实以29和开头2B。是否真的可以用不同的操作码来表达完全相同的指令?如果是这样,那是为什么?是因为历史原因和兼容性吗?参考说明了操作码的不同操作数类型,它们只是sub bx, ax. 这是为了以后通过自修改代码或类似方式修补不同操作数的能力吗?此外,Turbo Assembler 是否有语法结构来选择一个操作码而不是另一个?

注意:我知道条件跳转类似je并且jz具有相同的操作码,因为它们具有相同的标志相关行为,并且不同的助记符用于反映同一操作的不同语义,但前者让我感到困惑。

回答

大多数 x86 指令支持两个操作数,其中一个操作数可以是内存操作数。这是通过在modr/m字节中编码操作数来支持的。该字节始终编码一个寄存器操作数和一个寄存器或内存 (r/m) 操作数,但指令必须决定其操作数中的哪个是寄存器操作数,哪个是内存操作数。

因此,为了支持在源操作数或目标操作数中具有内存操作数,许多指令都可以使用一种变体,其中源操作数可以是内存操作数,另一种变体可以是目标操作数。这通常由位控制01(在某些手册中称为 d 位)。

因此,不需要内存操作数的指令可以以两种方式进行编码,汇编程序通常会选择一种或另一种作为有点随机的实现细节。

  • 第一个字节的第 1 位是 `d` 方向,您可以看到这是一个区别。在第二个字节中,第 5-3 位“000”(AX)和第 2-0 位“011”(BX)被交换。

以上是x86 子指令操作码混淆的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>