Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion arch/M68K/M68KDisassembler.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,22 @@ static unsigned long long read_imm_64(m68k_info *info)
return value & 0xffffffffffffffff;
}

/* Read a 12-byte Motorola extended-precision immediate: sign+exponent word,
* reserved word, and 64-bit significand. */
static bool read_imm_extended(m68k_info *info, m68k_op_fp_extended *value)
{
const uint64_t addr = (info->pc - info->baseAddress) &
info->address_mask;
if (addr > info->code_len || info->code_len - addr < 12)
return false;

memset(value, 0, sizeof(*value));
value->sign_exp = (uint16_t)read_imm_16(info);
value->reserved = (uint16_t)read_imm_16(info);
value->significand = read_imm_64(info);
return true;
}

/* 100% portable signed int generators */
static int make_int_8(int value)
{
Expand Down Expand Up @@ -3184,7 +3200,15 @@ static void d68020_cpgen(m68k_info *info)
case M68K_FPSRC_EXTENDED:
ext->op_size.type = M68K_SIZE_TYPE_FPU;
ext->op_size.fpu_size = M68K_FPU_SIZE_EXTENDED;
if (!get_ea_mode_op(info, op0, info->ir, 12)) {
if (m68k_ea_is_immediate(info->ir)) {
if (!read_imm_extended(info,
&op0->fp_extended)) {
invalid_insn(info);
return;
}
op0->address_mode = M68K_AM_IMMEDIATE;
op0->type = M68K_OP_FP_EXTENDED;
} else if (!get_ea_mode_op(info, op0, info->ir, 12)) {
invalid_insn(info);
return;
}
Expand Down
83 changes: 81 additions & 2 deletions arch/M68K/M68KInstPrinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "../../MCInst.h"
#include "../../MCInstrDesc.h"
#include "../../MCRegisterInfo.h"
#include "../../MathExtras.h"

#ifndef CAPSTONE_DIET
static const char s_spacing[] = " ";
Expand Down Expand Up @@ -211,6 +212,79 @@ static void printBitfield(SStream *O, const cs_m68k_op *op)
SStream_concat0(O, "}");
}

#if !defined(_KERNEL_MODE)
/* Round `value >> shift` to nearest, ties to even. Requires 1 <= shift <= 64. */
static uint64_t round_right_to_even(uint64_t value, unsigned int shift)
{
if (shift < 64) {
uint64_t quotient = value >> shift;
uint64_t remainder = value & ((1ULL << shift) - 1);
uint64_t halfway = 1ULL << (shift - 1);
if (remainder > halfway ||
(remainder == halfway && (quotient & 1)))
return quotient + 1;
return quotient;
}
if (value > 0x8000000000000000ULL)
return 1;
return 0;
}

/* Convert only for assembly-text rendering. The detail operand retains the
* complete external representation in fp_extended. */
static double extended_to_double(const m68k_op_fp_extended *value)
{
const uint16_t sign_exp = value->sign_exp;
const uint64_t significand = value->significand;
const uint64_t sign = ((uint64_t)(sign_exp & 0x8000)) << 48;
const unsigned int E = sign_exp & 0x7fff;

if (E == 0x7fff) {
uint64_t fraction = significand & 0x7fffffffffffffffULL;
if (fraction == 0)
return BitsToDouble(sign | 0x7ff0000000000000ULL);
return BitsToDouble(sign | 0x7ff0000000000000ULL |
((fraction >> 11) | 0x0008000000000000ULL));
}

if (E == 0 || significand == 0)
return BitsToDouble(sign);

{
unsigned int leading = CountLeadingZeros_64(significand);
uint64_t normalized = significand << leading;
int64_t e = (int64_t)E - 16383 - (int64_t)leading;

if (e > 1023)
return BitsToDouble(sign | 0x7ff0000000000000ULL);

if (e >= -1022) {
uint64_t rounded = round_right_to_even(normalized, 11);
if (rounded == (1ULL << 53)) {
rounded >>= 1;
++e;
if (e > 1023)
return BitsToDouble(
sign | 0x7ff0000000000000ULL);
}
return BitsToDouble(sign |
((uint64_t)(e + 1023) << 52) |
(rounded & 0x000fffffffffffffULL));
}

{
uint64_t shift = (uint64_t)(-e - 1011);
uint64_t fraction =
shift > 64 ? 0 :
round_right_to_even(
normalized,
(unsigned int)shift);
return BitsToDouble(sign | fraction);
}
}
}
#endif

static void printImmediate(SStream *O, const cs_m68k *inst,
const cs_m68k_op *op)
{
Expand All @@ -219,10 +293,15 @@ static void printImmediate(SStream *O, const cs_m68k *inst,
SStream_concat(O, "#<float_point_unsupported>");
return;
#else
if (inst->op_size.fpu_size == M68K_FPU_SIZE_SINGLE)
/* Dispatch on the operand storage type. Extended immediates
* are converted only for GNU-compatible assembly text. */
if (op->type == M68K_OP_FP_SINGLE)
SStream_concat(O, "#%f", op->simm);
else if (inst->op_size.fpu_size == M68K_FPU_SIZE_DOUBLE)
else if (op->type == M68K_OP_FP_DOUBLE)
SStream_concat(O, "#%f", op->dimm);
else if (op->type == M68K_OP_FP_EXTENDED)
SStream_concat(O, "#0e%g",
extended_to_double(&op->fp_extended));
else
SStream_concat(O, "#<unsupported>");
return;
Expand Down
3 changes: 2 additions & 1 deletion bindings/java/capstone/M68k_const.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public class M68k_const {
public static final int M68K_OP_REG_PAIR = CS_OP_SPECIAL+3;
public static final int M68K_OP_BR_DISP = CS_OP_SPECIAL+4;
public static final int M68K_OP_SHIFT = CS_OP_SPECIAL+5;
public static final int M68K_OP_FP_EXTENDED = CS_OP_SPECIAL+6;
public static final int M68K_OP_MEM = CS_OP_MEM;

public static final int M68K_OP_FLAG_NONE = 0;
Expand Down Expand Up @@ -534,4 +535,4 @@ public class M68k_const {
public static final int M68K_GRP_IRET = 5;
public static final int M68K_GRP_BRANCH_RELATIVE = 7;
public static final int M68K_GRP_ENDING = 8;
}
}
1 change: 1 addition & 0 deletions bindings/ocaml/m68k_const.ml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ let _M68K_OP_FP_DOUBLE = _CS_OP_SPECIAL+1;;
let _M68K_OP_REG_BITS = _CS_OP_SPECIAL+2;;
let _M68K_OP_REG_PAIR = _CS_OP_SPECIAL+3;;
let _M68K_OP_BR_DISP = _CS_OP_SPECIAL+4;;
let _M68K_OP_FP_EXTENDED = _CS_OP_SPECIAL+6;;
let _M68K_OP_MEM = _CS_OP_MEM;;

let _M68K_OP_BR_DISP_SIZE_INVALID = 0;;
Expand Down
13 changes: 13 additions & 0 deletions bindings/python/capstone/m68k.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,20 @@ class M68KOpRegPair(ctypes.Structure):
)


class M68KOpFpExtended(ctypes.Structure):
_fields_ = (
("significand", ctypes.c_uint64),
("sign_exp", ctypes.c_uint16),
("reserved", ctypes.c_uint16),
)


class M68KOpValue(ctypes.Union):
_fields_ = (
("imm", ctypes.c_int64),
("dimm", ctypes.c_double),
("simm", ctypes.c_float),
("fp_extended", M68KOpFpExtended),
("reg", ctypes.c_uint),
("reg_pair", M68KOpRegPair),
)
Expand Down Expand Up @@ -73,6 +82,10 @@ def dimm(self):
def simm(self):
return self.value.simm

@property
def fp_extended(self):
return self.value.fp_extended

@property
def reg(self):
return self.value.reg
Expand Down
38 changes: 26 additions & 12 deletions bindings/python/capstone/m68k_const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
from . import CS_OP_INVALID, CS_OP_REG, CS_OP_IMM, CS_OP_FP, CS_OP_PRED, CS_OP_SPECIAL, CS_OP_MEM, CS_OP_MEM_REG, CS_OP_MEM_IMM, UINT16_MAX, UINT8_MAX
from . import (
CS_OP_INVALID,
CS_OP_REG,
CS_OP_IMM,
CS_OP_FP,
CS_OP_PRED,
CS_OP_SPECIAL,
CS_OP_MEM,
CS_OP_MEM_REG,
CS_OP_MEM_IMM,
UINT16_MAX,
UINT8_MAX,
)

# For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [m68k_const.py]
M68K_OPERAND_COUNT = 6

Expand Down Expand Up @@ -86,20 +99,21 @@
M68K_OP_INVALID = CS_OP_INVALID
M68K_OP_REG = CS_OP_REG
M68K_OP_IMM = CS_OP_IMM
M68K_OP_FP_SINGLE = CS_OP_SPECIAL+0
M68K_OP_FP_DOUBLE = CS_OP_SPECIAL+1
M68K_OP_REG_BITS = CS_OP_SPECIAL+2
M68K_OP_REG_PAIR = CS_OP_SPECIAL+3
M68K_OP_BR_DISP = CS_OP_SPECIAL+4
M68K_OP_SHIFT = CS_OP_SPECIAL+5
M68K_OP_FP_SINGLE = CS_OP_SPECIAL + 0
M68K_OP_FP_DOUBLE = CS_OP_SPECIAL + 1
M68K_OP_REG_BITS = CS_OP_SPECIAL + 2
M68K_OP_REG_PAIR = CS_OP_SPECIAL + 3
M68K_OP_BR_DISP = CS_OP_SPECIAL + 4
M68K_OP_SHIFT = CS_OP_SPECIAL + 5
M68K_OP_FP_EXTENDED = CS_OP_SPECIAL + 6
M68K_OP_MEM = CS_OP_MEM

M68K_OP_FLAG_NONE = 0
M68K_OP_FLAG_REG_LOWER = 1<<0
M68K_OP_FLAG_REG_UPPER = 1<<1
M68K_OP_FLAG_SHIFT_LEFT = 1<<2
M68K_OP_FLAG_SHIFT_RIGHT = 1<<3
M68K_OP_FLAG_MEM_UPDATE = 1<<4
M68K_OP_FLAG_REG_LOWER = 1 << 0
M68K_OP_FLAG_REG_UPPER = 1 << 1
M68K_OP_FLAG_SHIFT_LEFT = 1 << 2
M68K_OP_FLAG_SHIFT_RIGHT = 1 << 3
M68K_OP_FLAG_MEM_UPDATE = 1 << 4
M68K_BF_REG_FLAG = 0x80

M68K_OP_BR_DISP_SIZE_INVALID = 0
Expand Down
21 changes: 21 additions & 0 deletions bindings/python/cstest_py/src/cstest_py/details.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
M68K_OP_BR_DISP,
M68K_OP_REG_BITS,
M68K_OP_FP_DOUBLE,
M68K_OP_FP_EXTENDED,
M68K_OP_FP_SINGLE,
M68K_OP_MEM,
M68K_OP_SHIFT,
Expand Down Expand Up @@ -1146,6 +1147,26 @@ def test_expected_m68k(actual: CsInsn, expected: dict) -> bool:
elif aop.type == M68K_OP_FP_DOUBLE:
if not compare_dp(aop.dimm, eop.get("dimm"), "dimm"):
return False
elif aop.type == M68K_OP_FP_EXTENDED:
fp_extended = eop.get("fp_extended", {})
if not compare_uint64(
aop.fp_extended.significand,
fp_extended.get("significand"),
"fp_extended.significand",
):
return False
if not compare_uint16(
aop.fp_extended.sign_exp,
fp_extended.get("sign_exp"),
"fp_extended.sign_exp",
):
return False
if not compare_uint16(
aop.fp_extended.reserved,
fp_extended.get("reserved"),
"fp_extended.reserved",
):
return False
elif aop.type == M68K_OP_FP_SINGLE:
if not compare_fp(aop.simm, eop.get("simm"), "simm"):
return False
Expand Down
12 changes: 12 additions & 0 deletions cstool/cstool_m68k.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ void print_insn_detail_m68k(csh handle, cs_insn *ins)
printf("\t\toperands[%u].type: FP_DOUBLE\n", i);
printf("\t\t\toperands[%u].dimm: %lf\n", i, op->dimm);
break;
case M68K_OP_FP_EXTENDED:
printf("\t\toperands[%u].type: FP_EXTENDED\n", i);
printf("\t\t\toperands[%u].fp_extended.sign_exp: "
"0x%04" PRIx16 "\n",
i, op->fp_extended.sign_exp);
printf("\t\t\toperands[%u].fp_extended.reserved: "
"0x%04" PRIx16 "\n",
i, op->fp_extended.reserved);
printf("\t\t\toperands[%u].fp_extended.significand: "
"0x%016" PRIx64 "\n",
i, op->fp_extended.significand);
break;
case M68K_OP_SHIFT:
printf("\t\toperands[%u].type: SHIFT\n", i);
break;
Expand Down
14 changes: 14 additions & 0 deletions include/capstone/m68k.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ typedef enum m68k_op_type {
/// Shift-direction pseudo operand.
/// Shift direction is set in cs_m68k_op.flags
M68K_OP_SHIFT = CS_OP_SPECIAL + 5,
/// Extended precision Floating-Point operand.
M68K_OP_FP_EXTENDED = CS_OP_SPECIAL + 6,
M68K_OP_MEM = CS_OP_MEM, ///< = CS_OP_MEM (Memory operand).
} m68k_op_type;

Expand Down Expand Up @@ -199,12 +201,24 @@ typedef struct cs_m68k_op_reg_pair {
m68k_reg reg_1;
} cs_m68k_op_reg_pair;

/// Motorola extended-precision real in its 96-bit external representation.
/// The fields are host-endian components, not a packed 12-byte buffer.
typedef struct m68k_op_fp_extended {
/// Explicit integer bit followed by the 63-bit fractional part.
uint64_t significand;
/// Sign in bit 15 and the 15-bit biased exponent in bits 14-0.
uint16_t sign_exp;
/// Raw reserved word from the external representation.
uint16_t reserved;
} m68k_op_fp_extended;

/// Instruction operand
typedef struct cs_m68k_op {
union {
uint64_t imm; ///< immediate value for IMM operand
double dimm; ///< double imm
float simm; ///< float imm
m68k_op_fp_extended fp_extended; ///< extended-precision immediate
m68k_reg reg; ///< register value for REG operand
cs_m68k_op_reg_pair reg_pair; ///< register pair in one operand
};
Expand Down
21 changes: 21 additions & 0 deletions suite/cstest/include/test_detail_m68k.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ static const cyaml_schema_field_t test_detail_m68k_op_mem_mapping_schema[] = {
CYAML_FIELD_END
};

typedef struct {
uint64_t significand;
uint16_t sign_exp;
uint16_t reserved;
} TestDetailM68KOpFpExtended;

static const cyaml_schema_field_t
test_detail_m68k_op_fp_extended_mapping_schema[] = {
CYAML_FIELD_UINT("significand", CYAML_FLAG_OPTIONAL,
TestDetailM68KOpFpExtended, significand),
CYAML_FIELD_UINT("sign_exp", CYAML_FLAG_OPTIONAL,
TestDetailM68KOpFpExtended, sign_exp),
CYAML_FIELD_UINT("reserved", CYAML_FLAG_OPTIONAL,
TestDetailM68KOpFpExtended, reserved),
CYAML_FIELD_END
};

typedef struct {
char *type;
char *address_mode;
Expand All @@ -82,6 +99,7 @@ typedef struct {
double dimm;
float simm;

TestDetailM68KOpFpExtended *fp_extended;
TestDetailM68KOpMem *mem;
char **flags;
size_t flags_count;
Expand Down Expand Up @@ -114,6 +132,9 @@ static const cyaml_schema_field_t test_detail_m68k_op_mapping_schema[] = {
register_bits),
CYAML_FIELD_FLOAT("dimm", CYAML_FLAG_OPTIONAL, TestDetailM68KOp, dimm),
CYAML_FIELD_FLOAT("simm", CYAML_FLAG_OPTIONAL, TestDetailM68KOp, simm),
CYAML_FIELD_MAPPING_PTR("fp_extended", CYAML_FLAG_OPTIONAL,
TestDetailM68KOp, fp_extended,
test_detail_m68k_op_fp_extended_mapping_schema),
CYAML_FIELD_MAPPING_PTR("mem", CYAML_FLAG_OPTIONAL, TestDetailM68KOp,
mem, test_detail_m68k_op_mem_mapping_schema),
CYAML_FIELD_SEQUENCE("flags", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
Expand Down
1 change: 1 addition & 0 deletions suite/cstest/include/test_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,7 @@ static const cs_enum_id_map cs_enum_map[] = {
{ .str = "M68K_OP_FLAG_SHIFT_LEFT", .val = M68K_OP_FLAG_SHIFT_LEFT },
{ .str = "M68K_OP_FLAG_SHIFT_RIGHT", .val = M68K_OP_FLAG_SHIFT_RIGHT },
{ .str = "M68K_OP_FP_DOUBLE", .val = M68K_OP_FP_DOUBLE },
{ .str = "M68K_OP_FP_EXTENDED", .val = M68K_OP_FP_EXTENDED },
{ .str = "M68K_OP_FP_SINGLE", .val = M68K_OP_FP_SINGLE },
{ .str = "M68K_OP_IMM", .val = M68K_OP_IMM },
{ .str = "M68K_OP_MEM", .val = M68K_OP_MEM },
Expand Down
Loading
Loading