x64架构下带VEX前缀指令的REX编码中~R、~X、~B位的通用确定算法咨询
x64架构下带VEX前缀指令的REX编码中R、X、~B位的通用确定算法咨询
这个问题确实容易踩坑——VEX前缀里的R、X、~B位不是靠“取第一个/最后一个操作数”这种简单规则来确定的,核心得看指令的编码规范,以及每个操作数对应到ModRM/SIB里的哪个字段。我给你拆解清楚:
先搞懂R/X/~B的本质
VEX前缀里的这三个位,其实是REX前缀中R、X、B位的反码(也就是~R = 1 - R,以此类推)。而REX的R/X/B位本来是用来把ModRM/SIB里的3位寄存器编码扩展成4位,从而支持r8~r15这些寄存器的:
- R位:扩展ModRM的
reg字段(对应某个寄存器操作数,或操作码扩展) - X位:扩展SIB的
index字段(仅当指令用到SIB字节时有效) - B位:扩展ModRM的
r/m字段(当它作为base寄存器时)或SIB的base字段
通用确定步骤
- 查指令的编码手册(比如Intel官方的《64位和IA-32架构软件开发手册卷2》):
- 找到指令对应的
map_select(就是VEX第二个字节的低5位),它会告诉你该指令属于哪一类编码模板。 - 重点看指令的「操作数编码」部分,明确每个操作数对应ModRM的
reg、r/m字段,还是VEX.vvvv字段,有没有用到SIB字节。
- 找到指令对应的
- 判断是否需要REX扩展:
- 如果某个操作数对应ModRM的
reg字段,且该寄存器是r8r15(编码≥8),则REX.R=1,对应VEX.R=0;如果是r0r7,REX.R=0,VEX.R=1。 - 如果操作数对应ModRM的
r/m字段(作为base寄存器)或SIB的base字段,且寄存器是r8r15,则REX.B=1,VEX.B=0;反之则REX.B=0,VEX.~B=1。 - 如果用到SIB的
index字段且寄存器是r8r15,REX.X=1,VEX.X=0;否则REX.X=0,VEX.~X=1。
- 如果某个操作数对应ModRM的
- 注意特殊情况:
- 有些指令的ModRM.reg字段是用来扩展操作码的,不是表示寄存器,这时候REX.R位无关,通常设为0(对应VEX.~R=1)。
- 没有SIB字节的指令,REX.X位无关,默认设为0(VEX.~X=1)。
用你的例子验证
1. andn ecx, r15d, edx 编码为 c4 e2 00 f2 ca
根据手册,ANDN的编码模板是VEX.NDS.LIG.0F38.W0 F2 /r:
/r表示ModRM的r/m字段是目标寄存器ecx(编码001,属于r0~r7),不需要B位扩展,所以REX.B=0 → VEX.~B=1。- VEX.vvvv字段对应源寄存器r15d(编码1111,vvvv是寄存器的反码,所以vvvv=0000)。
- ModRM的
reg字段是用来扩展操作码的(区分ANDN和同组其他指令),不是寄存器,所以REX.R=0 → VEX.~R=1。 - 没有SIB字节,REX.X=0 → VEX.~X=1。
- 组合起来VEX第二个字节的高3位是111,低5位是00010(map_select=2),就是
e2(11100010),完全匹配。
2. bextr ecx, r15d, edx 编码为 c4 c2 68 f7 cf
BEXTR的编码模板是VEX.NDS.LIG.0F38.W0 F7 /r:
/r表示ModRM的r/m字段是源寄存器r15d(编码1111,属于r8~r15),需要B位扩展,所以REX.B=1 → VEX.~B=0。- VEX.vvvv字段对应目标寄存器ecx(编码001,反码是1110)。
- ModRM的
reg字段对应控制寄存器edx(编码010,r0~r7),不需要R位扩展,REX.R=0 → VEX.~R=1。 - 没有SIB字节,REX.X=0 → VEX.~X=1。
- 组合起来VEX第二个字节的高3位是110,低5位是00010(map_select=2),就是
c2(11000010),和你给出的编码一致。
总结
别再用“第一个/最后一个操作数”这种经验规则了,必须结合指令的编码规范来确定每个操作数对应的字段,再判断是否需要REX扩展——这才是通用的方法。
备注:内容来源于stack exchange,提问作者Goubermouche
相关产品推荐
相关产品推荐

