assembly - x86 子指令操作码混淆
问题描述
玩了一下 Turbo Assembler 和 Turbo Debugger,我对操作码感到惊讶。更准确地说,我有一些组装的二进制文件,其中 Turbo Debugger 反汇编了这个词
29 C3
正确地sub bx, ax
. 然而,Turbo Assembler 将相同的指令汇编sub bx, ax
为以下字
2B D8
对此感到困惑,我发现这个参考文献指出从寄存器中减去寄存器确实可能以29
and开头2B
。真的是完全相同的指令可以用不同的操作码来表达吗?如果是这样,那是为什么?是因为历史原因和兼容性吗?参考说明了操作码的不同操作数类型,它们只是在sub bx, ax
. 这是为了以后通过自修改代码等修补不同操作数的能力吗?此外,Turbo Assembler 是否具有语法结构来选择一个操作码而不是另一个操作码?
注意:我知道条件跳转喜欢je
并jz
具有相同的操作码,因为它们具有相同的标志相关行为,并且存在不同的助记符以反映同一操作的不同语义,但前者让我感到困惑。
解决方案
大多数 x86 指令支持两个操作数,其中一个操作数可以是内存操作数。这通过在modr/m字节中编码操作数来支持。该字节始终编码一个寄存器操作数和一个寄存器或内存 (r/m) 操作数,但指令必须确定其操作数中的哪个是寄存器操作数,哪个是内存操作数。
因此,为了支持在源操作数或目标操作数中包含内存操作数,许多指令都可以使用一种变体,其中源操作数可以是内存操作数,而另一种变体可以是目标操作数。这通常由位控制01
(在某些手册中称为 d 位)。
因此,不需要内存操作数的指令可以以两种方式编码,汇编程序通常会选择其中一种作为有点随机的实现细节。
推荐阅读
- dart - 在流构建器列表视图中显示文档快照的引用
- php - 重新启动 PHP 数组索引
- java - 如何从 MySQL DATETIME 转换为 java.time.Instant 并在系统默认时区显示给用户?
- node.js - Node js API nginx webserver AWS 负载均衡器
- javascript - 简单的反应组件无法读取状态
- python - 使用 matplotlib 和 Axes3D 标记绘制的日期
- java - 如何在运行时更改 JSON 文件中的值?
- for-loop - Delphi中C++ For命令中的预增量(++i)有什么等价物?
- django - Django:我如何发送一封包含联系表单中所有输入的描述的电子邮件?
- javascript - 如何在 React 中显示 Draft.js 格式化的数据?