Allow prefix table at end of opcode

Some instructions, e.g. VZEROUPPER, have a prefix table but no
associated byte for that. Fix this by removing the prefix handling from
the table walking loop.
This commit is contained in:
Alexis Engelke
2019-01-13 15:53:48 +01:00
parent d1110fae6a
commit 4f4b2050c8

View File

@@ -38,6 +38,12 @@ static const uint8_t _decode_table64[] = {
#define ENTRY_MASK 7 #define ENTRY_MASK 7
#define ENTRY_IS_TABLE(kind) ((kind) >= ENTRY_TABLE256) #define ENTRY_IS_TABLE(kind) ((kind) >= ENTRY_TABLE256)
#define ENTRY_UNPACK(table,kind,decode_table,entry) do { \
uint16_t entry_copy = entry; \
table = (uint16_t*) &(decode_table)[entry_copy & ~7]; \
kind = entry_copy & ENTRY_MASK; \
} while (0)
#define INSTR_ENC_ADDR 0x08 #define INSTR_ENC_ADDR 0x08
#define INSTR_ENC_IMM 0x10 #define INSTR_ENC_IMM 0x10
#define INSTR_ENC_MODRM 0x80 #define INSTR_ENC_MODRM 0x80
@@ -466,51 +472,38 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, Instr* instr)
} }
} }
do // First walk through full-byte opcodes. We do at most three iterations.
while (kind == ENTRY_TABLE256 && LIKELY(off < len))
ENTRY_UNPACK(table, kind, decode_table, table[buffer[off++]]);
// Then, walk through ModR/M-encoded opcode extensions.
if ((kind == ENTRY_TABLE8 || kind == ENTRY_TABLE72) && LIKELY(off < len))
{ {
uint16_t entry = 0; uint16_t entry = 0;
if (kind == ENTRY_TABLE256) if (kind == ENTRY_TABLE72 && (buffer[off] & 0xc0) == 0xc0)
{
entry = table[buffer[off++]];
}
else if (kind == ENTRY_TABLE8)
{
entry = table[(buffer[off] >> 3) & 7];
}
else if (kind == ENTRY_TABLE72)
{
if ((buffer[off] & 0xc0) == 0xc0)
{ {
entry = table[buffer[off] - 0xb8]; entry = table[buffer[off] - 0xb8];
if ((entry & ENTRY_MASK) != ENTRY_NONE) if ((entry & ENTRY_MASK) != ENTRY_NONE)
{
off++; off++;
}
else else
{
entry = table[(buffer[off] >> 3) & 7]; entry = table[(buffer[off] >> 3) & 7];
} }
}
else else
{
entry = table[(buffer[off] >> 3) & 7]; entry = table[(buffer[off] >> 3) & 7];
ENTRY_UNPACK(table, kind, decode_table, entry);
} }
}
else if (kind == ENTRY_TABLE_PREFIX) // Finally, handle mandatory prefixes (which behave like an opcode ext.).
if (kind == ENTRY_TABLE_PREFIX)
{ {
uint8_t index = 0; uint8_t index = 0;
if (prefixes & PREFIX_OPSZ) if (prefixes & PREFIX_OPSZ)
{
index = 1; index = 1;
}
else if (prefixes & PREFIX_REP) else if (prefixes & PREFIX_REP)
{
index = 2; index = 2;
}
else if (prefixes & PREFIX_REPNZ) else if (prefixes & PREFIX_REPNZ)
{
index = 3; index = 3;
}
#if defined(ARCH_X86_64) #if defined(ARCH_X86_64)
index |= prefixes & PREFIX_REXW ? (1 << 2) : 0; index |= prefixes & PREFIX_REXW ? (1 << 2) : 0;
#endif #endif
@@ -520,16 +513,8 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, Instr* instr)
// for the 0x66 prefix, which could otherwise override the operand // for the 0x66 prefix, which could otherwise override the operand
// size of general purpose registers. // size of general purpose registers.
prefixes &= ~(PREFIX_OPSZ | PREFIX_REPNZ | PREFIX_REP); prefixes &= ~(PREFIX_OPSZ | PREFIX_REPNZ | PREFIX_REP);
entry = table[index]; ENTRY_UNPACK(table, kind, decode_table, table[index]);
} }
else
{
break;
}
kind = entry & ENTRY_MASK;
table = (uint16_t*) &decode_table[entry & ~7];
} while (LIKELY(off < len));
if (UNLIKELY(kind != ENTRY_INSTR)) if (UNLIKELY(kind != ENTRY_INSTR))
{ {