From 7ee9320840838b6d698494f98cfd3b6cff156b95 Mon Sep 17 00:00:00 2001 From: Alexis Engelke Date: Tue, 30 Jun 2020 21:42:31 +0200 Subject: [PATCH] decode: Add second fixed operand size --- decode.c | 28 ++++++++++++++-------------- parseinstrs.py | 49 +++++++++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/decode.c b/decode.c index 4e53fa3..950ded8 100644 --- a/decode.c +++ b/decode.c @@ -303,15 +303,8 @@ struct InstrDesc { uint16_t type; uint8_t operand_indices; - uint8_t operand_sizes; uint8_t immediate; - - uint8_t gp_size_8 : 1; - uint8_t gp_size_def64 : 1; - uint8_t gp_instr_width : 1; - uint8_t gp_fixed_operand_size : 3; - uint8_t lock : 1; - uint8_t vsib : 1; + uint16_t operand_sizes; uint16_t reg_types; } __attribute__((packed)); @@ -326,6 +319,13 @@ struct InstrDesc #define DESC_IMM_CONTROL(desc) (((desc)->immediate >> 4) & 0x7) #define DESC_IMM_IDX(desc) (((desc)->immediate & 3) ^ 3) #define DESC_IMPLICIT_VAL(desc) (((desc)->immediate >> 2) & 1) +#define DESC_LOCK(desc) (((desc)->immediate >> 3) & 1) +#define DESC_VSIB(desc) (((desc)->immediate >> 7) & 1) +#define DESC_SIZE8(desc) (((desc)->operand_sizes >> 8) & 1) +#define DESC_SIZED64(desc) (((desc)->operand_sizes >> 9) & 1) +#define DESC_SIZE_FIX1(desc) (((desc)->operand_sizes >> 10) & 7) +#define DESC_SIZE_FIX2(desc) (((desc)->operand_sizes >> 13) & 3) +#define DESC_INSTR_WIDTH(desc) (((desc)->operand_sizes >> 15) & 1) int fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, @@ -445,13 +445,13 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, instr->address = address; uint8_t op_size = 0; - if (desc->gp_size_8) + if (DESC_SIZE8(desc)) op_size = 1; else if (mode == DECODE_64 && (prefixes & PREFIX_REXW)) op_size = 8; else if (prefixes & PREFIX_OPSZ) op_size = 2; - else if (mode == DECODE_64 && desc->gp_size_def64) + else if (mode == DECODE_64 && DESC_SIZED64(desc)) op_size = 8; else op_size = 4; @@ -492,7 +492,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, operand2 = &instr->operands[DESC_MODREG_IDX(desc)]; retval = decode_modrm(buffer + off, len - off, mode, instr, prefixes, - desc->vsib, operand1, operand2); + DESC_VSIB(desc), operand1, operand2); if (UNLIKELY(retval < 0)) return retval; off += retval; @@ -635,11 +635,11 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, } if (UNLIKELY(prefixes & PREFIX_LOCK)) - if (!desc->lock || instr->operands[0].type != FD_OT_MEM) + if (!DESC_LOCK(desc) || instr->operands[0].type != FD_OT_MEM) return FD_ERR_UD; uint8_t operand_sizes[4] = { - 0, 1 << desc->gp_fixed_operand_size, op_size, vec_size + 1 << DESC_SIZE_FIX1(desc) >> 1, 1 << DESC_SIZE_FIX2(desc), op_size, vec_size }; for (int i = 0; i < 4; i++) @@ -657,7 +657,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, } instr->size = off; - instr->operandsz = desc->gp_instr_width ? op_size : 0; + instr->operandsz = DESC_INSTR_WIDTH(desc) ? op_size : 0; return off; } diff --git a/parseinstrs.py b/parseinstrs.py index d6f606b..6996638 100644 --- a/parseinstrs.py +++ b/parseinstrs.py @@ -30,21 +30,20 @@ InstrFlags = bitstruct("InstrFlags", [ "modreg_idx:2", "vexreg_idx:2", "zeroreg_idx:2", + "imm_idx:2", + "zeroreg_val:1", + "lock:1", + "imm_control:3", + "vsib:1", "op0_size:2", "op1_size:2", "op2_size:2", "op3_size:2", - "imm_idx:2", - "zeroreg_val:1", - "_unused:1", - "imm_control:3", - "_unused:1", - "gp_size_8:1", - "gp_size_def64:1", - "gp_instr_width:1", - "gp_fixed_operand_size:3", - "lock:1", - "vsib:1", + "size8:1", + "sized64:1", + "size_fix1:3", + "size_fix2:2", + "instr_width:1", "op0_regty:3", "op1_regty:3", "op2_regty:3", @@ -135,8 +134,8 @@ class InstrDesc(NamedTuple): OPKIND_REGTYS = {"GP": 0, "FPU": 1, "XMM": 2, "MASK": 3, "MMX": 4, "BND": 5} OPKIND_SIZES = { - 0: (0,0), 1: (1,0), 2: (1,1), 4: (1,2), 8: (1,3), 16: (1,4), 32: (1,5), - OpKind.SZ_OP: (2,0), OpKind.SZ_VEC: (3,0), + 0: 0, 1: 1, 2: 2, 4: 3, 8: 4, 16: 5, 32: 6, 10: 0, + OpKind.SZ_OP: -2, OpKind.SZ_VEC: -3, } @classmethod @@ -148,23 +147,29 @@ class InstrDesc(NamedTuple): def encode(self): flags = copy(ENCODINGS[self.encoding]) - fixed_opsz = set() + opsz = set(self.OPKIND_SIZES[opkind.size] for opkind in self.operands) + + # Sort fixed sizes encodable in size_fix2 as second element. + fixed = sorted((x for x in opsz if x >= 0), key=lambda x: 1 <= x <= 4) + if len(fixed) > 2 or (len(fixed) == 2 and not (1 <= fixed[1] <= 4)): + raise Exception("invalid fixed operand sizes: %r"%fixed) + sizes = (fixed + [1, 1])[:2] + [-2, -3] # See operand_sizes in decode.c. + flags.size_fix1 = sizes[0] + flags.size_fix2 = sizes[1] - 1 + for i, opkind in enumerate(self.operands): - enc_size, fixed_size = self.OPKIND_SIZES.get(opkind.size, (0, 0)) + sz = self.OPKIND_SIZES[opkind.size] reg_type = self.OPKIND_REGTYS.get(opkind.kind, 7) - if enc_size == 1: fixed_opsz.add(fixed_size) - setattr(flags, "op%d_size"%i, enc_size) + setattr(flags, "op%d_size"%i, sizes.index(sz)) if i < 3: setattr(flags, "op%d_regty"%i, reg_type) elif reg_type not in (7, 2): raise Exception("invalid regty for op 3, must be VEC") - if fixed_opsz: flags.gp_fixed_operand_size = next(iter(fixed_opsz)) - # Miscellaneous Flags - if "DEF64" in self.flags: flags.gp_size_def64 = 1 - if "SIZE_8" in self.flags: flags.gp_size_8 = 1 - if "INSTR_WIDTH" in self.flags: flags.gp_instr_width = 1 + if "DEF64" in self.flags: flags.sized64 = 1 + if "SIZE_8" in self.flags: flags.size8 = 1 + if "INSTR_WIDTH" in self.flags: flags.instr_width = 1 if "IMM_8" in self.flags: flags.imm_control = {4: 5, 6: 7}[flags.imm_control] if "LOCK" in self.flags: flags.lock = 1 if "VSIB" in self.flags: flags.vsib = 1