-
Notifications
You must be signed in to change notification settings - Fork 0
/
modifiers
159 lines (137 loc) · 3.58 KB
/
modifiers
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#define rotate_right(v, n) (v >> n | v << (32 - n))
/* ARM immediate encoding routine
* Based on Binutils' ARM port
*/
ac_modifier_encode(aimm)
{
unsigned int a;
unsigned int i;
#define rotate_left(v, n) (v << n | v >> (32 - n))
for (i = 0; i < 32; i += 2)
if ((a = rotate_left (reloc->input, i)) <= 0xff) {
reloc->Type_DPI3.rotate = i >> 1;
reloc->Type_DPI3.imm8 = a;
return;
}
reloc->error = 1;
}
ac_modifier_decode(aimm)
{
reloc->output = rotate_right(reloc->input, (reloc->Type_DPI3.rotate << 1));
}
/*
* "Branch" and "Branch and Link" instructions immediate modifier
* Coded as 24bit, 2 times right shifted (ARM ISA is 32bits word aligned)
* pc-relative + 8 offset.
*/
ac_modifier_encode(bimm)
{
reloc->output = (reloc->input - reloc->address - 8) >>2;
}
ac_modifier_decode(bimm)
{
int val = (int) reloc->input;
if (val & 0x00800000)
val |= 0xFF000000;
reloc->output = (val << 2) + reloc->address + 8;
}
/*
* "Branch and Exchange to thumb mode" instruction immediate modifier
* Coded as 24bit, 2 times right shifted (Thumb instructions is
* 16bits word aligned, so bit 1 is coded in field "H")
* pc-relative + 8 offset.
*/
ac_modifier_encode(bximm)
{
unsigned int modifiedImm = reloc->input;
modifiedImm = modifiedImm - reloc->address - 8;
reloc->Type_BBLT.h = (modifiedImm >> 1) & 0x01;
reloc->Type_BBLT.offset = modifiedImm >> 2;
}
ac_modifier_decode(bximm)
{
reloc->output = (reloc->input << 2) + reloc->address + 8;
}
/* Converts pc-relative immediates, rotated - used only
* in ADR pseudo instruction
*/
ac_modifier_encode(pcrelrot)
{
unsigned int pcrelat = reloc->input - reloc->address - 8;
unsigned int a;
unsigned int i;
// Determines if ADR will be ADD or SUB
if ((pcrelat & 0x80000000) == 0)
reloc->Type_DPI3.func1 = 0x04; // ADD
else
{
reloc->Type_DPI3.func1 = 0x02; // SUB
pcrelat = 0 - pcrelat;
}
for (i = 0; i < 32; i += 2)
if ((a = rotate_left (pcrelat, i)) <= 0xff) {
reloc->Type_DPI3.rotate = ((i >> 1)&0xF);
reloc->Type_DPI3.imm8 = (a & 0xFF);
return;
}
reloc->error = 1;
}
ac_modifier_decode(pcrelrot)
{
reloc->error = 0;
}
/* converts pc-relative immediate (used only in pseudo LDR)
*/
ac_modifier_encode(pcrelldr)
{
unsigned int pcrelat = reloc->input - reloc->address - 8;
// Determines if LDR will have negative or positive offset
if ((pcrelat & 0x80000000) == 0)
reloc->Type_LSI.u = 0x01; // ADD
else
{
reloc->Type_LSI.u = 0x00; // SUB
pcrelat = 0 - pcrelat;
}
reloc->Type_LSI.imm12 = 0xFFF & pcrelat;
}
ac_modifier_decode(pcrelldr)
{
reloc->output = reloc->input + reloc->address + 8;
}
/* Multiple data transfer register list element - codifies
* a register number into a bit in the register list.
* Uses the list operator to obtain list of registers parsed.
*/
ac_modifier_encode(dorlist)
{
int init_range = -1;
unsigned i = 0;
while (list_results_has_data(reloc->list_results))
{
char separator = list_results_get_separator(reloc->list_results);
unsigned int result = list_results_next(&(reloc->list_results));
if (init_range != -1)
{
for (i = init_range; i <= result; i++)
reloc->output = reloc->output | (1 << i);
}
else
reloc->output = reloc->output | (1 << result);
init_range = -1;
if (separator == '-')
init_range = result;
}
}
ac_modifier_decode(dorlist)
{
unsigned i = 0;
unsigned val = reloc->input;
for (i = 0; i < 16; i++)
{
unsigned aux = val >> i;
if (aux & 1) {
list_results_store(&(reloc->list_results), i);
}
}
}