FreeCalypso > hg > freecalypso-reveng
comparison ticoff/thumbdis.c @ 111:0f94d17899b3
tiobjd: disassembly integrated, no relocs or hints yet
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 03 Apr 2014 05:14:15 +0000 |
parents | |
children | d97fbe98600b |
comparison
equal
deleted
inserted
replaced
110:e650fdc743fe | 111:0f94d17899b3 |
---|---|
1 /* | |
2 * Thumb state disassembly | |
3 */ | |
4 | |
5 #include <sys/types.h> | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <strings.h> | |
10 #include "intstruct.h" | |
11 #include "globals.h" | |
12 | |
13 extern unsigned get_u16(), get_u32(); | |
14 | |
15 extern char *regnames[16], *condition_decode[16], *shift_types[4]; | |
16 | |
17 static void | |
18 format_1_2(word) | |
19 unsigned word; | |
20 { | |
21 unsigned op, imm; | |
22 | |
23 op = (word >> 11) & 3; | |
24 if (op != 3) { | |
25 /* format 1 */ | |
26 imm = (word >> 6) & 0x1F; | |
27 if (op != 0 && imm == 0) | |
28 imm = 32; | |
29 printf("%s\t%s, %s, #%u\n", shift_types[op], regnames[word&7], | |
30 regnames[(word>>3)&7], imm); | |
31 return; | |
32 } | |
33 /* format 2 */ | |
34 printf("%s\t%s, %s, ", word&0x200 ? "sub" : "add", regnames[word&7], | |
35 regnames[(word>>3)&7]); | |
36 if (word & 0x400) | |
37 printf("#%u\n", (word >> 6) & 7); | |
38 else | |
39 printf("%s\n", regnames[(word >> 6) & 7]); | |
40 } | |
41 | |
42 static void | |
43 format_3(word) | |
44 unsigned word; | |
45 { | |
46 static char *opctab[4] = {"mov", "cmp", "add", "sub"}; | |
47 unsigned imm; | |
48 | |
49 imm = word & 0xFF; | |
50 printf("%s\t%s, #%u", opctab[(word>>11)&3], regnames[(word>>8)&7], imm); | |
51 if (imm > 9) | |
52 printf("\t; 0x%x", imm); | |
53 putchar('\n'); | |
54 } | |
55 | |
56 static void | |
57 format_4(word) | |
58 unsigned word; | |
59 { | |
60 static char *opc[16] = {"and", "eor", "lsl", "lsr", | |
61 "asr", "adc", "sbc", "ror", | |
62 "tst", "neg", "cmp", "cmn", | |
63 "orr", "mul", "bic", "mvn"}; | |
64 | |
65 printf("%s\t%s, %s\n", opc[(word>>6)&0xF], regnames[word&7], | |
66 regnames[(word>>3)&7]); | |
67 } | |
68 | |
69 static void | |
70 format_5_bx(word) | |
71 unsigned word; | |
72 { | |
73 if (word & 0x80) | |
74 printf("<invalid: blx instead of bx>\n"); | |
75 else | |
76 printf("bx\t%s\n", regnames[(word>>3)&0xF]); | |
77 } | |
78 | |
79 static void | |
80 format_5_hiops(word) | |
81 unsigned word; | |
82 { | |
83 static char *opctab[3] = {"add", "cmp", "mov"}; | |
84 int reg1, reg2, op; | |
85 | |
86 if (word & 0xC0) { | |
87 reg1 = word & 7; | |
88 if (word & 0x80) | |
89 reg1 += 8; | |
90 reg2 = (word >> 3) & 0xF; | |
91 op = (word >> 8) & 3; | |
92 if (op == 2 && reg1 == reg2 && reg1 != 15) | |
93 printf("nop\t\t\t(mov %s, %s)\n", | |
94 regnames[reg1], regnames[reg2]); | |
95 else | |
96 printf("%s\t%s, %s\n", opctab[op], | |
97 regnames[reg1], regnames[reg2]); | |
98 } else | |
99 printf("<invalid: hi-reg format with both low regs>\n"); | |
100 } | |
101 | |
102 static void | |
103 format_5(word) | |
104 unsigned word; | |
105 { | |
106 if ((word & 0x300) == 0x300) | |
107 format_5_bx(word); | |
108 else | |
109 format_5_hiops(word); | |
110 } | |
111 | |
112 static void | |
113 format_6(sec, off, word) | |
114 struct internal_scnhdr *sec; | |
115 unsigned off, word; | |
116 { | |
117 unsigned loff, litoff; | |
118 | |
119 loff = (word & 0xFF) << 2; | |
120 off &= ~3; | |
121 off += 4; | |
122 litoff = off + loff; | |
123 if (litoff+4 <= sec->size) | |
124 printf("ldr\t%s, =0x%x\t; via 0x%x\n", regnames[(word>>8)&7], | |
125 get_u32(filemap + sec->data_offset + litoff), litoff); | |
126 else | |
127 printf("ldr\t%s, [pc, #%u]\t(0x%x)\n", regnames[(word>>8)&7], | |
128 loff, litoff); | |
129 } | |
130 | |
131 static void | |
132 format_7(word) | |
133 unsigned word; | |
134 { | |
135 printf("%s%s\t%s, [%s, %s]\n", word&0x800 ? "ldr" : "str", | |
136 word&0x400 ? "b" : "", regnames[word&7], | |
137 regnames[(word>>3)&7], regnames[(word>>6)&7]); | |
138 } | |
139 | |
140 static void | |
141 format_8(word) | |
142 unsigned word; | |
143 { | |
144 static char *opc[4] = {"strh", "ldrsb", "ldrh", "ldrsh"}; | |
145 | |
146 printf("%s\t%s, [%s, %s]\n", opc[(word>>10)&3], regnames[word&7], | |
147 regnames[(word>>3)&7], regnames[(word>>6)&7]); | |
148 } | |
149 | |
150 static void | |
151 format_9(word) | |
152 unsigned word; | |
153 { | |
154 unsigned loff; | |
155 | |
156 loff = (word >> 6) & 0x1F; | |
157 if (!(word & 0x1000)) | |
158 loff <<= 2; | |
159 printf("%s%s\t%s, [%s, #%u]", word&0x800 ? "ldr" : "str", | |
160 word&0x1000 ? "b" : "", regnames[word&7], | |
161 regnames[(word>>3)&7], loff); | |
162 if (loff >= 10) | |
163 printf("\t; 0x%x", loff); | |
164 putchar('\n'); | |
165 } | |
166 | |
167 static void | |
168 format_10(word) | |
169 unsigned word; | |
170 { | |
171 unsigned loff; | |
172 | |
173 loff = (word >> 6) & 0x1F; | |
174 loff <<= 1; | |
175 printf("%sh\t%s, [%s, #%u]", word&0x800 ? "ldr" : "str", | |
176 regnames[word&7], regnames[(word>>3)&7], loff); | |
177 if (loff >= 10) | |
178 printf("\t; 0x%x", loff); | |
179 putchar('\n'); | |
180 } | |
181 | |
182 static void | |
183 format_11(word) | |
184 unsigned word; | |
185 { | |
186 unsigned loff; | |
187 | |
188 loff = (word & 0xFF) << 2; | |
189 printf("%s\t%s, [sp, #%u]", word&0x800 ? "ldr" : "str", | |
190 regnames[(word>>8)&7], loff); | |
191 if (loff >= 10) | |
192 printf("\t; 0x%x", loff); | |
193 putchar('\n'); | |
194 } | |
195 | |
196 static void | |
197 format_12(off, word) | |
198 unsigned off, word; | |
199 { | |
200 unsigned loff; | |
201 | |
202 loff = (word & 0xFF) << 2; | |
203 printf("add\t%s, %s, #%u", regnames[(word>>8)&7], | |
204 word&0x800 ? "sp" : "pc", loff); | |
205 if (loff >= 10) | |
206 printf("\t; 0x%x", loff); | |
207 putchar('\n'); | |
208 } | |
209 | |
210 static void | |
211 format_13(word) | |
212 unsigned word; | |
213 { | |
214 unsigned loff; | |
215 | |
216 if ((word & 0xFF00) != 0xB000) { | |
217 printf("<invalid format 13>\n"); | |
218 return; | |
219 } | |
220 loff = (word & 0x7F) << 2; | |
221 printf("%s\tsp, #%u", word&0x80 ? "sub" : "add", loff); | |
222 if (loff >= 10) | |
223 printf("\t; 0x%x", loff); | |
224 putchar('\n'); | |
225 } | |
226 | |
227 static void | |
228 format_14(word) | |
229 unsigned word; | |
230 { | |
231 int r, flag; | |
232 | |
233 if ((word & 0xF600) != 0xB400) { | |
234 printf("<invalid format 14>\n"); | |
235 return; | |
236 } | |
237 printf("%s\t{", word&0x800 ? "pop" : "push"); | |
238 flag = 0; | |
239 for (r = 0; r < 9; r++) | |
240 if (word & (1 << r)) { | |
241 if (flag) | |
242 fputs(", ", stdout); | |
243 if (r == 8) | |
244 fputs(word&0x800 ? "pc" : "lr", stdout); | |
245 else | |
246 fputs(regnames[r], stdout); | |
247 flag = 1; | |
248 } | |
249 putchar('}'); | |
250 putchar('\n'); | |
251 } | |
252 | |
253 static void | |
254 format_15(word) | |
255 unsigned word; | |
256 { | |
257 int r, flag; | |
258 | |
259 printf("%sia\t%s!, {", word&0x800 ? "ldm" : "stm", | |
260 regnames[(word>>8)&7]); | |
261 flag = 0; | |
262 for (r = 0; r < 8; r++) | |
263 if (word & (1 << r)) { | |
264 if (flag) | |
265 fputs(", ", stdout); | |
266 fputs(regnames[r], stdout); | |
267 flag = 1; | |
268 } | |
269 putchar('}'); | |
270 putchar('\n'); | |
271 } | |
272 | |
273 static void | |
274 format_16_17(off, word) | |
275 unsigned off, word; | |
276 { | |
277 unsigned cond; | |
278 unsigned dest; | |
279 | |
280 cond = (word >> 8) & 0xF; | |
281 switch (cond) { | |
282 case 0xE: | |
283 printf("<invalid: bal>\n"); | |
284 return; | |
285 case 0xF: | |
286 printf("swi\t0x%x\n", word & 0xFF); | |
287 return; | |
288 } | |
289 dest = (word & 0xFF) << 1; | |
290 if (dest & 0x00000100) | |
291 dest |= 0xFFFFFE00; | |
292 dest += off + 4; | |
293 printf("b%s\t0x%x\n", condition_decode[cond], dest); | |
294 } | |
295 | |
296 static void | |
297 format_18(off, word) | |
298 unsigned off, word; | |
299 { | |
300 unsigned dest; | |
301 | |
302 if (word & 0x800) { | |
303 printf("<invalid format 18>\n"); | |
304 return; | |
305 } | |
306 dest = (word & 0x7FF) << 1; | |
307 if (dest & 0x00000800) | |
308 dest |= 0xFFFFF000; | |
309 dest += off + 4; | |
310 printf("b\t0x%x\n", dest); | |
311 } | |
312 | |
313 void | |
314 thumb_disasm_line(sec, off) | |
315 struct internal_scnhdr *sec; | |
316 unsigned off; | |
317 { | |
318 unsigned word; | |
319 | |
320 word = get_u16(filemap + sec->data_offset + off); | |
321 printf("%04x\t\t", word); | |
322 switch (word >> 12) { | |
323 case 0: | |
324 case 1: | |
325 format_1_2(word); | |
326 return; | |
327 case 2: | |
328 case 3: | |
329 format_3(word); | |
330 return; | |
331 case 4: | |
332 if (word & 0x800) | |
333 format_6(sec, off, word); | |
334 else if (word & 0x400) | |
335 format_5(word); | |
336 else | |
337 format_4(word); | |
338 return; | |
339 case 5: | |
340 if (word & 0x200) | |
341 format_8(word); | |
342 else | |
343 format_7(word); | |
344 return; | |
345 case 6: | |
346 case 7: | |
347 format_9(word); | |
348 return; | |
349 case 8: | |
350 format_10(word); | |
351 return; | |
352 case 9: | |
353 format_11(word); | |
354 return; | |
355 case 0xA: | |
356 format_12(off, word); | |
357 return; | |
358 case 0xB: | |
359 if (word & 0x400) | |
360 format_14(word); | |
361 else | |
362 format_13(word); | |
363 return; | |
364 case 0xC: | |
365 format_15(word); | |
366 return; | |
367 case 0xD: | |
368 format_16_17(off, word); | |
369 return; | |
370 case 0xE: | |
371 format_18(off, word); | |
372 return; | |
373 case 0xF: | |
374 printf("<half-bl>\n"); | |
375 return; | |
376 } | |
377 } | |
378 | |
379 thumb_check_bl(sec, off) | |
380 struct internal_scnhdr *sec; | |
381 unsigned off; | |
382 { | |
383 unsigned ins1, ins2; | |
384 unsigned dest; | |
385 | |
386 ins1 = get_u16(filemap + sec->data_offset + off); | |
387 if ((ins1 & 0xF800) != 0xF000) | |
388 return(0); | |
389 ins2 = get_u16(filemap + sec->data_offset + off + 2); | |
390 if ((ins2 & 0xF800) != 0xF800) | |
391 return(0); | |
392 /* match */ | |
393 dest = ((ins1 & 0x7FF) << 12) | ((ins2 & 0x7FF) << 1); | |
394 if (dest & 0x00400000) | |
395 dest |= 0xFF800000; | |
396 dest += off + 4; | |
397 printf("%04x %04x\tbl\t0x%x\n", ins1, ins2, dest); | |
398 return(1); | |
399 } |