decode: Handle imm_byte size differently
For byte-sized immediates, there are only two options for the operand size: byte and the instruction's operand size. This knowledge allows to remove the byte constraint from the set of fixed operand sizes.
This commit is contained in:
72
decode.c
72
decode.c
@@ -494,47 +494,51 @@ skip_modrm:
|
|||||||
}
|
}
|
||||||
else if (imm_control != 0)
|
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
|
// 4/5 = immediate, operand-sized/8 bit
|
||||||
// 6/7 = offset, operand-sized/8 bit (used for jumps/calls)
|
// 6/7 = offset, operand-sized/8 bit (used for jumps/calls)
|
||||||
int imm_byte = imm_control & 1;
|
int imm_byte = imm_control & 1;
|
||||||
int imm_offset = imm_control & 2;
|
int imm_offset = imm_control & 2;
|
||||||
|
|
||||||
uint8_t imm_size;
|
FdOp* operand = &instr->operands[DESC_IMM_IDX(desc)];
|
||||||
if (imm_byte)
|
operand->type = FD_OT_IMM;
|
||||||
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;
|
|
||||||
|
|
||||||
if (UNLIKELY(off + imm_size > len))
|
if (imm_byte) {
|
||||||
return FD_ERR_PARTIAL;
|
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)
|
uint8_t imm_size;
|
||||||
instr->imm = (int8_t) LOAD_LE_1(&buffer[off]);
|
if (UNLIKELY(instr->type == FDI_RET || instr->type == FDI_RETF ||
|
||||||
else if (imm_size == 2)
|
instr->type == FDI_SSE_EXTRQ ||
|
||||||
instr->imm = (int16_t) LOAD_LE_2(&buffer[off]);
|
instr->type == FDI_SSE_INSERTQ))
|
||||||
else if (imm_size == 3)
|
imm_size = 2;
|
||||||
instr->imm = LOAD_LE_3(&buffer[off]);
|
else if (UNLIKELY(instr->type == FDI_JMPF || instr->type == FDI_CALLF))
|
||||||
else if (imm_size == 4)
|
imm_size = (1 << op_size >> 1) + 2;
|
||||||
instr->imm = (int32_t) LOAD_LE_4(&buffer[off]);
|
else if (UNLIKELY(instr->type == FDI_ENTER))
|
||||||
else if (imm_size == 6)
|
imm_size = 3;
|
||||||
instr->imm = LOAD_LE_4(&buffer[off]) | LOAD_LE_2(&buffer[off+4]) << 32;
|
else if (instr->type == FDI_MOVABS)
|
||||||
else if (imm_size == 8)
|
imm_size = (1 << op_size >> 1);
|
||||||
instr->imm = (int64_t) LOAD_LE_8(&buffer[off]);
|
else
|
||||||
off += imm_size;
|
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)
|
if (imm_offset)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -269,8 +269,13 @@ class InstrDesc(NamedTuple):
|
|||||||
extraflags["instr_width"] = "INSTR_WIDTH" in self.flags
|
extraflags["instr_width"] = "INSTR_WIDTH" in self.flags
|
||||||
extraflags["lock"] = "LOCK" 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.
|
# 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)
|
fixed = sorted(fixed, key=lambda x: 1 <= x <= 4)
|
||||||
if len(fixed) > 2 or (len(fixed) == 2 and not (1 <= fixed[1] <= 4)):
|
if len(fixed) > 2 or (len(fixed) == 2 and not (1 <= fixed[1] <= 4)):
|
||||||
raise Exception(f"invalid fixed sizes {fixed} in {self}")
|
raise Exception(f"invalid fixed sizes {fixed} in {self}")
|
||||||
@@ -280,9 +285,14 @@ class InstrDesc(NamedTuple):
|
|||||||
|
|
||||||
for i, opkind in enumerate(self.operands):
|
for i, opkind in enumerate(self.operands):
|
||||||
sz = self.OPKIND_SIZES[opkind.size] if opkind.size >= 0 else opkind.size
|
sz = self.OPKIND_SIZES[opkind.size] if opkind.size >= 0 else opkind.size
|
||||||
opname = ENCODING_OPORDER[self.encoding][i]
|
if opkind.kind == "IMM":
|
||||||
extraflags[f"{opname}_size"] = sizes.index(sz)
|
if imm_byte and sz not in (dynsizes[0], 1):
|
||||||
extraflags[f"{opname}_ty"] = self.OPKIND_REGTYS[opname, opkind.kind]
|
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
|
# Miscellaneous Flags
|
||||||
if "VSIB" in self.flags: extraflags["vsib"] = 1
|
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):
|
if "U66" not in self.flags and (ign66 or "I66" in self.flags):
|
||||||
extraflags["ign66"] = 1
|
extraflags["ign66"] = 1
|
||||||
|
|
||||||
if self.imm_size(4) == 1:
|
|
||||||
extraflags["imm_control"] = flags.imm_control | 1
|
|
||||||
|
|
||||||
enc = flags._replace(**extraflags)._encode()
|
enc = flags._replace(**extraflags)._encode()
|
||||||
enc = tuple((enc >> i) & 0xffff for i in range(0, 48, 16))
|
enc = tuple((enc >> i) & 0xffff for i in range(0, 48, 16))
|
||||||
# First 2 bytes are the mnemonic, last 6 bytes are the encoding.
|
# First 2 bytes are the mnemonic, last 6 bytes are the encoding.
|
||||||
|
|||||||
Reference in New Issue
Block a user