首页 > 解决方案 > x86 子指令操作码混淆

问题描述

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

29 C3

正确地sub bx, ax. 然而,Turbo Assembler 将相同的指令汇编sub bx, ax为以下字

2B D8

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

注意:我知道条件跳转喜欢jejz具有相同的操作码,因为它们具有相同的标志相关行为,并且存在不同的助记符以反映同一操作的不同语义,但前者让我感到困惑。

标签: assemblyx86tasmopcodeinstruction-encoding

解决方案


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

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

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


推荐阅读