d &= ~ModRM;
#undef ModRM /* Only its aliases are valid to use from here on. */
- modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3);
+ modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3) |
+ ((evex_encoded() && !evex.R) << 4);
modrm_rm = modrm & 0x07;
/*
if ( modrm_mod == 3 )
{
generate_exception_if(d & vSIB, EXC_UD);
- modrm_rm |= (rex_prefix & 1) << 3;
+ modrm_rm |= ((rex_prefix & 1) << 3) |
+ (evex_encoded() && !evex.x) << 4;
ea.type = OP_REG;
}
else if ( ad_bytes == 2 )
state->sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
state->sib_scale = (sib >> 6) & 3;
- if ( state->sib_index != 4 && !(d & vSIB) )
+ if ( unlikely(d & vSIB) )
+ state->sib_index |= (mode_64bit() && evex_encoded() &&
+ !evex.RX) << 4;
+ else if ( state->sib_index != 4 )
{
ea.mem.off = *decode_gpr(state->regs, state->sib_index);
ea.mem.off <<= state->sib_scale;
generate_exception_if(state->not_64bit && mode_64bit(), EXC_UD);
if ( ea.type == OP_REG )
- ea.reg = _decode_gpr(&_regs, modrm_rm, (d & ByteOp) && !rex_prefix);
+ ea.reg = _decode_gpr(&_regs, modrm_rm, (d & ByteOp) && !rex_prefix && !vex.opcx);
memset(mmvalp, 0xaa /* arbitrary */, sizeof(*mmvalp));
src.type = OP_REG;
if ( d & ByteOp )
{
- src.reg = _decode_gpr(&_regs, modrm_reg, !rex_prefix);
+ src.reg = _decode_gpr(&_regs, modrm_reg, !rex_prefix && !vex.opcx);
src.val = *(uint8_t *)src.reg;
src.bytes = 1;
}
dst.type = OP_REG;
if ( d & ByteOp )
{
- dst.reg = _decode_gpr(&_regs, modrm_reg, !rex_prefix);
+ dst.reg = _decode_gpr(&_regs, modrm_reg, !rex_prefix && !vex.opcx);
dst.val = *(uint8_t *)dst.reg;
dst.bytes = 1;
}
BUILD_BUG_ON(ARRAY_SIZE(cpu_user_regs_gpr_offsets) &
(ARRAY_SIZE(cpu_user_regs_gpr_offsets) - 1));
- ASSERT(modrm < ARRAY_SIZE(cpu_user_regs_gpr_offsets));
-
- /* Note that this also acts as array_access_nospec() stand-in. */
+ /*
+ * Note that this also acts as array_access_nospec() stand-in. Higher
+ * bits may legitimately come in set here, from EVEX decoding, and
+ * hence truncation is what we want (bits not ignored will get checked
+ * elsewhere).
+ */
modrm &= ARRAY_SIZE(cpu_user_regs_gpr_offsets) - 1;
return (void *)regs + cpu_user_regs_gpr_offsets[modrm];