From 5bdafbbcf0a4bd0fef613f4c5388006fb5ce982f Mon Sep 17 00:00:00 2001 From: Alexis Engelke Date: Sun, 13 Jan 2019 15:56:39 +0100 Subject: [PATCH] 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. --- decode.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/decode.c b/decode.c index f78e1d7..d7b1734 100644 --- a/decode.c +++ b/decode.c @@ -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; }