diff --git a/decode.c b/decode.c index 5928242..dec6542 100644 --- a/decode.c +++ b/decode.c @@ -494,47 +494,51 @@ skip_modrm: } else if (imm_control != 0) { - FdOp* operand = &instr->operands[DESC_IMM_IDX(desc)]; - operand->type = FD_OT_IMM; - operand->size = operand_sizes[(desc->operand_sizes >> 6) & 3]; - // 4/5 = immediate, operand-sized/8 bit // 6/7 = offset, operand-sized/8 bit (used for jumps/calls) int imm_byte = imm_control & 1; int imm_offset = imm_control & 2; - uint8_t imm_size; - if (imm_byte) - imm_size = 1; - else if (UNLIKELY(instr->type == FDI_RET || instr->type == FDI_RETF || - instr->type == FDI_SSE_EXTRQ || - instr->type == FDI_SSE_INSERTQ)) - imm_size = 2; - else if (UNLIKELY(instr->type == FDI_JMPF || instr->type == FDI_CALLF)) - imm_size = (1 << op_size >> 1) + 2; - else if (UNLIKELY(instr->type == FDI_ENTER)) - imm_size = 3; - else if (instr->type == FDI_MOVABS) - imm_size = (1 << op_size >> 1); - else - imm_size = op_size == 2 ? 2 : 4; + FdOp* operand = &instr->operands[DESC_IMM_IDX(desc)]; + operand->type = FD_OT_IMM; - if (UNLIKELY(off + imm_size > len)) - return FD_ERR_PARTIAL; + if (imm_byte) { + if (UNLIKELY(off + 1 > len)) + return FD_ERR_PARTIAL; + instr->imm = (int8_t) LOAD_LE_1(&buffer[off++]); + operand->size = desc->operand_sizes & 0x40 ? 1 : op_size; + } else { + operand->size = operand_sizes[(desc->operand_sizes >> 6) & 3]; - if (imm_size == 1) - instr->imm = (int8_t) LOAD_LE_1(&buffer[off]); - else if (imm_size == 2) - instr->imm = (int16_t) LOAD_LE_2(&buffer[off]); - else if (imm_size == 3) - instr->imm = LOAD_LE_3(&buffer[off]); - else if (imm_size == 4) - instr->imm = (int32_t) LOAD_LE_4(&buffer[off]); - else if (imm_size == 6) - instr->imm = LOAD_LE_4(&buffer[off]) | LOAD_LE_2(&buffer[off+4]) << 32; - else if (imm_size == 8) - instr->imm = (int64_t) LOAD_LE_8(&buffer[off]); - off += imm_size; + uint8_t imm_size; + if (UNLIKELY(instr->type == FDI_RET || instr->type == FDI_RETF || + instr->type == FDI_SSE_EXTRQ || + instr->type == FDI_SSE_INSERTQ)) + imm_size = 2; + else if (UNLIKELY(instr->type == FDI_JMPF || instr->type == FDI_CALLF)) + imm_size = (1 << op_size >> 1) + 2; + else if (UNLIKELY(instr->type == FDI_ENTER)) + imm_size = 3; + else if (instr->type == FDI_MOVABS) + imm_size = (1 << op_size >> 1); + else + imm_size = op_size == 2 ? 2 : 4; + + if (UNLIKELY(off + imm_size > len)) + return FD_ERR_PARTIAL; + + if (imm_size == 2) + instr->imm = (int16_t) LOAD_LE_2(&buffer[off]); + else if (imm_size == 3) + instr->imm = LOAD_LE_3(&buffer[off]); + else if (imm_size == 4) + instr->imm = (int32_t) LOAD_LE_4(&buffer[off]); + else if (imm_size == 6) + instr->imm = LOAD_LE_4(&buffer[off]) | LOAD_LE_2(&buffer[off+4]) << 32; + else if (imm_size == 8) + instr->imm = (int64_t) LOAD_LE_8(&buffer[off]); + off += imm_size; + } if (imm_offset) { diff --git a/parseinstrs.py b/parseinstrs.py index 2aa6e36..35bab67 100644 --- a/parseinstrs.py +++ b/parseinstrs.py @@ -269,8 +269,13 @@ class InstrDesc(NamedTuple): extraflags["instr_width"] = "INSTR_WIDTH" in self.flags extraflags["lock"] = "LOCK" in self.flags + imm_byte = self.imm_size(4) == 1 + extraflags["imm_control"] = flags.imm_control | imm_byte + # Sort fixed sizes encodable in size_fix2 as second element. - fixed = set(self.OPKIND_SIZES[op.size] for op in self.operands if op.size >= 0) + # But: byte-sized immediates are handled specially and don't cost space. + fixed = set(self.OPKIND_SIZES[op.size] for op in self.operands if + op.size >= 0 and not (imm_byte and op.kind == "IMM")) fixed = sorted(fixed, key=lambda x: 1 <= x <= 4) if len(fixed) > 2 or (len(fixed) == 2 and not (1 <= fixed[1] <= 4)): raise Exception(f"invalid fixed sizes {fixed} in {self}") @@ -280,9 +285,14 @@ class InstrDesc(NamedTuple): for i, opkind in enumerate(self.operands): sz = self.OPKIND_SIZES[opkind.size] if opkind.size >= 0 else opkind.size - opname = ENCODING_OPORDER[self.encoding][i] - extraflags[f"{opname}_size"] = sizes.index(sz) - extraflags[f"{opname}_ty"] = self.OPKIND_REGTYS[opname, opkind.kind] + if opkind.kind == "IMM": + if imm_byte and sz not in (dynsizes[0], 1): + raise Exception(f"imm_byte with opsize {sz} in {self}") + extraflags[f"imm_size"] = sz == 1 if imm_byte else sizes.index(sz) + else: + opname = ENCODING_OPORDER[self.encoding][i] + extraflags[f"{opname}_size"] = sizes.index(sz) + extraflags[f"{opname}_ty"] = self.OPKIND_REGTYS[opname, opkind.kind] # Miscellaneous Flags if "VSIB" in self.flags: extraflags["vsib"] = 1 @@ -291,9 +301,6 @@ class InstrDesc(NamedTuple): if "U66" not in self.flags and (ign66 or "I66" in self.flags): extraflags["ign66"] = 1 - if self.imm_size(4) == 1: - extraflags["imm_control"] = flags.imm_control | 1 - enc = flags._replace(**extraflags)._encode() enc = tuple((enc >> i) & 0xffff for i in range(0, 48, 16)) # First 2 bytes are the mnemonic, last 6 bytes are the encoding.