Fix VEX decoding with mandatory VEX.W bit

The Intel documentation is, well, inconsistent about this: at one point,
they say that the VEX.W prefix is ignored entirely in 32-bit mode, but
the instruction description indicates that a VEX.W can be required in
32-bit/compatibility mode as well.
This commit is contained in:
Alexis Engelke
2019-01-13 15:56:39 +01:00
parent 5532602000
commit 5bdafbbcf0

View File

@@ -138,10 +138,12 @@ decode_prefixes(const uint8_t* buffer, int len, DecodeMode mode,
if (UNLIKELY(off + 2 >= len))
return -1;
byte = buffer[off + 2];
// SDM Vol 2A 2-16 (Dec. 2016)
// SDM Vol 2A 2-16 (Dec. 2016) says that:
// - "In 32-bit modes, VEX.W is silently ignored."
// - VEX.W either replaces REX.W, is don't care or is reserved.
prefixes |= mode == DECODE_64 && (byte & 0x80) ? PREFIX_REXW : 0;
// This is actually incorrect, there are instructions that
// use VEX.W as an opcode extension even in 32-bit mode.
prefixes |= byte & 0x80 ? PREFIX_REXW : 0;
}
else // 2-byte VEX
prefixes |= PREFIX_ESC_0F;
@@ -459,12 +461,10 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, Instr* instr)
{
op_size_log = 1;
}
#if defined(ARCH_X86_64)
else if (prefixes & PREFIX_REXW)
else if (mode == DECODE_64 && (prefixes & PREFIX_REXW))
{
op_size_log = 4;
}
#endif
else if (prefixes & PREFIX_OPSZ)
{
op_size_log = 2;
@@ -609,7 +609,8 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, Instr* instr)
imm_size = 2;
}
#if defined(ARCH_X86_64)
else if (prefixes & PREFIX_REXW && instr->type == IT_MOVABS_IMM)
else if (mode == DECODE_64 && (prefixes & PREFIX_REXW) &&
instr->type == IT_MOVABS_IMM)
{
imm_size = 8;
}