【问题标题】:same assembly instruction but different machine instruction相同的汇编指令但不同的机器指令
【发布时间】:2015-12-03 16:31:00
【问题描述】:

我正在玩 x86 ISA,当我尝试使用 nasm 将一些汇编指令转换为机器指令时,我发现了一些有趣的东西。

mov [0x3412],al 
mov [0x3412], bl
mov [0x3412], cl
mov [0x3412], dl

1 00000000 A21234                  mov [0x3412], al
2 00000003 881E1234                mov [0x3412], bl
3 00000007 880E1234                mov [0x3412], cl
4 0000000B 88161234                mov [0x3412], dl

如您所见,mov [0x3412], al 是该规则的一个例外。 另外,我发现mov [0x3412], al 映射到两个不同的机器指令。

root@localhost:~/asm$ ndisasm 123
00000000  88061234          mov [0x3412],al
00000004  A21234            mov [0x3412],al

除了这条特殊指令之外,x86 中是否还有其他汇编指令映射到多个机器指令?

【问题讨论】:

  • 您偶然发现了英特尔设计的 808X 产品。 AX 是一个通用的 16 位寄存器,但英特尔将 AX(或 AH 和 AL 的高/低 8 位版本)专门用于某些操作。英特尔将 AX 寄存器视为累加器。 AX(和 AH、AL)对某些指令有特殊的编码(通常少一个字节)。您可以选择使用较短或较长的指令(对于有限的内存而言,越短越好)。除MOV外,AX/AH/AL还有ADC、ADD、AND、CMP、OR、SBB、SUB、TEST、XOR等特殊编码。
  • @MichaelPetch:这实际上是答案,而不仅仅是评论!
  • 如果你对这些东西感兴趣,你一定要看看指令集参考。
  • @MichaelPetch 谢谢你的回答,你真的帮了我。
  • 您可以阅读英特尔手册,了解哪些指令具有针对特定寄存器目标的自定义编码。

标签: assembly x86 nasm disassembly


【解决方案1】:

您所观察到的是英特尔使用 8088 处理器进行的设计考虑之一的产物。为了保持与 8088 处理器的兼容性,当今基于 x86 的处理器推进了其中一些设计考虑,尤其是与指令集相关的设计考虑。特别是英特尔决定 8088 应该以性能为代价提高内存利用率。他们创建了一个可变长度的 CISC 指令集,该指令集具有一些特殊的编码来限制某些指令的大小。这与许多使用固定长度指令但可以实现更好性能的基于 RISC 的架构(如旧的摩托罗拉 88000)不同。

速度与可变或固定长度指令集之间的权衡是因为处理器需要更多时间来解码用于实现一些较小指令编码的复杂可变长度指令。英特尔 8088 也是如此。

在较早的文献中(大约 1980 年),实现更好地利用空间的考虑更为突出。我的答案中与 AX 寄存器相关的信息来自我书架上的一本名为 8088 Assembler Language Programming: The IBM PC 的书,但其中一些信息可以在 this 等在线文章中找到。

从网上的文章来看,这个信息非常适用于使用 AX(累加器)和其他通用寄存器如 BX、CX、DX 的情况。

AX 是“累加器”;

某些操作,例如 MUL 和 DIV,要求操作数之一在累加器中。其他一些操作,例如 ADD 和 SUB,可以应用于任何寄存器(即八个通用和专用寄存器中的任何一个),但在使用累加器时效率更高。

BX 是“基”寄存器;

它是唯一可用于间接寻址的通用寄存器。例如,指令 MOV [BX], AX 使 AX 的内容存储在 BX 中给出的地址的内存位置中。

CX 是“计数”寄存器。

循环指令(LOOP、LOOPE 和 LOOPNE)、移位和循环指令(RCL、RCR、ROL、ROR、SHL、SHR 和 SAR)和字符串指令(前缀为 REP、REPE 和REPNE)都使用计数寄存器来确定它们将重复多少次。

DX 是“数据”寄存器;

它与 AX 一起用于字长的 MUL 和 DIV 操作,它还可以保存 IN 和 OUT 指令的端口号,但它主要用作存储数据的方便地方,就像所有其他通用寄存器。

正如您所见,英特尔打算将通用寄存器用于各种用途,但它们也可用于特定目的,并且通常对与其相关的指令具有特殊含义。在您的情况下,您观察到 AX 被视为 Accumulator 的事实。英特尔考虑到了这一点,并为许多指令添加了特殊的操作码,以更有效地存储完整的指令。您在 MOV 指令(使用 AX、AL)中找到了这一点,但它也适用于 ADCADDANDCMPORSBBSUB、@ 987654331@,XOR。当与 AL、AX 一起使用时,这些指令中的每一个都具有较短的操作码编码,需要少一个字节。您也可以使用较长的操作码对 AX、AL 进行编码。在你的情况下:

00000000  88061234          mov [0x3412],al
00000004  A21234            mov [0x3412],al

是相同的指令,但有两种不同的编码。

这是一个很好的 HTML x86 instruction set reference,可在线获得,但英特尔为 IA-32(i386 等)和 64 位架构提供了非常详细的 instruction reference

【讨论】:

  • 另一种短形式的操作码情况是逐个旋转,将imm8 字节保存为rol/ror/rcl/rcr。由于疯狂的 x86 CISC 怪异,根据数据旋转 1 组 OF(溢出标志),但旋转其他计数使其未定义。这可能仅适用于短格式操作码,不适用于C1 C0 01(长格式rol eax, 1)根据agner.org/optimizeusers.atw.hu/instlatx64/…,英特尔IvyBridge、Haswell 和Skylake 对长格式具有双倍吞吐量。 SandyBridge 对任何一种形式都需要 2 微秒,甚至是 count!=1
猜你喜欢
  • 1970-01-01
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 2016-04-15
  • 1970-01-01
相关资源
最近更新 更多