我正在玩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中的多个机器指令吗?
答案 0 :(得分:11)
您所观察到的是英特尔使用8088处理器进行设计考虑因素之一。为了与8088处理器保持兼容,今天的基于x86的处理器提出了一些设计考虑因素,特别是与指令集有关。特别是英特尔决定8088应该以性能为代价提高内存利用率。他们创建了一个可变长度的CISC指令集,它有一些特殊的编码来限制某些指令的大小。这与使用固定长度指令但可以获得更好性能的许多基于RISC的体系结构(如旧的Motorola 88000)不同。
速度与可变或固定长度指令集之间的权衡是因为处理器需要更多时间来解码用于实现某些较小指令编码的复杂可变长度指令。对于英特尔8088来说也是如此。
在较早的文献中(大约1980年),实现更好地利用空间的考虑因素更加突出。我的答案中与AX注册有关的信息来自我的书架8088 Assembler Language Programming: The IBM PC上的一本书,但有些信息可以在this等在线文章中找到。
在线文章中,此信息非常适用于AX(累加器)和其他通用寄存器(如BX,CX,DX)的情况。
AX是"累加器'&#39 ;;
某些操作(如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,{{3 }},OR,SBB,SUB,TEST。当与AL一起使用时,这些指令中的每一个都具有较短的操作码编码,AX需要少一个字节。您也可以使用更长的操作码对AX,AL进行编码。在你的情况下:
00000000 88061234 mov [0x3412],al
00000004 A21234 mov [0x3412],al
是相同的指令,但有两种不同的编码。
这是一个很好的HTML x86 XOR可在线获取,但英特尔为IA-32(i386等)和64位架构提供了非常详细的instruction set reference。