decode: Replace table walk macro with function
This commit is contained in:
50
decode.c
50
decode.c
@@ -37,11 +37,12 @@ typedef enum DecodeMode DecodeMode;
|
|||||||
#define ENTRY_TABLE_ROOT 8
|
#define ENTRY_TABLE_ROOT 8
|
||||||
#define ENTRY_MASK 7
|
#define ENTRY_MASK 7
|
||||||
|
|
||||||
#define ENTRY_UNPACK(table,kind,entry) do { \
|
static inline unsigned
|
||||||
uint16_t entry_copy = entry; \
|
table_walk(unsigned cur_idx, unsigned entry_idx, unsigned* out_kind) {
|
||||||
table = &_decode_table[(entry_copy & ~7) >> 1]; \
|
unsigned entry = _decode_table[cur_idx + entry_idx];
|
||||||
kind = entry_copy & ENTRY_MASK; \
|
*out_kind = entry & ENTRY_MASK;
|
||||||
} while (0)
|
return (entry & ~ENTRY_MASK) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
#define LOAD_LE_1(buf) ((size_t) *(uint8_t*) (buf))
|
#define LOAD_LE_1(buf) ((size_t) *(uint8_t*) (buf))
|
||||||
#define LOAD_LE_2(buf) (LOAD_LE_1(buf) | LOAD_LE_1((uint8_t*) (buf) + 1)<<8)
|
#define LOAD_LE_2(buf) (LOAD_LE_1(buf) | LOAD_LE_1((uint8_t*) (buf) + 1)<<8)
|
||||||
@@ -332,30 +333,23 @@ int
|
|||||||
fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
||||||
FdInstr* instr)
|
FdInstr* instr)
|
||||||
{
|
{
|
||||||
const uint16_t* table = NULL;
|
|
||||||
DecodeMode mode;
|
|
||||||
|
|
||||||
int len = len_sz > 15 ? 15 : len_sz;
|
int len = len_sz > 15 ? 15 : len_sz;
|
||||||
|
|
||||||
// Ensure that we can actually handle the decode request
|
// Ensure that we can actually handle the decode request
|
||||||
if (mode_int == 32)
|
DecodeMode mode;
|
||||||
|
unsigned table_idx;
|
||||||
|
unsigned kind = ENTRY_TABLE_ROOT;
|
||||||
|
switch (mode_int)
|
||||||
{
|
{
|
||||||
#if defined(ARCH_386)
|
#if defined(ARCH_386)
|
||||||
table = &_decode_table[FD_TABLE_OFFSET_32];
|
case 32: table_idx = FD_TABLE_OFFSET_32; mode = DECODE_32; break;
|
||||||
mode = DECODE_32;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
else if (mode_int == 64)
|
|
||||||
{
|
|
||||||
#if defined(ARCH_X86_64)
|
#if defined(ARCH_X86_64)
|
||||||
table = &_decode_table[FD_TABLE_OFFSET_64];
|
case 64: table_idx = FD_TABLE_OFFSET_64; mode = DECODE_64; break;
|
||||||
mode = DECODE_64;
|
|
||||||
#endif
|
#endif
|
||||||
|
default: return FD_ERR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UNLIKELY(table == NULL))
|
|
||||||
return FD_ERR_INTERNAL;
|
|
||||||
|
|
||||||
int retval;
|
int retval;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
uint8_t vex_operand = 0;
|
uint8_t vex_operand = 0;
|
||||||
@@ -372,8 +366,6 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
return FD_ERR_PARTIAL;
|
return FD_ERR_PARTIAL;
|
||||||
off += retval;
|
off += retval;
|
||||||
|
|
||||||
uint32_t kind = ENTRY_TABLE_ROOT;
|
|
||||||
|
|
||||||
if (UNLIKELY(prefixes & PREFIX_VEX))
|
if (UNLIKELY(prefixes & PREFIX_VEX))
|
||||||
{
|
{
|
||||||
if (opcode_escape < 0 || opcode_escape > 3)
|
if (opcode_escape < 0 || opcode_escape > 3)
|
||||||
@@ -393,9 +385,9 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
off += opcode_escape >= 2 ? 2 : 1;
|
off += opcode_escape >= 2 ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENTRY_UNPACK(table, kind, table[opcode_escape]);
|
table_idx = table_walk(table_idx, opcode_escape, &kind);
|
||||||
if (LIKELY(off < len))
|
if (LIKELY(off < len))
|
||||||
ENTRY_UNPACK(table, kind, table[buffer[off++]]);
|
table_idx = table_walk(table_idx, buffer[off++], &kind);
|
||||||
|
|
||||||
// Handle mandatory prefixes (which behave like an opcode ext.).
|
// Handle mandatory prefixes (which behave like an opcode ext.).
|
||||||
if (kind == ENTRY_TABLE_PREFIX)
|
if (kind == ENTRY_TABLE_PREFIX)
|
||||||
@@ -406,16 +398,16 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
// general purpose registers. The instruction descriptor encodes whether
|
// general purpose registers. The instruction descriptor encodes whether
|
||||||
// the 66 prefix has an effect on the instruction (IGN66).
|
// the 66 prefix has an effect on the instruction (IGN66).
|
||||||
prefixes &= ~(PREFIX_REPNZ | PREFIX_REP);
|
prefixes &= ~(PREFIX_REPNZ | PREFIX_REP);
|
||||||
ENTRY_UNPACK(table, kind, table[mandatory_prefix]);
|
table_idx = table_walk(table_idx, mandatory_prefix, &kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then, walk through ModR/M-encoded opcode extensions.
|
// Then, walk through ModR/M-encoded opcode extensions.
|
||||||
if (kind == ENTRY_TABLE16 && LIKELY(off < len)) {
|
if (kind == ENTRY_TABLE16 && LIKELY(off < len)) {
|
||||||
unsigned isreg = (buffer[off] & 0xc0) == 0xc0 ? 8 : 0;
|
unsigned isreg = (buffer[off] & 0xc0) == 0xc0 ? 8 : 0;
|
||||||
ENTRY_UNPACK(table, kind, table[((buffer[off] >> 3) & 7) | isreg]);
|
table_idx = table_walk(table_idx, ((buffer[off] >> 3) & 7) | isreg, &kind);
|
||||||
|
if (kind == ENTRY_TABLE8E)
|
||||||
|
table_idx = table_walk(table_idx, buffer[off++] & 7, &kind);
|
||||||
}
|
}
|
||||||
if (kind == ENTRY_TABLE8E && LIKELY(off < len))
|
|
||||||
ENTRY_UNPACK(table, kind, table[buffer[off++] & 7]);
|
|
||||||
|
|
||||||
// For VEX prefix, we have to distinguish between VEX.W and VEX.L which may
|
// For VEX prefix, we have to distinguish between VEX.W and VEX.L which may
|
||||||
// be part of the opcode.
|
// be part of the opcode.
|
||||||
@@ -424,13 +416,13 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
index |= prefixes & PREFIX_REXW ? (1 << 0) : 0;
|
index |= prefixes & PREFIX_REXW ? (1 << 0) : 0;
|
||||||
index |= prefixes & PREFIX_VEXL ? (1 << 1) : 0;
|
index |= prefixes & PREFIX_VEXL ? (1 << 1) : 0;
|
||||||
ENTRY_UNPACK(table, kind, table[index]);
|
table_idx = table_walk(table_idx, index, &kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UNLIKELY(kind != ENTRY_INSTR))
|
if (UNLIKELY(kind != ENTRY_INSTR))
|
||||||
return kind == 0 ? FD_ERR_UD : FD_ERR_PARTIAL;
|
return kind == 0 ? FD_ERR_UD : FD_ERR_PARTIAL;
|
||||||
|
|
||||||
struct InstrDesc* desc = (struct InstrDesc*) table;
|
struct InstrDesc* desc = (struct InstrDesc*) &_decode_table[table_idx];
|
||||||
|
|
||||||
if (DESC_IGN66(desc))
|
if (DESC_IGN66(desc))
|
||||||
prefixes &= ~PREFIX_OPSZ;
|
prefixes &= ~PREFIX_OPSZ;
|
||||||
|
|||||||
Reference in New Issue
Block a user