blob: 8f2400bc5cf9b85b5df9fdc76493291337c77cb9 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#pragma once
#define MIN_INSN_SIZE 2
/* each input instruction might turn into:
* - 2 bytes for Bcc, if in IT
* then ONE of:
* - 2/4 bytes for just the instruction
* - 2+8 bytes for branch (which in *valid* code rules out IT but whatever)
* - up to 7 4-byte insns for pcrel (if dest=pc, and while these can be subject
* to IT, there can only reasonably be two per block, and if there are both
* then that's an unconditional exit - but we don't enforce any of this
* currently)
* - up to 7 4-byte insns for similar moves to PC that fall under 'data'
* the maximum number of possible inputs is 4, plus 4 extras if the last one
* was an IT (but in that case it can't be one of the above cases)
* while this looks huge, it's overly conservative and doesn't matter much,
* since only the actually used space will be taken up in the final output
*/
#define TD_MAX_REWRITTEN_SIZE (7*4*7 + 4) /* 196 */
struct arch_pcrel_info {
unsigned reg;
enum pcrel_load_mode load_mode;
};
struct arch_dis_ctx {
/* thumb? */
bool pc_low_bit;
/* if thumb, IT cond for the next 5 instructions
* (5 because we still advance after IT) */
uint8_t it_conds[5];
/* for transform_dis - did we add space for a Bccrel? */
uint8_t bccrel_bits;
void *bccrel_p;
};
static inline void arch_dis_ctx_init(struct arch_dis_ctx *ctx) {
ctx->pc_low_bit = false;
ctx->bccrel_p = NULL;
memset(ctx->it_conds, 0xe, 5);
}
static inline int arch_code_alignment(struct arch_dis_ctx ctx) {
return ctx.pc_low_bit ? 2 : 4;
}
static inline void advance_it_cond(struct arch_dis_ctx *ctx) {
ctx->it_conds[0] = ctx->it_conds[1];
ctx->it_conds[1] = ctx->it_conds[2];
ctx->it_conds[2] = ctx->it_conds[3];
ctx->it_conds[3] = ctx->it_conds[4];
ctx->it_conds[4] = 0xe;
}
#define DFLAG_IS_LDRD_STRD (1 << 16)
/* Types of conditionals for 'branch' */
/* a regular old branch-with-condition */
#define CC_ARMCC (CC_CONDITIONAL | 0x400)
/* already in an IT block - in transform_dis this will be rewritten to a branch
* anyway, so it can be treated as unconditional; in jump_dis we have to know
* to keep going */
#define CC_ALREADY_IN_IT (CC_CONDITIONAL | 0x800)
/* CBZ/CBNZ is rewritten */
#define CC_CBXZ (CC_CONDITIONAL | 0xc00)
|