相同的装配指令但不同的机器指令

Hui*_*hoo 5 x86 assembly nasm disassembly

我正在玩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
Run Code Online (Sandbox Code Playgroud)

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

root@localhost:~/asm$ ndisasm 123
00000000  88061234          mov [0x3412],al
00000004  A21234            mov [0x3412],al
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*tch 11

您所观察到的是英特尔使用8088处理器进行设计考虑因素之一.为了与8088处理器保持兼容,今天的基于x86的处理器继承了其中一些设计考虑因素,特别是与指令集有关.特别是英特尔决定8088应该以性能为代价提高内存利用率.他们创建了一个可变长度的CISC指令集,它有一些特殊的编码来限制某些指令的大小.这与使用固定长度指令但可以获得更好性能的许多基于RISC的体系结构(如旧版Motorola 88000)不同.

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

在较早的文献中(大约1980年),实现更好地利用空间的考虑因素更加突出.在我的答案,因为它涉及到AX寄存器中的信息来自一本书,我书架上名为8088汇编语言程序设计:IBM PC,但有些信息可以像在网上的文章中找到.

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

AX是"累加器";

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

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被视为累加器的事实.英特尔考虑到了这一点,并为一些指令添加了特殊的操作码,以便更有效地存储完整的指令.你发现这个与MOV指令(用AX,AL),但它也适用于ADC,ADD,AND,CMP,OR,SBB,SUB, TEST,异或.当与AL一起使用时,这些指令中的每一个都具有较短的操作码编码,AX需要少一个字节.您也可以使用更长的操作码对AX,AL进行编码.在你的情况下:

00000000  88061234          mov [0x3412],al
00000004  A21234            mov [0x3412],al
Run Code Online (Sandbox Code Playgroud)

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

这是一个很好的HTML x86 指令集参考,可在线获得,但Intel 为IA-32(i386等)和64位架构提供了非常详细的指令参考.

  • 另一个简短形式的操作码情况是逐个旋转,为`rol/ror/rcl/rcr`保存`imm8`字节.由于疯狂的x86 CISC怪异,根据数据旋转1组`OF`(溢出标志),但是通过其他计数旋转保持未定义.这可能只适用于短格式操作码,而不适用于`C1 C0 01`(长格式`rol eax,1`)根据http://agner.org/optimize/和http://users.atw.hu /instlatx64/GenuineIntel00506E3_Skylake_InstLatX64.txt,Intel IvyBridge,Haswell和Skylake的长格式产品具有双倍的吞吐量.SandyBridge对于任何一种形式都需要2 uop,甚至`count!= 1`. (2认同)