decode: Ignore ES/CS/SS/DS override in 64-bit mode

This commit is contained in:
Alexis Engelke
2020-11-22 20:59:13 +01:00
parent 8ab9f641b8
commit bb8510d77f
2 changed files with 65 additions and 38 deletions

View File

@@ -238,39 +238,60 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
int rex_off = -1; int rex_off = -1;
instr->segment = FD_REG_NONE; instr->segment = FD_REG_NONE;
while (LIKELY(off < len)) #if defined(ARCH_386)
{ if (mode == DECODE_32) {
uint8_t prefix = buffer[off]; while (LIKELY(off < len))
switch (UNLIKELY(prefix))
{ {
default: goto prefix_end; uint8_t prefix = buffer[off];
// From segment overrides, the last one wins. switch (UNLIKELY(prefix))
case 0x26: instr->segment = FD_REG_ES; break; {
case 0x2e: instr->segment = FD_REG_CS; break; default: goto prefix_end;
case 0x36: instr->segment = FD_REG_SS; break; // From segment overrides, the last one wins.
case 0x3e: instr->segment = FD_REG_DS; break; case 0x26: instr->segment = FD_REG_ES; break;
case 0x64: instr->segment = FD_REG_FS; break; case 0x2e: instr->segment = FD_REG_CS; break;
case 0x65: instr->segment = FD_REG_GS; break; case 0x36: instr->segment = FD_REG_SS; break;
case 0x66: prefix_66 = true; break; case 0x3e: instr->segment = FD_REG_DS; break;
case 0x67: prefix_67 = true; break; case 0x64: instr->segment = FD_REG_FS; break;
case 0xf0: prefix_lock = true; break; case 0x65: instr->segment = FD_REG_GS; break;
// From REP/REPE and REPNZ, the last one wins; and for mandatory case 0x66: prefix_66 = true; break;
// prefixes they have a higher priority than 66h (handled below). case 0x67: prefix_67 = true; break;
case 0xf3: prefix_rep = 2; break; case 0xf0: prefix_lock = true; break;
case 0xf2: prefix_rep = 3; break; case 0xf3: prefix_rep = 2; break;
#if defined(ARCH_X86_64) 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: off++;
case 0x4c: case 0x4d: case 0x4e: case 0x4f:
if (mode != DECODE_64)
goto prefix_end;
prefix_rex = prefix;
rex_off = off;
break;
#endif
} }
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: prefix_end:
// REX prefix is only considered if it is the last prefix. // REX prefix is only considered if it is the last prefix.

View File

@@ -58,12 +58,18 @@ main(int argc, char** argv)
TEST("\x90", "[NOP]"); TEST("\x90", "[NOP]");
TEST("\x90", "[NOP]"); TEST("\x90", "[NOP]");
TEST("\x2e\x90", "[cs:NOP]"); TEST32("\x2e\x90", "[cs:NOP]");
TEST("\x2e\x2e\x90", "[cs:NOP]"); TEST64("\x2e\x90", "[NOP]");
TEST("\x2e\x26\x90", "[es:NOP]"); TEST32("\x2e\x2e\x90", "[cs:NOP]");
TEST("\x26\x2e\x90", "[cs:NOP]"); TEST64("\x2e\x2e\x90", "[NOP]");
TEST("\x26\x65\x90", "[gs:NOP]"); TEST32("\x2e\x26\x90", "[es:NOP]");
TEST("\x65\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("\x0f\x10\xc1", "[SSE_MOVUPS reg16:r0 reg16:r1]");
TEST("\x66\x0f\x10\xc1", "[SSE_MOVUPD 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]"); 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("\x48\x90", "[NOP]");
TEST64("\x49\x90", "[XCHG reg8:r8 reg8:r0]"); TEST64("\x49\x90", "[XCHG reg8:r8 reg8:r0]");
TEST64("\x48\x91", "[XCHG reg8:r1 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]"); TEST64("\x66\x90", "[NOP]");
TEST("\x0f\xc7\x0f", "[CMPXCHGD_4 mem0:r7]"); TEST("\x0f\xc7\x0f", "[CMPXCHGD_4 mem0:r7]");
TEST64("\x48\x0f\xc7\x0f", "[CMPXCHGD_8 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("\x66\xc5\xf2\x2a\xc0", "UD"); // VEX+66
TEST("\xf0\xc5\xf2\x2a\xc0", "UD"); // VEX+LOCK TEST("\xf0\xc5\xf2\x2a\xc0", "UD"); // VEX+LOCK
TEST64("\x40\xc5\xf2\x2a\xc0", "UD"); // VEX+REX 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]"); 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 TEST32("\xc4\xe1\x00\x58\xc1", "[VADDPS reg16:r0 reg16:r7 reg16:r1]"); // MSB in vvvv ignored