diff options
author | comex | 2015-02-08 23:45:24 -0500 |
---|---|---|
committer | comex | 2015-02-08 23:45:24 -0500 |
commit | eb93cee2a22cde812ccd6b9bd418d36185c058f5 (patch) | |
tree | 43a22ccf021a1513dba3a9c99f7b81822fe950fa /lib/arm/transform-dis-arm-multi.inc.h | |
parent | formatting (diff) | |
download | substitute-eb93cee2a22cde812ccd6b9bd418d36185c058f5.tar.gz |
Refactor disassembly so x86 works, and add x86 transform-dis.
This patch is a monolithic mess, because I was too lazy to do the
refactor first (that would require some stash fun, since I wasn't
actually sure before doing x86 transform-dis what would be needed).
Anyway, the resulting code should be cleaner - less duplication.
This breaks ARM/ARM64.
Diffstat (limited to 'lib/arm/transform-dis-arm-multi.inc.h')
-rw-r--r-- | lib/arm/transform-dis-arm-multi.inc.h | 195 |
1 files changed, 0 insertions, 195 deletions
diff --git a/lib/arm/transform-dis-arm-multi.inc.h b/lib/arm/transform-dis-arm-multi.inc.h deleted file mode 100644 index 6e91ff5..0000000 --- a/lib/arm/transform-dis-arm-multi.inc.h +++ /dev/null @@ -1,195 +0,0 @@ -/* TODO fix BL incl MOV LR, PC */ -#include "arm/assemble.h" - -static struct assemble_ctx tdctx_to_actx(const struct transform_dis_ctx *ctx) { - int cond; - if (ctx->arch.pc_low_bit) { - cond = ctx->op >> 28; - if (cond == 0xf) - cond = 0xe; - } else { - cond = 0; - } - return (struct assemble_ctx) { - ctx->rewritten_ptr_ptr, - ctx->arch.pc_low_bit, - cond - }; - -} - -static int invert_arm_cond(int cc) { - if (cc >= 0xe) - __builtin_abort(); - return cc ^ 1; -} - -static NOINLINE UNUSED void transform_dis_data(struct transform_dis_ctx *ctx, - unsigned o0, unsigned o1, unsigned o2, unsigned o3, unsigned out_mask) { -#ifdef TRANSFORM_DIS_VERBOSE - printf("transform_dis_data: (%p) %x %x %x %x out_mask=%x\n", (void *) ctx->pc, - o0, o1, o2, o3, out_mask); -#endif - /* We only care if at least one op is PC, so quickly test that. */ - if (((o0 | o1 | o2 | o3) & 15) != 15) - return; - unsigned *newval = ctx->newval; - newval[0] = o0; - newval[1] = o1; - newval[2] = o2; - newval[3] = o3; - - void **codep = ctx->rewritten_ptr_ptr; - struct assemble_ctx actx = tdctx_to_actx(ctx); - - /* A few cases: - * 1. Move to PC that does not read PC. Probably fine. - * 2. Move to PC that does read PC, e.g. 'ldrls pc, [pc, r0, lsl #2]'. - * This is different from #4 mainly in that we can't need to do - * something like pop {temp, pc}. Not terribly plausible (only likely - * in non-position-independent code in ARM mode, and I can't get it to - * happen in the first 8 bytes then), but we may as well handle it. - * 3. Read of PC that does not read the register(s) it writes, e.g. adr r3, - * X. In this case we can use that register as a temporary. - * 4. Read of PC that does, or doesn't have any output register, e.g. add - * r3, pc. In this case we use the stack because reliably finding a - * free register would be work, and might not even be possible (thumb - * mov r9, r0; mov r12, r1; <some PC using insn(s)>) - * the out register is always first. - */ - uint16_t in_regs = 0; - int out_reg = -1; - for (int i = 0; i < 4; i++) { - if (out_mask & 1 << i) - out_reg = newval[i]; - else if (newval[i] != null_op) - in_regs |= 1 << newval[i]; - } - if (out_mask & DFLAG_IS_LDRD_STRD) - in_regs |= 1 << (newval[0] + 1); - uint32_t pc = ctx->pc + (ctx->arch.pc_low_bit ? 4 : 8); - int scratch = __builtin_ctz(~(in_regs | (1 << out_reg))); - -#ifdef TRANSFORM_DIS_VERBOSE - printf("transform_dis_data: in_regs=%x out_reg=%d pc=%x scratch=%d\n", - in_regs, out_reg, pc, scratch); -#endif - - if (out_reg == 15) { - if (in_regs & 1 << 15) - return; /* case 1 */ - /* case 2 */ - PUSHone(actx, scratch); - PUSHone(actx, scratch); - MOVW_MOVT(actx, scratch, pc); - for (int i = 0; i < 4; i++) - if (newval[i] == 15) - newval[i] = scratch; - ctx->write_newop_here = *codep; *codep += ctx->op_size; - STRri(actx, scratch, 13, 4); - POPmulti(actx, 1 << scratch | 1 << 15); - if (actx.cond != 0xe) - transform_dis_ret(ctx); - } else { - if (out_reg != -1 && !(in_regs & 1 << out_reg)) { - /* case 3 - ignore scratch */ - MOVW_MOVT(actx, out_reg, pc); - for (int i = 0; i < 4; i++) - if (newval[i] == 15) - newval[i] = out_reg; - ctx->write_newop_here = *codep; *codep += ctx->op_size; - } else { - /* case 4 */ - PUSHone(actx, scratch); - MOVW_MOVT(actx, scratch, pc); - for (int i = 0; i < 4; i++) - if (newval[i] == 15) - newval[i] = scratch; - ctx->write_newop_here = *codep; *codep += ctx->op_size; - POPone(actx, scratch); - } - } - ctx->modify = true; -#ifdef TRANSFORM_DIS_VERBOSE - printf("transform_dis_data: => %x %x %x %x\n", - newval[0], newval[1], newval[2], newval[3]); -#endif -} - -static NOINLINE UNUSED void transform_dis_pcrel(struct transform_dis_ctx *ctx, - uintptr_t dpc, unsigned reg, enum pcrel_load_mode load_mode) { -#ifdef TRANSFORM_DIS_VERBOSE - printf("transform_dis_pcrel: (%p) dpc=%p reg=%x mode=%d\n", (void *) ctx->pc, - (void *) dpc, reg, load_mode); -#endif - ctx->write_newop_here = NULL; - struct assemble_ctx actx = tdctx_to_actx(ctx); - if (reg == 15) { - int scratch = 0; - PUSHone(actx, scratch); - PUSHone(actx, scratch); - MOVW_MOVT(actx, scratch, dpc); - if (load_mode != PLM_ADR) - LDRxi(actx, scratch, scratch, 0, load_mode); - STRri(actx, scratch, 13, 4); - POPmulti(actx, 1 << scratch | 1 << 15); - transform_dis_ret(ctx); - } else { - MOVW_MOVT(actx, reg, dpc); - if (load_mode != PLM_ADR) - LDRxi(actx, reg, reg, 0, load_mode); - } -} - -static NOINLINE UNUSED void transform_dis_branch(struct transform_dis_ctx *ctx, - uintptr_t dpc, int cc) { -#ifdef TRANSFORM_DIS_VERBOSE - printf("transform_dis (%p): branch => %p\n", (void *) ctx->pc, (void *) dpc); -#endif - if (dpc >= ctx->pc_patch_start && dpc < ctx->pc_patch_end) { - /* don't support this for now */ - /* making the simplifying assumption here that functions will not try - * to branch into the middle of an IT block, which is the case where - * pc_patch_end changes to include additional instructions (as opposed - * to include the end of a partially included instruction, which is - * common) */ - ctx->err = SUBSTITUTE_ERR_FUNC_BAD_INSN_AT_START; - return; - } - struct assemble_ctx actx = tdctx_to_actx(ctx); - ctx->write_newop_here = NULL; - if ((cc & CC_ARMCC) == CC_ARMCC) { - actx.cond = invert_arm_cond(cc & 0xf); - Bccrel(actx, 2+8); - } else if ((cc & CC_CBXZ) == CC_CBXZ) { - ctx->modify = true; - ctx->newval[0] = ctx->pc + 2+8; - ctx->newval[1] = 1; /* do invert */ - void **codep = ctx->rewritten_ptr_ptr; - ctx->write_newop_here = *codep; *codep += 2; - } - actx.cond = 0xe; - LDR_PC(actx, dpc | ctx->arch.pc_low_bit); -} - -static void transform_dis_pre_dis(struct transform_dis_ctx *ctx) { - /* for simplicity we turn IT into a series of branches for each - * instruction, so... */ - if (ctx->arch.it_conds[0] != 0xe) { - ctx->arch.bccrel_bits = invert_arm_cond(ctx->arch.it_conds[0]); - ctx->arch.bccrel_p = *ctx->rewritten_ptr_ptr; - *ctx->rewritten_ptr_ptr += 2; - } else { - ctx->arch.bccrel_p = NULL; - } -} - -static void transform_dis_post_dis(struct transform_dis_ctx *ctx) { - if (ctx->arch.bccrel_p) { - struct assemble_ctx actx = {&ctx->arch.bccrel_p, - /*thumb*/ true, - ctx->arch.bccrel_bits}; - Bccrel(actx, *ctx->rewritten_ptr_ptr - ctx->arch.bccrel_p); - } - ctx->force_keep_transforming = ctx->arch.it_conds[0] != 0xe; -} |