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)) if (UNLIKELY(off + 2 >= len))
return -1; return -1;
byte = buffer[off + 2]; 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." // - "In 32-bit modes, VEX.W is silently ignored."
// - VEX.W either replaces REX.W, is don't care or is reserved. // - 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 else // 2-byte VEX
prefixes |= PREFIX_ESC_0F; prefixes |= PREFIX_ESC_0F;
@@ -459,12 +461,10 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, Instr* instr)
{ {
op_size_log = 1; op_size_log = 1;
} }
#if defined(ARCH_X86_64) else if (mode == DECODE_64 && (prefixes & PREFIX_REXW))
else if (prefixes & PREFIX_REXW)
{ {
op_size_log = 4; op_size_log = 4;
} }
#endif
else if (prefixes & PREFIX_OPSZ) else if (prefixes & PREFIX_OPSZ)
{ {
op_size_log = 2; op_size_log = 2;
@@ -609,7 +609,8 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, Instr* instr)
imm_size = 2; imm_size = 2;
} }
#if defined(ARCH_X86_64) #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; imm_size = 8;
} }