diff --git a/decode.c b/decode.c index b5dcb6c..ab43cfd 100644 --- a/decode.c +++ b/decode.c @@ -238,39 +238,60 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, int rex_off = -1; instr->segment = FD_REG_NONE; - while (LIKELY(off < len)) - { - uint8_t prefix = buffer[off]; - switch (UNLIKELY(prefix)) +#if defined(ARCH_386) + if (mode == DECODE_32) { + while (LIKELY(off < len)) { - default: goto prefix_end; - // From segment overrides, the last one wins. - case 0x26: instr->segment = FD_REG_ES; break; - case 0x2e: instr->segment = FD_REG_CS; break; - case 0x36: instr->segment = FD_REG_SS; break; - case 0x3e: instr->segment = FD_REG_DS; break; - case 0x64: instr->segment = FD_REG_FS; break; - case 0x65: instr->segment = FD_REG_GS; break; - case 0x66: prefix_66 = true; break; - case 0x67: prefix_67 = true; break; - case 0xf0: prefix_lock = true; break; - // From REP/REPE and REPNZ, the last one wins; and for mandatory - // prefixes they have a higher priority than 66h (handled below). - case 0xf3: prefix_rep = 2; break; - case 0xf2: prefix_rep = 3; break; -#if defined(ARCH_X86_64) - case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: - case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - if (mode != DECODE_64) - goto prefix_end; - prefix_rex = prefix; - rex_off = off; - break; -#endif + uint8_t prefix = buffer[off]; + switch (UNLIKELY(prefix)) + { + default: goto prefix_end; + // From segment overrides, the last one wins. + case 0x26: instr->segment = FD_REG_ES; break; + case 0x2e: instr->segment = FD_REG_CS; break; + case 0x36: instr->segment = FD_REG_SS; break; + case 0x3e: instr->segment = FD_REG_DS; break; + case 0x64: instr->segment = FD_REG_FS; break; + case 0x65: instr->segment = FD_REG_GS; break; + case 0x66: prefix_66 = true; break; + case 0x67: prefix_67 = true; break; + case 0xf0: prefix_lock = true; break; + case 0xf3: prefix_rep = 2; break; + case 0xf2: prefix_rep = 3; break; + } + off++; } - off++; } +#endif +#if defined(ARCH_X86_64) + if (mode == DECODE_64) { + while (LIKELY(off < len)) + { + uint8_t prefix = buffer[off]; + switch (UNLIKELY(prefix)) + { + default: goto prefix_end; + // ES/CS/SS/DS overrides are ignored. + case 0x26: case 0x2e: case 0x36: case 0x3e: break; + // From segment overrides, the last one wins. + case 0x64: instr->segment = FD_REG_FS; break; + case 0x65: instr->segment = FD_REG_GS; break; + case 0x66: prefix_66 = true; break; + case 0x67: prefix_67 = true; break; + case 0xf0: prefix_lock = true; break; + case 0xf3: prefix_rep = 2; break; + case 0xf2: prefix_rep = 3; break; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: + case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + prefix_rex = prefix; + rex_off = off; + break; + } + off++; + } + } +#endif prefix_end: // REX prefix is only considered if it is the last prefix. diff --git a/tests/test_decode.c b/tests/test_decode.c index 9804e82..fa5beaf 100644 --- a/tests/test_decode.c +++ b/tests/test_decode.c @@ -58,12 +58,18 @@ main(int argc, char** argv) TEST("\x90", "[NOP]"); TEST("\x90", "[NOP]"); - TEST("\x2e\x90", "[cs:NOP]"); - TEST("\x2e\x2e\x90", "[cs:NOP]"); - TEST("\x2e\x26\x90", "[es:NOP]"); - TEST("\x26\x2e\x90", "[cs:NOP]"); - TEST("\x26\x65\x90", "[gs:NOP]"); - TEST("\x65\x26\x90", "[es:NOP]"); + TEST32("\x2e\x90", "[cs:NOP]"); + TEST64("\x2e\x90", "[NOP]"); + TEST32("\x2e\x2e\x90", "[cs:NOP]"); + TEST64("\x2e\x2e\x90", "[NOP]"); + TEST32("\x2e\x26\x90", "[es:NOP]"); + TEST64("\x2e\x26\x90", "[NOP]"); + TEST32("\x26\x2e\x90", "[cs:NOP]"); + TEST64("\x26\x2e\x90", "[NOP]"); + TEST32("\x26\x65\x90", "[gs:NOP]"); + TEST64("\x26\x65\x90", "[gs:NOP]"); + TEST32("\x65\x26\x90", "[es:NOP]"); + TEST64("\x65\x26\x90", "[gs:NOP]"); TEST("\x0f\x10\xc1", "[SSE_MOVUPS reg16:r0 reg16:r1]"); TEST("\x66\x0f\x10\xc1", "[SSE_MOVUPD reg16:r0 reg16:r1]"); TEST("\xf2\x66\x0f\x10\xc1", "[SSE_MOVSD reg16:r0 reg8:r1]"); @@ -73,7 +79,7 @@ main(int argc, char** argv) TEST64("\x48\x90", "[NOP]"); TEST64("\x49\x90", "[XCHG reg8:r8 reg8:r0]"); TEST64("\x48\x91", "[XCHG reg8:r1 reg8:r0]"); - TEST64("\x48\x26\x91", "[es:XCHG reg4:r1 reg4:r0]"); + TEST64("\x48\x26\x91", "[XCHG reg4:r1 reg4:r0]"); TEST64("\x66\x90", "[NOP]"); TEST("\x0f\xc7\x0f", "[CMPXCHGD_4 mem0:r7]"); TEST64("\x48\x0f\xc7\x0f", "[CMPXCHGD_8 mem0:r7]"); @@ -285,7 +291,7 @@ main(int argc, char** argv) TEST("\x66\xc5\xf2\x2a\xc0", "UD"); // VEX+66 TEST("\xf0\xc5\xf2\x2a\xc0", "UD"); // VEX+LOCK TEST64("\x40\xc5\xf2\x2a\xc0", "UD"); // VEX+REX - TEST64("\x40\x26\xc5\xf2\x2a\xc0", "[es:VCVTSI2SS reg16:r0 reg16:r1 reg4:r0]"); // VEX+REX, but REX doesn't precede VEX + TEST64("\x40\x26\xc5\xf2\x2a\xc0", "[VCVTSI2SS reg16:r0 reg16:r1 reg4:r0]"); // VEX+REX, but REX doesn't precede VEX TEST("\xf3\x0f\x7e\x5c\x24\x08", "[SSE_MOVQ reg16:r3 mem8:r4+0x8]"); TEST32("\xc4\xe1\x00\x58\xc1", "[VADDPS reg16:r0 reg16:r7 reg16:r1]"); // MSB in vvvv ignored