decode: Store instruction descriptors separately
This commit is contained in:
31
decode.c
31
decode.c
@@ -9,12 +9,6 @@
|
|||||||
#define LIKELY(x) __builtin_expect((x), 1)
|
#define LIKELY(x) __builtin_expect((x), 1)
|
||||||
#define UNLIKELY(x) __builtin_expect((x), 0)
|
#define UNLIKELY(x) __builtin_expect((x), 0)
|
||||||
|
|
||||||
#define FD_DECODE_TABLE_DATA
|
|
||||||
static __attribute__((aligned(16))) const uint16_t _decode_table[] = {
|
|
||||||
#include <fadec-table.inc>
|
|
||||||
};
|
|
||||||
#undef FD_DECODE_TABLE_DATA
|
|
||||||
|
|
||||||
// Defines FD_TABLE_OFFSET_32 and FD_TABLE_OFFSET_64, if available
|
// Defines FD_TABLE_OFFSET_32 and FD_TABLE_OFFSET_64, if available
|
||||||
#define FD_DECODE_TABLE_DEFINES
|
#define FD_DECODE_TABLE_DEFINES
|
||||||
#include <fadec-table.inc>
|
#include <fadec-table.inc>
|
||||||
@@ -39,6 +33,11 @@ typedef enum DecodeMode DecodeMode;
|
|||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
table_walk(unsigned cur_idx, unsigned entry_idx, unsigned* out_kind) {
|
table_walk(unsigned cur_idx, unsigned entry_idx, unsigned* out_kind) {
|
||||||
|
static __attribute__((aligned(16))) const uint16_t _decode_table[] = {
|
||||||
|
#define FD_DECODE_TABLE_DATA
|
||||||
|
#include <fadec-table.inc>
|
||||||
|
#undef FD_DECODE_TABLE_DATA
|
||||||
|
};
|
||||||
unsigned entry = _decode_table[cur_idx + entry_idx];
|
unsigned entry = _decode_table[cur_idx + entry_idx];
|
||||||
*out_kind = entry & ENTRY_MASK;
|
*out_kind = entry & ENTRY_MASK;
|
||||||
return (entry & ~ENTRY_MASK) >> 1;
|
return (entry & ~ENTRY_MASK) >> 1;
|
||||||
@@ -181,8 +180,7 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr,
|
|||||||
struct InstrDesc
|
struct InstrDesc
|
||||||
{
|
{
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
uint8_t operand_indices;
|
uint16_t operand_indices;
|
||||||
uint8_t immediate;
|
|
||||||
uint16_t operand_sizes;
|
uint16_t operand_sizes;
|
||||||
uint16_t reg_types;
|
uint16_t reg_types;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
@@ -195,11 +193,11 @@ struct InstrDesc
|
|||||||
#define DESC_VEXREG_IDX(desc) ((((desc)->operand_indices >> 4) & 3) ^ 3)
|
#define DESC_VEXREG_IDX(desc) ((((desc)->operand_indices >> 4) & 3) ^ 3)
|
||||||
#define DESC_HAS_IMPLICIT(desc) (((desc)->operand_indices & (3 << 6)) != 0)
|
#define DESC_HAS_IMPLICIT(desc) (((desc)->operand_indices & (3 << 6)) != 0)
|
||||||
#define DESC_IMPLICIT_IDX(desc) ((((desc)->operand_indices >> 6) & 3) ^ 3)
|
#define DESC_IMPLICIT_IDX(desc) ((((desc)->operand_indices >> 6) & 3) ^ 3)
|
||||||
#define DESC_IMM_CONTROL(desc) (((desc)->immediate >> 4) & 0x7)
|
#define DESC_IMM_CONTROL(desc) (((desc)->operand_indices >> 12) & 0x7)
|
||||||
#define DESC_IMM_IDX(desc) (((desc)->immediate & 3) ^ 3)
|
#define DESC_IMM_IDX(desc) ((((desc)->operand_indices >> 8) & 3) ^ 3)
|
||||||
#define DESC_IMPLICIT_VAL(desc) (((desc)->immediate >> 2) & 1)
|
#define DESC_IMPLICIT_VAL(desc) (((desc)->operand_indices >> 10) & 1)
|
||||||
#define DESC_LOCK(desc) (((desc)->immediate >> 3) & 1)
|
#define DESC_LOCK(desc) (((desc)->operand_indices >> 11) & 1)
|
||||||
#define DESC_VSIB(desc) (((desc)->immediate >> 7) & 1)
|
#define DESC_VSIB(desc) (((desc)->operand_indices >> 15) & 1)
|
||||||
#define DESC_OPSIZE(desc) (((desc)->operand_sizes >> 8) & 3)
|
#define DESC_OPSIZE(desc) (((desc)->operand_sizes >> 8) & 3)
|
||||||
#define DESC_SIZE_FIX1(desc) (((desc)->operand_sizes >> 10) & 7)
|
#define DESC_SIZE_FIX1(desc) (((desc)->operand_sizes >> 10) & 7)
|
||||||
#define DESC_SIZE_FIX2(desc) (((desc)->operand_sizes >> 13) & 3)
|
#define DESC_SIZE_FIX2(desc) (((desc)->operand_sizes >> 13) & 3)
|
||||||
@@ -391,7 +389,12 @@ prefix_end:
|
|||||||
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*) &_decode_table[table_idx];
|
static __attribute__((aligned(16))) const struct InstrDesc descs[] = {
|
||||||
|
#define FD_DECODE_TABLE_DESCS
|
||||||
|
#include <fadec-table.inc>
|
||||||
|
#undef FD_DECODE_TABLE_DESCS
|
||||||
|
};
|
||||||
|
const struct InstrDesc* desc = &descs[table_idx >> 2];
|
||||||
|
|
||||||
instr->type = desc->type;
|
instr->type = desc->type;
|
||||||
instr->flags = prefix_rep == 2 ? FD_FLAG_REP :
|
instr->flags = prefix_rep == 2 ? FD_FLAG_REP :
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ class EntryKind(Enum):
|
|||||||
class TrieEntry(NamedTuple):
|
class TrieEntry(NamedTuple):
|
||||||
kind: EntryKind
|
kind: EntryKind
|
||||||
items: Tuple[Optional[str]]
|
items: Tuple[Optional[str]]
|
||||||
payload: Tuple[Union[int, str]]
|
descidx: Optional[int]
|
||||||
|
|
||||||
TABLE_LENGTH = {
|
TABLE_LENGTH = {
|
||||||
EntryKind.TABLE256: 256,
|
EntryKind.TABLE256: 256,
|
||||||
@@ -227,19 +227,19 @@ class TrieEntry(NamedTuple):
|
|||||||
def table(cls, kind):
|
def table(cls, kind):
|
||||||
return cls(kind, (None,) * cls.TABLE_LENGTH[kind], ())
|
return cls(kind, (None,) * cls.TABLE_LENGTH[kind], ())
|
||||||
@classmethod
|
@classmethod
|
||||||
def instr(cls, payload):
|
def instr(cls, descidx):
|
||||||
return cls(EntryKind.INSTR, (), payload)
|
return cls(EntryKind.INSTR, (), descidx)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def encode_length(self):
|
def encode_length(self):
|
||||||
return len(self.payload) + len(self.items)
|
return len(self.items)
|
||||||
def encode(self, encode_item) -> Tuple[Union[int, str]]:
|
def encode(self, encode_item) -> Tuple[Union[int, str]]:
|
||||||
enc_items = (encode_item(item) if item else 0 for item in self.items)
|
enc_items = (encode_item(item) if item else 0 for item in self.items)
|
||||||
return self.payload + tuple(enc_items)
|
return tuple(enc_items)
|
||||||
|
|
||||||
def map(self, map_func):
|
def map(self, map_func):
|
||||||
mapped_items = (map_func(i, v) for i, v in enumerate(self.items))
|
mapped_items = (map_func(i, v) for i, v in enumerate(self.items))
|
||||||
return TrieEntry(self.kind, tuple(mapped_items), self.payload)
|
return TrieEntry(self.kind, tuple(mapped_items), self.descidx)
|
||||||
def update(self, idx, new_val):
|
def update(self, idx, new_val):
|
||||||
return self.map(lambda i, v: new_val if i == idx else v)
|
return self.map(lambda i, v: new_val if i == idx else v)
|
||||||
|
|
||||||
@@ -347,6 +347,7 @@ class Table:
|
|||||||
self.roots = ["root%d"%i for i in range(root_count)]
|
self.roots = ["root%d"%i for i in range(root_count)]
|
||||||
for i in range(root_count):
|
for i in range(root_count):
|
||||||
self.data["root%d"%i] = TrieEntry.table(EntryKind.TABLE_ROOT)
|
self.data["root%d"%i] = TrieEntry.table(EntryKind.TABLE_ROOT)
|
||||||
|
self.descs = []
|
||||||
self.offsets = {}
|
self.offsets = {}
|
||||||
self.annotations = {}
|
self.annotations = {}
|
||||||
|
|
||||||
@@ -375,7 +376,10 @@ class Table:
|
|||||||
raise Exception("{}, have {}, want {}".format(
|
raise Exception("{}, have {}, want {}".format(
|
||||||
name, self.data[tn].kind, kind))
|
name, self.data[tn].kind, kind))
|
||||||
|
|
||||||
self._update_table(tn, opcode[-1][1], name, TrieEntry.instr(instr_encoding))
|
if instr_encoding not in self.descs:
|
||||||
|
self.descs.append(instr_encoding)
|
||||||
|
desc_idx = self.descs.index(instr_encoding)
|
||||||
|
self._update_table(tn, opcode[-1][1], name, TrieEntry.instr(desc_idx))
|
||||||
|
|
||||||
def deduplicate(self):
|
def deduplicate(self):
|
||||||
synonyms = True
|
synonyms = True
|
||||||
@@ -395,6 +399,9 @@ class Table:
|
|||||||
def calc_offsets(self):
|
def calc_offsets(self):
|
||||||
current = 0
|
current = 0
|
||||||
for name, entry in self.data.items():
|
for name, entry in self.data.items():
|
||||||
|
if entry.kind == EntryKind.INSTR:
|
||||||
|
self.offsets[name] = entry.descidx << 2
|
||||||
|
else:
|
||||||
self.annotations[current] = "%s(%d)" % (name, entry.kind.value)
|
self.annotations[current] = "%s(%d)" % (name, entry.kind.value)
|
||||||
self.offsets[name] = current
|
self.offsets[name] = current
|
||||||
current += (entry.encode_length + 3) & ~3
|
current += (entry.encode_length + 3) & ~3
|
||||||
@@ -406,7 +413,7 @@ class Table:
|
|||||||
|
|
||||||
def compile(self):
|
def compile(self):
|
||||||
self.calc_offsets()
|
self.calc_offsets()
|
||||||
ordered = sorted((off, self.data[k]) for k, off in self.offsets.items())
|
ordered = sorted((off, self.data[k]) for k, off in self.offsets.items() if self.data[k].encode_length)
|
||||||
|
|
||||||
data = ()
|
data = ()
|
||||||
for off, entry in ordered:
|
for off, entry in ordered:
|
||||||
@@ -414,7 +421,7 @@ class Table:
|
|||||||
|
|
||||||
stats = dict(Counter(entry.kind for entry in self.data.values()))
|
stats = dict(Counter(entry.kind for entry in self.data.values()))
|
||||||
print("%d bytes" % (2*len(data)), stats)
|
print("%d bytes" % (2*len(data)), stats)
|
||||||
return data, self.annotations, [self.offsets[k] for k in self.roots]
|
return data, self.annotations, [self.offsets[k] for k in self.roots], self.descs
|
||||||
|
|
||||||
def bytes_to_table(data, notes):
|
def bytes_to_table(data, notes):
|
||||||
strdata = tuple(d+"," if type(d) == str else "%#04x,"%d for d in data)
|
strdata = tuple(d+"," if type(d) == str else "%#04x,"%d for d in data)
|
||||||
@@ -425,6 +432,8 @@ def bytes_to_table(data, notes):
|
|||||||
template = """// Auto-generated file -- do not modify!
|
template = """// Auto-generated file -- do not modify!
|
||||||
#if defined(FD_DECODE_TABLE_DATA)
|
#if defined(FD_DECODE_TABLE_DATA)
|
||||||
{hex_table}
|
{hex_table}
|
||||||
|
#elif defined(FD_DECODE_TABLE_DESCS)
|
||||||
|
{descs}
|
||||||
#elif defined(FD_DECODE_TABLE_STRTAB1)
|
#elif defined(FD_DECODE_TABLE_STRTAB1)
|
||||||
{mnemonic_cstr}
|
{mnemonic_cstr}
|
||||||
#elif defined(FD_DECODE_TABLE_STRTAB2)
|
#elif defined(FD_DECODE_TABLE_STRTAB2)
|
||||||
@@ -611,7 +620,7 @@ if __name__ == "__main__":
|
|||||||
table.add_opcode(opcode_path, desc.encode(ign66), i)
|
table.add_opcode(opcode_path, desc.encode(ign66), i)
|
||||||
|
|
||||||
table.deduplicate()
|
table.deduplicate()
|
||||||
table_data, annotations, root_offsets = table.compile()
|
table_data, annotations, root_offsets, descs = table.compile()
|
||||||
|
|
||||||
mnemonic_tab = [0]
|
mnemonic_tab = [0]
|
||||||
for name in mnemonics:
|
for name in mnemonics:
|
||||||
@@ -622,6 +631,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
decode_table = template.format(
|
decode_table = template.format(
|
||||||
hex_table=bytes_to_table(table_data, annotations),
|
hex_table=bytes_to_table(table_data, annotations),
|
||||||
|
descs="\n".join("{{{0},{1},{2},{3}}},".format(*desc) for desc in descs),
|
||||||
mnemonic_cstr=mnemonic_cstr,
|
mnemonic_cstr=mnemonic_cstr,
|
||||||
mnemonic_offsets=",".join(str(off) for off in mnemonic_tab),
|
mnemonic_offsets=",".join(str(off) for off in mnemonic_tab),
|
||||||
defines="\n".join("#define " + line for line in defines),
|
defines="\n".join("#define " + line for line in defines),
|
||||||
|
|||||||
Reference in New Issue
Block a user