aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dis-arm.inc.h24
-rw-r--r--lib/dis-thumb2.inc.h12
-rw-r--r--lib/dis.h10
-rw-r--r--lib/transform-dis-arm-multi.inc.h10
-rw-r--r--test/insns-arm.S2
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));
diff --git a/lib/dis.h b/lib/dis.h
index e0cbc4f..7a53f27 100644
--- a/lib/dis.h
+++ b/lib/dis.h
@@ -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} */