相同的汇编指令但不同的机器指令

same assembly instruction but different machine instruction

我正在玩 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 中是否还有其他汇编指令映射到多个机器指令?

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

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

在较早的文献(大约 1980 年)中,更好地利用 space 的考虑更为突出。我的答案中与 AX 寄存器相关的信息来自我书架上的一本书 8088 Assembler Language Programming: The IBM PC, however some of the information can be found in online articles like this.

来自在线文章,此信息非常适用于 AX(累加器)和其他通用寄存器(如 BX、CX、DX)的情况。

AX is the "accumulator'';

some of the operations, such as MUL and DIV, require that one of the operands be in the accumulator. Some other operations, such as ADD and SUB, may be applied to any of the registers (that is, any of the eight general- and special-purpose registers) but are more efficient when working with the accumulator.

BX 是“基址”寄存器;

it is the only general-purpose register which may be used for indirect addressing. For example, the instruction MOV [BX], AX causes the contents of AX to be stored in the memory location whose address is given in BX.

CX 是“计数”寄存器。

The looping instructions (LOOP, LOOPE, and LOOPNE), the shift and rotate instructions (RCL, RCR, ROL, ROR, SHL, SHR, and SAR), and the string instructions (with the prefixes REP, REPE, and REPNE) all use the count register to determine how many times they will repeat.

DX 是“数据”寄存器;

it is used together with AX for the word-size MUL and DIV operations, and it can also hold the port number for the IN and OUT instructions, but it is mostly available as a convenient place to store data, as are all of the other general-purpose registers.

如您所见,Intel 打算将通用寄存器用于多种用途,但它们也可用于特定用途,并且通常对与之关联的指令具有特殊含义。在您的情况下,您观察到 AX 被视为 Accumulator 这一事实。英特尔考虑到了这一点,并为一些指令添加了特殊的操作码,以更有效地存储完整的指令。您通过 MOV instruction(with AX, AL), but it also applies to ADC, ADD, AND, CMP, OR, SBB, SUB, TEST, XOR 找到了它。当与需要少一个字节的 AL、AX 一起使用时,这些指令中的每一个都具有更短的操作码编码。您也可以使用更长的操作码对 AX、AL 进行编码。在你的情况下:

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

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

对于 IA-32(i386 等)和 64 位架构,这是一个很好的 HTML x86 instruction set reference that is available online, however Intel provides a very detailed instruction reference