在分析spec cpu 2017中,汇编指令得到不同的opcode长度,从而对程序性能有影响。差别仅是操作的寄存器不同,一个为%rsp,一个为%rbp:
// 使用%rsp寄存器
849d49: 48 8b 84 24 f8 17 00 mov 0x17f8(%rsp),%rax
849d50: 00
// 使用%rbp寄存器
835cfb: 48 8b 85 58 03 00 00 mov 0x358(%rbp),%rax
opcode
操作码(Operation Code, OPCode):描述机器语言指令中,指令要执行某种操作的机器码。
opcode与汇编指令不是单纯的一一对应关系。
opcode相同,但可能对应的汇编代码不同,例如:
90 nop
90 xchg ax, ax
90 xchg eax, eax
同类型的指令对应的opcode也可能不同:
B8 01000000 mov eax, 1
8B C3 mov eax, ebx
8B C7 mov eax, edi
下面将分析这些opcode。根据Intel手册卷2-2.2节内容可知,在64-bit模式下,opcode格式如下所示:
Opcodes(必须)
主操作码,长度为1、2或3字节。例如8b c0 mov eax,eax,其中8b就是主操作码,90 nop就是只有主操作码,没有ModR/M和SIB字节的。
构造模式ModR/M(可选)
许多涉及内存操作数的指令都有一个紧挨着主操作码的寻址格式说明字节(叫做ModR/M字节),ModR/M字节包含3个域信息:
- mod域:表示寻址模式
- reg/opcode域:寄存器(目的操作数的寄存器)或附加的3位操作码
- r/m域:寄存器(源操作数)
mod域与r/m域确定源操作数信息。
Note:
- “[–][–]”记号表示ModR/M后跟随有一个SIB字节,用于指明寻址方式
- “disp32”记号表示ModR/M(或者SIB,如果出现的话) 后跟随一个32位的偏移量,该偏移量被加至有效地址
- “disp8” 记号表示ModR/M(或者SIB,如果出现的话)后跟随一个8位的偏移量,该偏移量将被符号扩展,然后被加至有效地址
辅助分析SIB(可选)
某些ModR/M字节编码需要第二寻址字节(SIB)。基址+索引或者比例+索引形式的32位寻址需要SIB字节。SIB字节包括下列域:
- scale 域:指定比例因子
- index域:指定变址寄存器
- base 域:指定基址寄存器
例如语法Imm(rb, ri, s)
,其中rb为基址寄存器,ri为变址寄存器,s为比例因子(s值必须是1、2、4或8),有效地址被计算为M[Imm + R[rb] + R[ri] * s]
。
mov指令的opcode
上图中的内容解释:
- /r表示:此opcode存在ModR/M结构,且ModR/M结构的reg/opcode域为寄存器
- /digit:表示此OpCode存在ModR/M结构,且ModR/M结构的reg/opcode域为opcode
- ib:表示opcode后面跟着一个byte型数值
- iw:表示opcode后面跟着一个word型数值
- id:表示opcode后面跟着一个dword型数值
两条汇编指令的差异
查看mov指令的opcode(Intel手册卷2-4.3),上面的mov指令对应的是下表的MOV r64, r/m64
指令,opcode为REX.W+8B /r
。
两条汇编指令opcode为:
849d49: 48 8b 84 24 f8 17 00 mov 0x17f8(%rsp),%rax
849d50: 00
... ...
835cfb: 48 8b 85 58 03 00 00 mov 0x358(%rbp),%rax
通过ModR/M表可知,84
对应[--][--]+disp32
,85
对应[EBP]+disp32
。所以汇编指令mov 0x17f8(%rsp),%rax
的opcode长度会比mov 0x358(%rbp),%rax
多1byte,导致
参考文档
- Intel手册卷2,2.1和2.2节