diff --git a/decode.c b/decode.c index 15d6acb..a3f7909 100644 --- a/decode.c +++ b/decode.c @@ -12,21 +12,16 @@ #define LIKELY(x) __builtin_expect((x), 1) #define UNLIKELY(x) __builtin_expect((x), 0) -#if defined(ARCH_386) -#define FD_DECODE_TABLE_DATA_32 -static const uint8_t _decode_table32[] = { +#define FD_DECODE_TABLE_DATA +static const uint8_t _decode_table[] = { #include }; -#undef FD_DECODE_TABLE_DATA_32 -#endif +#undef FD_DECODE_TABLE_DATA -#if defined(ARCH_X86_64) -#define FD_DECODE_TABLE_DATA_64 -static const uint8_t _decode_table64[] = { +// Defines FD_TABLE_OFFSET_32 and FD_TABLE_OFFSET_64, if available +#define FD_DECODE_TABLE_DEFINES #include -}; -#undef FD_DECODE_TABLE_DATA_64 -#endif +#undef FD_DECODE_TABLE_DEFINES enum DecodeMode { DECODE_64 = 0, @@ -369,7 +364,7 @@ int fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, FdInstr* instr) { - const uint8_t* decode_table = NULL; + const uint16_t* table = NULL; int len = len_sz > 15 ? 15 : len_sz; DecodeMode mode = mode_int == 32 ? DECODE_32 : @@ -378,14 +373,14 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, // Ensure that we can actually handle the decode request #if defined(ARCH_386) if (mode == DECODE_32) - decode_table = _decode_table32; + table = (uint16_t*) &_decode_table[FD_TABLE_OFFSET_32]; #endif #if defined(ARCH_X86_64) if (mode == DECODE_64) - decode_table = _decode_table64; + table = (uint16_t*) &_decode_table[FD_TABLE_OFFSET_64]; #endif - if (UNLIKELY(decode_table == NULL)) + if (UNLIKELY(table == NULL)) return -2; int retval; @@ -402,26 +397,25 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, } off += retval; - const uint16_t* table = (uint16_t*) decode_table; uint32_t kind = ENTRY_TABLE256; if (UNLIKELY(prefixes & PREFIX_ESC_MASK)) { uint32_t escape = prefixes & PREFIX_ESC_MASK; - table = (uint16_t*) &decode_table[table[0x0F] & ~7]; + table = (uint16_t*) &_decode_table[table[0x0F] & ~7]; if (escape == PREFIX_ESC_0F38) { - table = (uint16_t*) &decode_table[table[0x38] & ~7]; + table = (uint16_t*) &_decode_table[table[0x38] & ~7]; } else if (escape == PREFIX_ESC_0F3A) { - table = (uint16_t*) &decode_table[table[0x3A] & ~7]; + table = (uint16_t*) &_decode_table[table[0x3A] & ~7]; } } // 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++]]); + 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)) @@ -438,7 +432,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, else entry = table[(buffer[off] >> 3) & 7]; - ENTRY_UNPACK(table, kind, decode_table, entry); + ENTRY_UNPACK(table, kind, _decode_table, entry); } // Finally, handle mandatory prefixes (which behave like an opcode ext.). @@ -452,7 +446,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, // for the 0x66 prefix, which could otherwise override the operand // size of general purpose registers. prefixes &= ~(PREFIX_OPSZ | PREFIX_REPNZ | PREFIX_REP); - ENTRY_UNPACK(table, kind, decode_table, table[index]); + ENTRY_UNPACK(table, kind, _decode_table, table[index]); } if (UNLIKELY(kind != ENTRY_INSTR)) diff --git a/meson.build b/meson.build index a111bd9..ae5e8cf 100644 --- a/meson.build +++ b/meson.build @@ -46,8 +46,15 @@ if not decode_32 and not decode_64 error('no architecture mode') endif +generate_args = [] +if decode_32 + generate_args += ['--32'] +endif +if decode_64 + generate_args += ['--64'] +endif instr_data = custom_target('tables', - command: [python3, '@INPUT0@', '@INPUT1@', '@OUTPUT@'], + command: [python3, '@INPUT0@', '@INPUT1@', '@OUTPUT@'] + generate_args, input: files('parseinstrs.py', 'instrs.txt'), output: ['decode-table.inc']) diff --git a/parseinstrs.py b/parseinstrs.py index 5f09036..0167559 100644 --- a/parseinstrs.py +++ b/parseinstrs.py @@ -210,6 +210,7 @@ def parse_opcode(opcode_string): class Table: def __init__(self, root_count=1): self.data = OrderedDict() + self.roots = ["root%d"%i for i in range(root_count)] for i in range(root_count): self.data["root%d"%i] = TrieEntry.table(EntryKind.TABLE256) self.offsets = {} @@ -276,7 +277,7 @@ class Table: stats = dict(Counter(entry.kind for entry in self.data.values())) print("%d bytes" % len(data), stats) - return data, self.annotations + return data, self.annotations, [self.offsets[k] for k in self.roots] def wrap(string): return "\n".join(string[i:i+80] for i in range(0, len(string), 80)) @@ -288,16 +289,16 @@ def bytes_to_table(data, notes): for p, c in zip(offs, offs[1:])) template = """// Auto-generated file -- do not modify! -#if defined(FD_DECODE_TABLE_DATA_32) -{hex_table32} -#elif defined(FD_DECODE_TABLE_DATA_64) -{hex_table64} +#if defined(FD_DECODE_TABLE_DATA) +{hex_table} #elif defined(FD_DECODE_TABLE_MNEMONICS) {mnemonic_list} #elif defined(FD_DECODE_TABLE_STRTAB1) {mnemonic_cstr} #elif defined(FD_DECODE_TABLE_STRTAB2) {mnemonic_offsets} +#elif defined(FD_DECODE_TABLE_DEFINES) +{defines} #else #error "unspecified decode table" #endif @@ -305,6 +306,8 @@ template = """// Auto-generated file -- do not modify! if __name__ == "__main__": parser = argparse.ArgumentParser() + parser.add_argument("--32", dest="modes", action="append_const", const=32) + parser.add_argument("--64", dest="modes", action="append_const", const=64) parser.add_argument("table", type=argparse.FileType('r')) parser.add_argument("output", type=argparse.FileType('w')) args = parser.parse_args() @@ -319,28 +322,28 @@ if __name__ == "__main__": mnemonics = sorted({desc.mnemonic for _, desc in entries}) mnemonics_lut = {name: mnemonics.index(name) for name in mnemonics} - table32 = Table() - table64 = Table() - masks = "ONLY64", "ONLY32" + modes = [32, 64] + table = Table(root_count=len(args.modes)) for opcode, desc in entries: - if "ONLY64" not in desc.flags: - table32.add_opcode(opcode, desc.encode(mnemonics_lut)) - if "ONLY32" not in desc.flags: - table64.add_opcode(opcode, desc.encode(mnemonics_lut)) + for i, mode in enumerate(args.modes): + if "ONLY%d"%(96-mode) not in desc.flags: + table.add_opcode(opcode, desc.encode(mnemonics_lut), i) - table32.deduplicate() - table64.deduplicate() + table.deduplicate() + table_data, annotations, root_offsets = table.compile() mnemonic_tab = [0] for name in mnemonics: mnemonic_tab.append(mnemonic_tab[-1] + len(name) + 1) mnemonic_cstr = '"' + "\\0".join(mnemonics) + '"' + defines = ["FD_TABLE_OFFSET_%d %d"%k for k in zip(args.modes, root_offsets)] + file = template.format( - hex_table32=bytes_to_table(*table32.compile()), - hex_table64=bytes_to_table(*table64.compile()), + hex_table=bytes_to_table(table_data, annotations), mnemonic_list="\n".join("FD_MNEMONIC(%s,%d)"%entry for entry in mnemonics_lut.items()), mnemonic_cstr=mnemonic_cstr, mnemonic_offsets=",".join(str(off) for off in mnemonic_tab), + defines="\n".join("#define " + line for line in defines), ) args.output.write(file)