assembly - x86 子指令操作码混淆

标签 assembly x86 tasm opcode instruction-encoding

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

29 C3

正确到 sub bx, ax。然而,Turbo Assembler 将相同的指令 sub bx, ax 汇编为以下单词

2B D8

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

注意: 我知道像 jejz 这样的条件跳转具有相同的操作码,因为它们具有相同的标志相关行为和不同的助记符是用来反射(reflect)同一个操作的不同语义的,但前者让我很困惑。

最佳答案

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

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

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

关于assembly - x86 子指令操作码混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68882519/

相关文章:

ios - 在 ARM 组件中使用堆栈指针(sp)

c - 同一内存地址处的两个不同值 - 汇编

c++ - 移动__m128的上下 float

c - 如何使用 ptrace 找到 CALL 和 RET 号码?

performance - x86 bsr/bsf 如何具有固定延迟,而不依赖于数据?它不是像伪代码显示的那样循环遍历位吗?

assembly - 在 x86 NASM 或 YASM 程序集中实现选择排序的问题

C++ 和内联汇编代码在一个程序中具有相同的输出,但在另一个程序中具有不同的输出

assembly - 汇编程序编译错误

程序集 - 程序按预期工作,但第二次运行时,打印出乱码

assembly - 编译汇编语言