diff options
author | comex | 2015-01-17 22:51:13 -0500 |
---|---|---|
committer | comex | 2015-01-17 22:51:13 -0500 |
commit | e2395c46c89514628fc5950d1a104fa624c4728b (patch) | |
tree | f12d3a35443b38ad328ae099865e3f0709180657 | |
parent | improve test; thumb2 fixes (diff) | |
download | substitute-e2395c46c89514628fc5950d1a104fa624c4728b.tar.gz |
ldrd/strd fix - we definitely need to know that in ldrd r0, r1, [pc], we can't use r1 as scratch
-rw-r--r-- | lib/dis-arm.inc.h | 24 | ||||
-rw-r--r-- | lib/dis-thumb2.inc.h | 12 | ||||
-rw-r--r-- | lib/dis.h | 10 | ||||
-rw-r--r-- | lib/transform-dis-arm-multi.inc.h | 10 | ||||
-rw-r--r-- | test/insns-arm.S | 2 |
5 files changed, 38 insertions, 20 deletions
diff --git a/lib/dis-arm.inc.h b/lib/dis-arm.inc.h index 0779205..2f06234 100644 --- a/lib/dis-arm.inc.h +++ b/lib/dis-arm.inc.h @@ -65,16 +65,20 @@ static INLINE void P(GPR_Rt_addr_offset_none_addr_am2offset_reg_offset_S_4_STRBT data(r(addr), rs(offset, 0, 4), r(Rt)); } static INLINE void P(GPR_Rt_addr_offset_none_addr_am3offset_offset_S_2_STRD_POST)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { - data(r(addr), rs(offset, 0, 4), r(Rt)); + data_flags(IS_LDRD_STRD, r(Rt), r(addr), rs(offset, 0, 4)); } static INLINE void P(GPR_Rt_addr_offset_none_addr_postidx_imm8_offset_S_1_STRHTi)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), r(Rt)); } static INLINE void P(GPR_Rt_addrmode3_addr_S_2_STRD)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { - data(rs(addr, 9, 4), rs(addr, 0, 4), r(Rt)); + unsigned addr_val = bs_get(addr, ctx->op); + if (addr_val & 1 << 13) + data_flags(IS_LDRD_STRD, r(Rt), rs(addr, 9, 4)); + else + data_flags(IS_LDRD_STRD, r(Rt), rs(addr, 9, 4), rs(addr, 0, 4)); } static INLINE void P(GPR_Rt_addrmode3_pre_addr_S_2_STRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { - data(rs(addr, 9, 4), rs(addr, 0, 4), r(Rt)); + return P(GPR_Rt_addrmode3_addr_S_2_STRD)(ctx, addr, Rt); } static INLINE void P(GPR_Rt_addrmode_imm12_addr_S_1_STRi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), r(Rt)); @@ -125,12 +129,16 @@ static INLINE void P(addr_offset_none_addr_postidx_imm8s4_offset_S_4_STC2L_POST) static INLINE void P(addr_offset_none_addr_unk_Rt_13_LDA)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { data(rout(Rt), r(addr)); } -static INLINE void P(addrmode3_addr_unk_Rt_4_LDRD)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { - /* ignoring Rt2 = Rt + 1, but it isn't supposed to load PC anyway */ - data(rs(addr, 9, 4), rs(addr, 0, 4)); +static INLINE void P(addrmode3_addr_unk_Rt_4_LDRD)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { + /* ignoring Rt2 = Rt + 1, but LDRD itself isn't supposed to load PC anyway */ + unsigned addr_val = bs_get(addr, ctx->op); + if (addr_val & 1 << 13) + data_flags(IS_LDRD_STRD, rout(Rt), rs(addr, 9, 4)); + else + data_flags(IS_LDRD_STRD, rout(Rt), rs(addr, 9, 4), rs(addr, 0, 4)); } -static INLINE void P(addrmode3_pre_addr_unk_Rt_4_LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { - data(rs(addr, 9, 4), rs(addr, 0, 4)); +static INLINE void P(addrmode3_pre_addr_unk_Rt_4_LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { + return P(addrmode3_addr_unk_Rt_4_LDRD)(ctx, addr, Rt); } static INLINE void P(addrmode5_addr_8_LDC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); diff --git a/lib/dis-thumb2.inc.h b/lib/dis-thumb2.inc.h index fa744bc..a9d7f9d 100644 --- a/lib/dis-thumb2.inc.h +++ b/lib/dis-thumb2.inc.h @@ -100,10 +100,10 @@ static INLINE void P(rGPR_Rt_t2addrmode_imm8_pre_addr_S_2_t2STRB_PRE)(tdis_ctx c data(r(Rt), rs(addr, 9, 4)); } static INLINE void P(rGPR_Rt_t2addrmode_imm8s4_addr_S_1_t2STRDi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { - data(r(Rt), rs(addr, 9, 4)); + data_flags(IS_LDRD_STRD, r(Rt), rs(addr, 9, 4)); } static INLINE void P(rGPR_Rt_t2addrmode_imm8s4_pre_addr_S_1_t2STRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { - data(r(Rt), rs(addr, 9, 4)); + data_flags(IS_LDRD_STRD, r(Rt), rs(addr, 9, 4)); } static INLINE void P(rGPR_Rt_t2addrmode_negimm8_addr_S_2_t2STRBi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 9, 4)); @@ -129,11 +129,11 @@ static INLINE void P(t2addrmode_imm8_pre_addr_unk_Rt_5_t2LDRB_PRE)(tdis_ctx ctx, static INLINE void P(addr_offset_none_Rn_t2am_imm8_offset_offset_unk_Rt_5_t2LDRB_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { data(rout(Rt), r(Rn)); } -static INLINE void P(t2addrmode_imm8s4_addr_unk_Rt_1_t2LDRDi8)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { - data(rs(addr, 9, 4)); +static INLINE void P(t2addrmode_imm8s4_addr_unk_Rt_1_t2LDRDi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { + data_flags(IS_LDRD_STRD, rout(Rt), rs(addr, 9, 4)); } -static INLINE void P(t2addrmode_imm8s4_pre_addr_unk_Rt_1_t2LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { - data(rs(addr, 9, 4)); +static INLINE void P(t2addrmode_imm8s4_pre_addr_unk_Rt_1_t2LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { + data_flags(IS_LDRD_STRD, rout(Rt), rs(addr, 9, 4)); } static INLINE void P(t2addrmode_negimm8_addr_unk_Rt_5_t2LDRBi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 9, 4)); @@ -81,9 +81,11 @@ static const unsigned null_op = -0x100; #define rout(nn) nn, true, true #define rsout(nn, l, s) bs_slice(nn, l, s), true, true #define rnull null_bs, false, false -#define data(...) data_(__VA_ARGS__, rnull, rnull, rnull, rnull) + +#define data(...) data_flags(0, __VA_ARGS__) +#define data_flags(...) data_(__VA_ARGS__, rnull, rnull, rnull, rnull) #define data_(...) data__(__VA_ARGS__) -#define data__(b1, o1, v1, b2, o2, v2, b3, o3, v3, b4, o4, v4, ...) do { \ +#define data__(fl, b1, o1, v1, b2, o2, v2, b3, o3, v3, b4, o4, v4, ...) do { \ P(data)(ctx, \ v1 ? bs_get(b1, ctx->op) : null_op, \ v2 ? bs_get(b2, ctx->op) : null_op, \ @@ -92,7 +94,8 @@ static const unsigned null_op = -0x100; (o1 << 0) | \ (o2 << 1) | \ (o3 << 2) | \ - (o4 << 3)); \ + (o4 << 3) | \ + fl); \ if (TDIS_CTX_MODIFY(ctx)) { \ unsigned new = ctx->op; \ new = bs_set(b1, TDIS_CTX_NEWVAL(ctx, 0), new); \ @@ -116,6 +119,7 @@ static const unsigned null_op = -0x100; #define MIN_INSN_SIZE 2 #define TARGET_DIS_HEADER "dis-arm-multi.inc.h" struct arch_dis_ctx { unsigned thumb_it_length; }; + enum { IS_LDRD_STRD = 1 << 16 }; #elif defined(TARGET_arm64) #define MIN_INSN_SIZE 4 #define TARGET_DIS_HEADER "dis-arm64.inc.h" diff --git a/lib/transform-dis-arm-multi.inc.h b/lib/transform-dis-arm-multi.inc.h index dc066ff..662b501 100644 --- a/lib/transform-dis-arm-multi.inc.h +++ b/lib/transform-dis-arm-multi.inc.h @@ -113,9 +113,11 @@ static NOINLINE UNUSED void transform_dis_data(struct transform_dis_ctx *ctx, for (int i = 0; i < 4; i++) { if (out_mask & 1 << i) out_reg = newval[i]; - else + else if (newval[i] != null_op) in_regs |= 1 << newval[i]; } + if (out_mask & IS_LDRD_STRD) + in_regs |= 1 << (newval[0] + 1); uint32_t pc = ctx->pc + (ctx->pc_low_bit ? 4 : 8); int scratch = __builtin_ctz(~(in_regs | (1 << out_reg))); @@ -149,7 +151,7 @@ static NOINLINE UNUSED void transform_dis_data(struct transform_dis_ctx *ctx, /* case 4 */ PUSHone(ctx, scratch); MOVW_MOVT(ctx, scratch, pc); - for (int i = 1; i < 4; i++) + for (int i = 0; i < 4; i++) if (newval[i] == 15) newval[i] = scratch; ctx->write_newop_here = *rpp; *rpp += ctx->op_size; @@ -157,6 +159,10 @@ static NOINLINE UNUSED void transform_dis_data(struct transform_dis_ctx *ctx, } } 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, diff --git a/test/insns-arm.S b/test/insns-arm.S index b5a2cce..2470c35 100644 --- a/test/insns-arm.S +++ b/test/insns-arm.S @@ -39,7 +39,7 @@ ldrd r0, r1, [pc] str r1, [pc] strd r0, r1, [pc] -push {r0-r3, pc} +/* push {r0-r3, pc} */ push {r0-r3, lr} /* pop {r0-r3, pc} */ |