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

Assembly 相同的装配指令但不同的机器指令,assembly,x86,nasm,disassembly,Assembly,X86,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

我在玩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中的多条机器指令?

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

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

在较旧的文献(大约1980年)中,对更好地利用空间的考虑更为突出。我的答案中与AX寄存器相关的信息来自我书架上的一本书,书名为,但是一些信息可以在网上的文章中找到,如

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

AX是“累加器”

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

BX是“基”寄存器

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

CX是“计数”寄存器

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

DX是“数据”寄存器

它与AX一起用于字大小的MUL和DIV操作,还可以保存IN和OUT指令的端口号,但与所有其他通用寄存器一样,它通常是存储数据的方便场所

正如您所见,英特尔打算将通用寄存器用于各种用途,但它们也可以用于特定用途,并且通常对与之相关的指令具有特殊意义。在您的案例中,您观察到的事实是,AX被视为一个累加器。英特尔考虑到了这一点,并为一些指令添加了特殊的操作码,以更有效地存储完整的指令。您在指令(AX、AL)中发现了这一点,但它也适用于、、。当与AL、AX一起使用时,这些指令中的每一条指令都有一个较短的操作码编码,该编码需要较少的一个字节。您也可以使用更长的操作码对AX、AL进行编码。就你而言:

00000000  88061234          mov [0x3412],al
00000004  A21234            mov [0x3412],al
是相同的指令,但有两种不同的编码


这是一款在线提供的优秀HTML x86,但Intel提供了非常详细的IA-32(i386等)和64位体系结构的详细说明。

您偶然发现了Intel 808X设计的一个产物。AX是一个通用16位寄存器,但Intel将AX(或AH和AL的高/低8位版本)专用于某些操作。英特尔将AX寄存器视为累加器。AX(和AH,AL)对某些指令有特殊的编码(通常少用一个字节)。您可以选择使用更短或更长的指令(对于有限的内存,更短的指令更好)。除了MOV,AX/AH/AL对ADC、ADD、AND、CMP、OR、SBB、SUB、TEST、XOR都有特殊的编码。@MichaelPetch:这实际上是答案,而不仅仅是注释!如果您对这类内容感兴趣,您一定要查看指令集参考。@MichaelPetch谢谢您的回答,您真的帮了我的忙。您可以阅读英特尔手册,了解哪些指令具有特定寄存器目标的自定义编码。另一个简短的操作码案例适用于rotate by one,保存
rol/ror/rcl/rcr
imm8
字节。由于疯狂的x86 CISC古怪,根据数据旋转1组
(溢出标志),但旋转其他计数时未定义。这可能只适用于短形式的操作码,而不适用于长形式的
C1 C001
(长形式
rol eax,1
),根据和,Intel IvyBridge、Haswell和Skylake的长形式吞吐量加倍。SandyBridge对任何一种形式都使用2个UOP,甚至
count=1