diff options
Diffstat (limited to 'lib/arm')
-rw-r--r-- | lib/arm/arch-dis.h | 2 | ||||
-rw-r--r-- | lib/arm/arch-transform-dis.inc.h | 37 | ||||
-rw-r--r-- | lib/arm/jump-patch.h | 2 |
3 files changed, 30 insertions, 11 deletions
diff --git a/lib/arm/arch-dis.h b/lib/arm/arch-dis.h index 1c63b12..157acfb 100644 --- a/lib/arm/arch-dis.h +++ b/lib/arm/arch-dis.h @@ -62,4 +62,4 @@ static inline void advance_it_cond(struct arch_dis_ctx *ctx) { * to keep going */ #define CC_ALREADY_IN_IT (CC_CONDITIONAL | 0x800) /* CBZ/CBNZ is rewritten */ -#define CC_CBXZ (CC_CONDITIONAL | 0xc00) +#define CC_CBXZ (CC_CONDITIONAL | 0x1000) diff --git a/lib/arm/arch-transform-dis.inc.h b/lib/arm/arch-transform-dis.inc.h index 1e9579d..b23c2c3 100644 --- a/lib/arm/arch-transform-dis.inc.h +++ b/lib/arm/arch-transform-dis.inc.h @@ -1,5 +1,6 @@ /* TODO fix BL incl MOV LR, PC */ #include "arm/assemble.h" +#include "arm/jump-patch.h" static struct assemble_ctx tdctx_to_actx(const struct transform_dis_ctx *ctx) { int cond; @@ -13,7 +14,7 @@ static struct assemble_ctx tdctx_to_actx(const struct transform_dis_ctx *ctx) { return (struct assemble_ctx) { ctx->rewritten_ptr_ptr, *ctx->rewritten_ptr_ptr, - (uint_tptr) (uintptr_t) *ctx->rewritten_ptr_ptr, + ctx->base.pc, ctx->arch.pc_low_bit, cond }; @@ -165,23 +166,41 @@ void transform_dis_branch(struct transform_dis_ctx *ctx, uint_tptr dpc, int cc) transform_dis_branch_top(ctx, dpc, cc); struct assemble_ctx actx = tdctx_to_actx(ctx); ctx->write_newop_here = NULL; - int replacement_size = 8 + (actx.thumb ? 2 : 4); + int replacement_size; + + /* Dry run to get size */ + if ((cc & CC_ARMCC) == CC_ARMCC) { + replacement_size = actx.thumb ? 2 : 4; + } else if ((cc & CC_CBXZ) == CC_CBXZ) { + replacement_size = 2; + } + if ((cc & CC_CALL) == CC_CALL) { + replacement_size += 8 + (actx.thumb ? 2 : 4); + } else { + replacement_size += jump_patch_size(actx_pc(actx) + replacement_size, dpc, ctx->arch, 0); + } + + /* Actual run */ if ((cc & CC_ARMCC) == CC_ARMCC) { - replacement_size += actx.thumb ? 2 : 4; actx.cond = invert_arm_cond(cc & 0xf); Bccrel(actx, replacement_size); } else if ((cc & CC_CBXZ) == CC_CBXZ) { - replacement_size += 2; ctx->base.modify = true; - ctx->base.newval[0] = actx.pc_of_code_base + replacement_size; - ctx->base.newval[1] = 1; /* do invert */ + ctx->base.newop[0] = actx.pc_of_code_base + replacement_size; + ctx->base.newop[1] = 1; /* do invert */ void **codep = ctx->rewritten_ptr_ptr; ctx->write_newop_here = *codep; *codep += 2; } - /* If it's a call, we should jump back after the call */ + actx.cond = 0xe; - MOVW_MOVT(actx, 14, dpc | ctx->arch.pc_low_bit); - BLXr(actx, 14); + /* If it's a call, we should jump back after the call */ + if ((cc & CC_CALL) == CC_CALL) { + MOVW_MOVT(actx, 14, dpc | ctx->arch.pc_low_bit); + BLXr(actx, 14); + } else { + // otherwise we can't clobber LR + LDR_PC(actx, dpc | ctx->arch.pc_low_bit); + } substitute_assert(*actx.codep - actx.code_base == replacement_size); } diff --git a/lib/arm/jump-patch.h b/lib/arm/jump-patch.h index 8ba4c3a..361e357 100644 --- a/lib/arm/jump-patch.h +++ b/lib/arm/jump-patch.h @@ -14,6 +14,6 @@ static inline int jump_patch_size(uint_tptr pc, static inline void make_jump_patch(void **codep, uint_tptr pc, uint_tptr dpc, struct arch_dis_ctx arch) { - struct assemble_ctx actx = {codep, pc, arch.pc_low_bit, 0xe}; + struct assemble_ctx actx = {codep, *codep, pc, arch.pc_low_bit, 0xe}; LDR_PC(actx, dpc); } |