M68K: Branch targets are a separate addressing mode; PC relative displacements printed as target addresses (#1068)

* Branch targets are a separate addressing mode

Branch targets are relative displacements that identify code locations. These are neither .w nor .l nor immediates. This change removes the immediate #s before branch target addresses in disassembly, and represents the actual branch instructions more accurately in the cs_m68k_op datastructure.

M68K Python bindings have also been updated.

* m68k_inst.pc handles better; print target for PC relative offsets

Previous changes to branch operations relied on m68k_inst.pc pointing to (start of instruction + 2). This was not the case - it pointed to the end of the current instruction. This change makes it so that m68k_inst.pc points to (start of instruction), which is simple to work with.

It also changes printing of PC relative offsets to print the absolute target address, which is consistent with how most 68000 assemblers & disassemblers behave.
This commit is contained in:
Kalmalyzer 2018-01-06 13:13:41 +01:00 committed by Nguyen Anh Quynh
parent 775a1d9825
commit 9944bfde76
6 changed files with 128 additions and 73 deletions

View File

@ -759,7 +759,23 @@ static void build_imm_special_reg(m68k_info *info, int opcode, int imm, int size
op1->reg = reg;
}
static void build_bxx(m68k_info *info, int opcode, int size, int jump_offset)
static void build_relative_branch(m68k_info *info, int opcode, int size, int displacement)
{
cs_m68k_op* op;
cs_m68k* ext = build_init_op(info, opcode, 1, size);
op = &ext->operands[0];
op->type = M68K_OP_BR_DISP;
op->address_mode = M68K_AM_BRANCH_DISPLACEMENT;
op->br_disp.disp = displacement;
op->br_disp.disp_size = size;
set_insn_group(info, M68K_GRP_JUMP);
set_insn_group(info, M68K_GRP_BRANCH_RELATIVE);
}
static void build_absolute_jump_with_immediate(m68k_info *info, int opcode, int size, int immediate)
{
cs_m68k_op* op;
cs_m68k* ext = build_init_op(info, opcode, 1, size);
@ -768,23 +784,22 @@ static void build_bxx(m68k_info *info, int opcode, int size, int jump_offset)
op->type = M68K_OP_IMM;
op->address_mode = M68K_AM_IMMEDIATE;
op->imm = jump_offset;
op->imm = immediate;
set_insn_group(info, M68K_GRP_JUMP);
set_insn_group(info, M68K_GRP_BRANCH_RELATIVE);
}
static void build_bcc(m68k_info *info, int size, int jump_offset)
static void build_bcc(m68k_info *info, int size, int displacement)
{
build_bxx(info, s_branch_lut[(info->ir >> 8) & 0xf], size, jump_offset);
build_relative_branch(info, s_branch_lut[(info->ir >> 8) & 0xf], size, displacement);
}
static void build_trap(m68k_info *info, int size, int jump_offset)
static void build_trap(m68k_info *info, int size, int immediate)
{
build_bxx(info, s_trap_lut[(info->ir >> 8) & 0xf], size, jump_offset);
build_absolute_jump_with_immediate(info, s_trap_lut[(info->ir >> 8) & 0xf], size, immediate);
}
static void build_dbxx(m68k_info *info, int opcode, int size, int jump_offset)
static void build_dbxx(m68k_info *info, int opcode, int size, int displacement)
{
cs_m68k_op* op0;
cs_m68k_op* op1;
@ -796,17 +811,18 @@ static void build_dbxx(m68k_info *info, int opcode, int size, int jump_offset)
op0->address_mode = M68K_AM_REG_DIRECT_DATA;
op0->reg = M68K_REG_D0 + (info->ir & 7);
op1->type = M68K_OP_IMM;
op1->address_mode = M68K_AM_IMMEDIATE;
op1->imm = jump_offset;
op1->type = M68K_OP_BR_DISP;
op1->address_mode = M68K_AM_BRANCH_DISPLACEMENT;
op1->br_disp.disp = displacement;
op1->br_disp.disp_size = M68K_OP_BR_DISP_SIZE_LONG;
set_insn_group(info, M68K_GRP_JUMP);
set_insn_group(info, M68K_GRP_BRANCH_RELATIVE);
}
static void build_dbcc(m68k_info *info, int size, int jump_offset)
static void build_dbcc(m68k_info *info, int size, int displacement)
{
build_dbxx(info, s_dbcc_lut[(info->ir >> 8) & 0xf], size, jump_offset);
build_dbxx(info, s_dbcc_lut[(info->ir >> 8) & 0xf], size, displacement);
}
static void build_d_d_ea(m68k_info *info, int opcode, int size)
@ -1456,21 +1472,18 @@ static void d68000_asl_ea(m68k_info *info)
static void d68000_bcc_8(m68k_info *info)
{
uint temp_pc = info->pc;
build_bcc(info, 1, temp_pc + make_int_8(info->ir));
build_bcc(info, 1, make_int_8(info->ir));
}
static void d68000_bcc_16(m68k_info *info)
{
uint temp_pc = info->pc;
build_bcc(info, 2, temp_pc + make_int_16(read_imm_16(info)));
build_bcc(info, 2, make_int_16(read_imm_16(info)));
}
static void d68020_bcc_32(m68k_info *info)
{
uint temp_pc = info->pc;
LIMIT_CPU_TYPES(info, M68020_PLUS);
build_bcc(info, 4, temp_pc + read_imm_32(info));
build_bcc(info, 4, read_imm_32(info));
}
static void d68000_bchg_r(m68k_info *info)
@ -1496,7 +1509,7 @@ static void d68000_bclr_s(m68k_info *info)
static void d68010_bkpt(m68k_info *info)
{
LIMIT_CPU_TYPES(info, M68010_PLUS);
build_bxx(info, M68K_INS_BKPT, 0, info->ir & 7);
build_absolute_jump_with_immediate(info, M68K_INS_BKPT, 0, info->ir & 7);
}
static void d68020_bfchg(m68k_info *info)
@ -1558,21 +1571,18 @@ static void d68020_bftst(m68k_info *info)
static void d68000_bra_8(m68k_info *info)
{
uint temp_pc = info->pc;
build_bxx(info, M68K_INS_BRA, 1, temp_pc + make_int_8(info->ir));
build_relative_branch(info, M68K_INS_BRA, 1, make_int_8(info->ir));
}
static void d68000_bra_16(m68k_info *info)
{
uint temp_pc = info->pc;
build_bxx(info, M68K_INS_BRA, 2, temp_pc + make_int_16(read_imm_16(info)));
build_relative_branch(info, M68K_INS_BRA, 2, make_int_16(read_imm_16(info)));
}
static void d68020_bra_32(m68k_info *info)
{
uint temp_pc = info->pc;
LIMIT_CPU_TYPES(info, M68020_PLUS);
build_bxx(info, M68K_INS_BRA, 4, temp_pc + read_imm_32(info));
build_relative_branch(info, M68K_INS_BRA, 4, read_imm_32(info));
}
static void d68000_bset_r(m68k_info *info)
@ -1587,21 +1597,18 @@ static void d68000_bset_s(m68k_info *info)
static void d68000_bsr_8(m68k_info *info)
{
uint temp_pc = info->pc;
build_bxx(info, M68K_INS_BSR, 1, temp_pc + make_int_8(info->ir));
build_relative_branch(info, M68K_INS_BSR, 1, make_int_8(info->ir));
}
static void d68000_bsr_16(m68k_info *info)
{
uint temp_pc = info->pc;
build_bxx(info, M68K_INS_BSR, 2, temp_pc + make_int_16(read_imm_16(info)));
build_relative_branch(info, M68K_INS_BSR, 2, make_int_16(read_imm_16(info)));
}
static void d68020_bsr_32(m68k_info *info)
{
uint temp_pc = info->pc;
LIMIT_CPU_TYPES(info, M68020_PLUS);
build_bxx(info, M68K_INS_BSR, 4, temp_pc + peek_imm_32(info));
build_relative_branch(info, M68K_INS_BSR, 4, peek_imm_32(info));
}
static void d68000_btst_r(m68k_info *info)
@ -1789,26 +1796,29 @@ static void d68000_cmpm_32(m68k_info *info)
build_pi_pi(info, M68K_INS_CMPM, 4);
}
static void make_cpbcc_operand(cs_m68k_op* op, int size, int displacement)
{
op->address_mode = M68K_AM_BRANCH_DISPLACEMENT;
op->type = M68K_OP_BR_DISP;
op->br_disp.disp = displacement;
op->br_disp.disp_size = size;
}
static void d68020_cpbcc_16(m68k_info *info)
{
cs_m68k_op* op0;
cs_m68k* ext;
uint new_pc;
LIMIT_CPU_TYPES(info, M68020_PLUS);
new_pc = info->pc;
new_pc += make_int_16(read_imm_16(info));
// these are all in row with the extension so just doing a add here is fine
info->inst->Opcode += (info->ir & 0x2f);
ext = build_init_op(info, M68K_INS_FBF, 1, 2);
op0 = &ext->operands[0];
op0->address_mode = M68K_AM_IMMEDIATE;
op0->type = M68K_OP_IMM;
op0->imm = new_pc;
make_cpbcc_operand(op0, M68K_OP_BR_DISP_SIZE_WORD, make_int_16(read_imm_16(info)));
set_insn_group(info, M68K_GRP_JUMP);
set_insn_group(info, M68K_GRP_BRANCH_RELATIVE);
}
@ -1816,25 +1826,20 @@ static void d68020_cpbcc_32(m68k_info *info)
{
cs_m68k* ext;
cs_m68k_op* op0;
uint new_pc;
LIMIT_CPU_TYPES(info, M68020_PLUS);
LIMIT_CPU_TYPES(info, M68020_PLUS);
new_pc = info->pc;
new_pc += read_imm_32(info);
// these are all in row with the extension so just doing a add here is fine
info->inst->Opcode += (info->ir & 0x2f);
ext = build_init_op(info, M68K_INS_FBF, 1, 4);
op0 = &ext->operands[0];
op0->type = M68K_OP_IMM;
op0->address_mode = M68K_AM_IMMEDIATE;
op0->imm = new_pc;
make_cpbcc_operand(op0, M68K_OP_BR_DISP_SIZE_LONG, read_imm_32(info));
set_insn_group(info, M68K_GRP_JUMP);
set_insn_group(info, M68K_GRP_BRANCH_RELATIVE);
}
@ -1843,15 +1848,12 @@ static void d68020_cpdbcc(m68k_info *info)
cs_m68k* ext;
cs_m68k_op* op0;
cs_m68k_op* op1;
uint new_pc, ext1, ext2;
uint ext1, ext2;
LIMIT_CPU_TYPES(info, M68020_PLUS);
new_pc = info->pc;
ext1 = read_imm_16(info);
ext2 = read_imm_16(info);
new_pc += make_int_16(ext2) + 2;
// these are all in row with the extension so just doing a add here is fine
info->inst->Opcode += (ext1 & 0x2f);
@ -1862,10 +1864,9 @@ static void d68020_cpdbcc(m68k_info *info)
op0->reg = M68K_REG_D0 + (info->ir & 7);
op1->address_mode = M68K_AM_IMMEDIATE;
op1->type = M68K_OP_IMM;
op1->imm = new_pc;
make_cpbcc_operand(op1, M68K_OP_BR_DISP_SIZE_WORD, make_int_16(ext2) + 2);
set_insn_group(info, M68K_GRP_JUMP);
set_insn_group(info, M68K_GRP_BRANCH_RELATIVE);
}
@ -2212,14 +2213,12 @@ static void d68040_cpush(m68k_info *info)
static void d68000_dbra(m68k_info *info)
{
uint temp_pc = info->pc;
build_dbxx(info, M68K_INS_DBRA, 0, temp_pc + make_int_16(read_imm_16(info)));
build_dbxx(info, M68K_INS_DBRA, 0, make_int_16(read_imm_16(info)));
}
static void d68000_dbcc(m68k_info *info)
{
uint temp_pc = info->pc;
build_dbcc(info, 0, temp_pc + make_int_16(read_imm_16(info)));
build_dbcc(info, 0, make_int_16(read_imm_16(info)));
}
static void d68000_divs(m68k_info *info)
@ -3091,7 +3090,7 @@ static void d68010_rtd(m68k_info *info)
{
set_insn_group(info, M68K_GRP_RET);
LIMIT_CPU_TYPES(info, M68010_PLUS);
build_bxx(info, M68K_INS_RTD, 0, read_imm_16(info));
build_absolute_jump_with_immediate(info, M68K_INS_RTD, 0, read_imm_16(info));
}
static void d68000_rte(m68k_info *info)
@ -3109,7 +3108,7 @@ static void d68020_rtm(m68k_info *info)
LIMIT_CPU_TYPES(info, M68020_ONLY);
build_bxx(info, M68K_INS_RTM, 0, 0);
build_absolute_jump_with_immediate(info, M68K_INS_RTM, 0, 0);
ext = &info->extension;
op = &ext->operands[0];
@ -3154,7 +3153,7 @@ static void d68000_scc(m68k_info *info)
static void d68000_stop(m68k_info *info)
{
build_bxx(info, M68K_INS_STOP, 0, read_imm_16(info));
build_absolute_jump_with_immediate(info, M68K_INS_STOP, 0, read_imm_16(info));
}
static void d68000_sub_er_8(m68k_info *info)
@ -3269,7 +3268,7 @@ static void d68000_tas(m68k_info *info)
static void d68000_trap(m68k_info *info)
{
build_bxx(info, M68K_INS_TRAP, 0, info->ir&0xf);
build_absolute_jump_with_immediate(info, M68K_INS_TRAP, 0, info->ir&0xf);
}
static void d68020_trapcc_0(m68k_info *info)
@ -4019,6 +4018,7 @@ static unsigned int m68k_disassemble(m68k_info *info, uint64_t pc)
MCInst *inst = info->inst;
cs_m68k* ext = &info->extension;
int i;
unsigned int size;
inst->Opcode = M68K_INS_INVALID;
@ -4036,7 +4036,10 @@ static unsigned int m68k_disassemble(m68k_info *info, uint64_t pc)
g_instruction_table[info->ir].instruction(info);
}
return info->pc - (unsigned int)pc;
size = info->pc - (unsigned int)pc;
info->pc = (unsigned int)pc;
return size;
}
bool M68K_getInstruction(csh ud, const uint8_t* code, size_t code_len, MCInst* instr, uint16_t* size, uint64_t address, void* inst_info)

View File

@ -121,7 +121,7 @@ static void registerPair(SStream* O, const cs_m68k_op* op)
s_reg_names[M68K_REG_D0 + op->reg_pair.reg_1]);
}
void printAddressingMode(SStream* O, const cs_m68k* inst, const cs_m68k_op* op)
void printAddressingMode(SStream* O, unsigned int pc, const cs_m68k* inst, const cs_m68k_op* op)
{
switch (op->address_mode) {
case M68K_AM_NONE:
@ -146,7 +146,7 @@ void printAddressingMode(SStream* O, const cs_m68k* inst, const cs_m68k_op* op)
case M68K_AM_REGI_ADDR_POST_INC: SStream_concat(O, "(a%d)+", (op->reg - M68K_REG_A0)); break;
case M68K_AM_REGI_ADDR_PRE_DEC: SStream_concat(O, "-(a%d)", (op->reg - M68K_REG_A0)); break;
case M68K_AM_REGI_ADDR_DISP: SStream_concat(O, "%s$%x(a%d)", op->mem.disp < 0 ? "-" : "", abs(op->mem.disp), (op->mem.base_reg - M68K_REG_A0)); break;
case M68K_AM_PCI_DISP: SStream_concat(O, "%s$%x(pc)", op->mem.disp < 0 ? "-" : "", abs(op->mem.disp)); break;
case M68K_AM_PCI_DISP: SStream_concat(O, "$%x(pc)", pc + 2 + op->mem.disp); break;
case M68K_AM_ABSOLUTE_DATA_SHORT: SStream_concat(O, "$%x.w", op->imm); break;
case M68K_AM_ABSOLUTE_DATA_LONG: SStream_concat(O, "$%x.l", op->imm); break;
case M68K_AM_IMMEDIATE:
@ -168,15 +168,21 @@ void printAddressingMode(SStream* O, const cs_m68k* inst, const cs_m68k_op* op)
SStream_concat(O, "#$%x", op->imm);
break;
case M68K_AM_PCI_INDEX_8_BIT_DISP:
SStream_concat(O, "%s$%x(pc,%s%s.%c)", op->mem.disp < 0 ? "-" : "", abs(op->mem.disp), s_spacing, getRegName(op->mem.index_reg), op->mem.index_size ? 'l' : 'w');
SStream_concat(O, "$%x(pc,%s%s.%c)", pc + 2 + op->mem.disp, s_spacing, getRegName(op->mem.index_reg), op->mem.index_size ? 'l' : 'w');
break;
case M68K_AM_AREGI_INDEX_8_BIT_DISP:
SStream_concat(O, "%s$%x(%s,%s%s.%c)", op->mem.disp < 0 ? "-" : "", abs(op->mem.disp), getRegName(op->mem.base_reg), s_spacing, getRegName(op->mem.index_reg), op->mem.index_size ? 'l' : 'w');
break;
case M68K_AM_PCI_INDEX_BASE_DISP:
case M68K_AM_AREGI_INDEX_BASE_DISP:
if (op->mem.in_disp > 0)
SStream_concat(O, "$%x", op->mem.in_disp);
if (op->address_mode == M68K_AM_PCI_INDEX_BASE_DISP) {
SStream_concat(O, "$%x", pc + 2 + op->mem.in_disp);
}
else {
if (op->mem.in_disp > 0)
SStream_concat(O, "$%x", op->mem.in_disp);
}
SStream_concat(O, "(");
@ -201,8 +207,13 @@ void printAddressingMode(SStream* O, const cs_m68k* inst, const cs_m68k_op* op)
case M68K_AM_MEMI_PRE_INDEX:
case M68K_AM_MEMI_POST_INDEX:
SStream_concat(O, "([");
if (op->mem.in_disp > 0)
SStream_concat(O, "$%x", op->mem.in_disp);
if (op->address_mode == M68K_AM_PC_MEMI_POST_INDEX || op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX) {
SStream_concat(O, "$%x", pc + 2 + op->mem.in_disp);
} else {
if (op->mem.in_disp > 0)
SStream_concat(O, "$%x", op->mem.in_disp);
}
if (op->mem.base_reg != M68K_REG_INVALID) {
if (op->mem.in_disp > 0)
@ -228,6 +239,8 @@ void printAddressingMode(SStream* O, const cs_m68k* inst, const cs_m68k_op* op)
SStream_concat(O, ")");
break;
case M68K_AM_BRANCH_DISPLACEMENT:
SStream_concat(O, "$%x", pc + 2 + op->br_disp.disp);
default:
break;
}
@ -305,8 +318,8 @@ void M68K_printInst(MCInst* MI, SStream* O, void* PrinterInfo)
if (MI->Opcode == M68K_INS_CAS2) {
int reg_value_0, reg_value_1;
printAddressingMode(O, ext, &ext->operands[0]); SStream_concat0(O, ",");
printAddressingMode(O, ext, &ext->operands[1]); SStream_concat0(O, ",");
printAddressingMode(O, info->pc, ext, &ext->operands[0]); SStream_concat0(O, ",");
printAddressingMode(O, info->pc, ext, &ext->operands[1]); SStream_concat0(O, ",");
reg_value_0 = ext->operands[2].register_bits >> 4;
reg_value_1 = ext->operands[2].register_bits & 0xf;
SStream_concat(O, "(%s):(%s)", s_reg_names[M68K_REG_D0 + reg_value_0], s_reg_names[M68K_REG_D0 + reg_value_1]);
@ -314,7 +327,7 @@ void M68K_printInst(MCInst* MI, SStream* O, void* PrinterInfo)
}
for (i = 0; i < ext->op_count; ++i) {
printAddressingMode(O, ext, &ext->operands[i]);
printAddressingMode(O, info->pc, ext, &ext->operands[i]);
if ((i + 1) != ext->op_count)
SStream_concat(O, ",%s", s_spacing);
}

View File

@ -35,10 +35,17 @@ class M68KOpValue(ctypes.Union):
('reg_pair', M68KOpRegPair),
)
class M68KOpBrDisp(ctypes.Structure):
_fields_ = (
('disp', ctypes.c_int),
('disp_size', ctypes.c_ubyte),
)
class M68KOp(ctypes.Structure):
_fields_ = (
('value', M68KOpValue),
('mem', M68KOpMem),
('br_disp', M68KOpBrDisp),
('register_bits', ctypes.c_uint),
('type', ctypes.c_uint),
('address_mode', ctypes.c_uint),

View File

@ -73,6 +73,7 @@ M68K_AM_PC_MEMI_PRE_INDEX = 15
M68K_AM_ABSOLUTE_DATA_SHORT = 16
M68K_AM_ABSOLUTE_DATA_LONG = 17
M68K_AM_IMMEDIATE = 18
M68K_AM_BRANCH_DISPLACEMENT = 19
# Operand type for instruction's operands
@ -84,6 +85,14 @@ M68K_OP_FP_SINGLE = 4
M68K_OP_FP_DOUBLE = 5
M68K_OP_REG_BITS = 6
M68K_OP_REG_PAIR = 7
M68K_OP_BR_DISP = 8
# Operand type for instruction's operands
M68K_OP_BR_DISP_SIZE_INVALID = 0
M68K_OP_BR_DISP_SIZE_BYTE = 1
M68K_OP_BR_DISP_SIZE_WORD = 2
M68K_OP_BR_DISP_SIZE_LONG = 4
M68K_CPU_SIZE_NONE = 0
M68K_CPU_SIZE_BYTE = 1

View File

@ -40,6 +40,8 @@ s_addressing_modes = {
16: "Absolute Data Addressing - Short",
17: "Absolute Data Addressing - Long",
18: "Immediate value",
19: "Branch Displacement",
}
def print_read_write_regs(insn):
@ -82,6 +84,9 @@ def print_insn_detail(insn):
elif op.type == M68K_OP_FP_DOUBLE:
print("\t\toperands[%u].type: FP_DOUBLE" % i)
print("\t\toperands[%u].dimm: %lf", i, op.dimm)
elif op.type == M68K_OP_BR_DISP:
print("\t\toperands[%u].br_disp.disp: 0x%x" % (i, op.br_disp.disp))
print("\t\toperands[%u].br_disp.disp_size: %d" % (i, op.br_disp.disp_size))
print()
# ## Test class Cs

View File

@ -104,6 +104,9 @@ typedef enum m68k_address_mode {
M68K_AM_ABSOLUTE_DATA_SHORT, // Absolute Data Addressing - Short
M68K_AM_ABSOLUTE_DATA_LONG, // Absolute Data Addressing - Long
M68K_AM_IMMEDIATE, // Immediate value
M68K_AM_BRANCH_DISPLACEMENT, // Address as displacement from (PC+2) used by branches
} m68k_address_mode;
//> Operand type for instruction's operands
@ -116,6 +119,7 @@ typedef enum m68k_op_type {
M68K_OP_FP_DOUBLE, // double precision Floating-Point operand
M68K_OP_REG_BITS, // Register bits move
M68K_OP_REG_PAIR, // Register pair in the same op (upper 4 bits for first reg, lower for second)
M68K_OP_BR_DISP, // Branch displacement
} m68k_op_type;
// Instruction's operand referring to memory
@ -134,6 +138,19 @@ typedef struct m68k_op_mem {
uint8_t index_size; // 0 = w, 1 = l
} m68k_op_mem;
//> Operand type for instruction's operands
typedef enum m68k_op_br_disp_size {
M68K_OP_BR_DISP_SIZE_INVALID = 0, // = CS_OP_INVALID (Uninitialized).
M68K_OP_BR_DISP_SIZE_BYTE = 1, // signed 8-bit displacement
M68K_OP_BR_DISP_SIZE_WORD = 2, // signed 16-bit displacement
M68K_OP_BR_DISP_SIZE_LONG = 4, // signed 32-bit displacement
} m68k_op_br_disp_size;
typedef struct m68k_op_br_disp {
int32_t disp; // displacement value
uint8_t disp_size; // Size from m68k_op_br_disp_size type above
} m68k_op_br_disp;
// Instruction operand
typedef struct cs_m68k_op {
union {
@ -148,6 +165,7 @@ typedef struct cs_m68k_op {
};
m68k_op_mem mem; // data when operand is targeting memory
m68k_op_br_disp br_disp; // data when operand is a branch displacement
uint32_t register_bits; // register bits for movem etc. (always in d0-d7, a0-a7, fp0 - fp7 order)
m68k_op_type type;
m68k_address_mode address_mode; // M68K addressing mode for this op