comparison ticoff/armdis.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 * ARM 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 char *dataproc_ops[16] = {"and", "eor", "sub", "rsb",
18 "add", "adc", "sbc", "rsc",
19 "tst", "teq", "cmp", "cmn",
20 "orr", "mov", "bic", "mvn"};
21
22 static void
23 arm_branch(off, word)
24 unsigned off, word;
25 {
26 unsigned dest;
27
28 dest = (word & 0x00FFFFFF) << 2;
29 if (dest & 0x02000000)
30 dest |= 0xFC000000;
31 dest += off + 8;
32 printf("b%s%s\t0x%x\n", word&0x1000000 ? "l" : "",
33 condition_decode[word>>28], dest);
34 }
35
36 static void
37 op2_immed(word)
38 unsigned word;
39 {
40 unsigned low8, rot, val;
41
42 low8 = word & 0xFF;
43 rot = (word & 0xF00) >> 7;
44 val = (low8 << (32 - rot)) | (low8 >> rot);
45 if (val <= 9)
46 printf("#%u\n", val);
47 else
48 printf("#%u\t; 0x%x\n", val, val);
49 }
50
51 static void
52 op2_regbyconst(word)
53 unsigned word;
54 {
55 unsigned c, t;
56
57 c = (word >> 7) & 0x1F;
58 t = (word >> 5) & 3;
59 if (!c) {
60 switch (t) {
61 case 0:
62 printf("%s", regnames[word&0xF]);
63 return;
64 case 3:
65 printf("%s, rrx", regnames[word&0xF]);
66 return;
67 default:
68 c = 32;
69 }
70 }
71 printf("%s, %s #%u", regnames[word&0xF], shift_types[t], c);
72 }
73
74 static void
75 op2_regbyreg(word)
76 unsigned word;
77 {
78 printf("%s, %s %s", regnames[word&0xF], shift_types[(word>>5)&3],
79 regnames[(word>>8)&0xF]);
80 }
81
82 static void
83 op2_regshift(word)
84 unsigned word;
85 {
86 if (word & 0x10)
87 op2_regbyreg(word);
88 else
89 op2_regbyconst(word);
90 putchar('\n');
91 }
92
93 static void
94 dataproc_op2(word)
95 unsigned word;
96 {
97 if (word & 0x02000000)
98 op2_immed(word);
99 else
100 op2_regshift(word);
101 }
102
103 static void
104 dataproc_tstcmp_overlay(word)
105 unsigned word;
106 {
107 char msrmask[5], *cp;
108
109 if ((word & 0x0FFFFFF0) == 0x012FFF10) {
110 printf("bx%s\t%s\n", condition_decode[word>>28],
111 regnames[word&0xF]);
112 return;
113 } else if ((word & 0x0FBF0FFF) == 0x010F0000) {
114 printf("mrs%s\t%s, %cPSR\n", condition_decode[word>>28],
115 regnames[(word>>12)&0xF], word&0x400000 ? 'S' : 'C');
116 return;
117 } else if ((word & 0x0DB0F000) == 0x0120F000) {
118 if (!(word & 0x02000000) && (word & 0xFF0)) {
119 printf("<invalid MSR>\n");
120 return;
121 }
122 if (word & 0xF0000) {
123 cp = msrmask;
124 if (word & 0x80000)
125 *cp++ = 'f';
126 if (word & 0x40000)
127 *cp++ = 's';
128 if (word & 0x20000)
129 *cp++ = 'x';
130 if (word & 0x10000)
131 *cp++ = 'c';
132 *cp = '\0';
133 } else
134 strcpy(msrmask, "null");
135 printf("msr%s\t%cPSR_%s, ", condition_decode[word>>28],
136 word&0x400000 ? 'S' : 'C', msrmask);
137 dataproc_op2(word);
138 return;
139 }
140 printf("<invalid BX/MRS/MSR>\n");
141 }
142
143 static void
144 dataproc(word)
145 unsigned word;
146 {
147 unsigned opc;
148
149 opc = (word >> 21) & 0xF;
150 switch (opc) {
151 case 0:
152 case 1:
153 case 2:
154 case 3:
155 case 4:
156 case 5:
157 case 6:
158 case 7:
159 case 0xC:
160 case 0xE:
161 printf("%s%s%s\t%s, %s, ", dataproc_ops[opc],
162 condition_decode[word>>28], word&0x100000 ? "s" : "",
163 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]);
164 dataproc_op2(word);
165 return;
166 case 0xD:
167 case 0xF:
168 printf("%s%s%s\t%s, ", dataproc_ops[opc],
169 condition_decode[word>>28], word&0x100000 ? "s" : "",
170 regnames[(word>>12)&0xF]);
171 dataproc_op2(word);
172 return;
173 case 8:
174 case 9:
175 case 0xA:
176 case 0xB:
177 if (word & 0x100000) {
178 printf("%s%s\t%s, ", dataproc_ops[opc],
179 condition_decode[word>>28],
180 regnames[(word>>16)&0xF]);
181 dataproc_op2(word);
182 } else
183 dataproc_tstcmp_overlay(word);
184 return;
185 }
186 }
187
188 static void
189 multiply(word)
190 unsigned word;
191 {
192 if ((word & 0x0FE000F0) == 0x90)
193 printf("mul%s%s\t%s, %s, %s\n", condition_decode[word>>28],
194 word&0x100000 ? "s" : "", regnames[(word>>16)&0xF],
195 regnames[word&0xF], regnames[(word>>8)&0xF]);
196 else if ((word & 0x0FE000F0) == 0x00200090)
197 printf("mla%s%s\t%s, %s, %s, %s\n", condition_decode[word>>28],
198 word&0x100000 ? "s" : "", regnames[(word>>16)&0xF],
199 regnames[word&0xF], regnames[(word>>8)&0xF],
200 regnames[(word>>12)&0xF]);
201 else if ((word & 0x0F8000F0) == 0x00800090)
202 printf("%c%sl%s%s\t%s, %s, %s, %s\n",
203 word&0x400000 ? 's' : 'u',
204 word&0x200000 ? "mla" : "mul",
205 condition_decode[word>>28],
206 word&0x100000 ? "s" : "",
207 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF],
208 regnames[word&0xF], regnames[(word>>8)&0xF]);
209 else if ((word & 0x0FB00FF0) == 0x01000090)
210 printf("swp%s%s\t%s, %s, [%s]\n", condition_decode[word>>28],
211 word&0x400000, "b", "", regnames[(word>>12)&0xF],
212 regnames[word&0xF], regnames[(word>>16)&0xF]);
213 else
214 printf("<invalid multiply>\n");
215 }
216
217 static int
218 check_ldr_litpool(sec, off, word, loff, size)
219 struct internal_scnhdr *sec;
220 unsigned off, word, loff;
221 {
222 unsigned litoff, datum;
223
224 /* base reg must be 15 */
225 if (((word >> 16) & 0xF) != 15)
226 return(0);
227 /* must be a load */
228 if (!(word & 0x100000))
229 return(0);
230 /* no writeback allowed */
231 if (word & 0x200000)
232 return(0);
233 /* alignment */
234 if (loff & (size - 1))
235 return(0);
236 /* range */
237 off += 8;
238 if (word & 0x800000)
239 litoff = off + loff;
240 else {
241 if (loff > off)
242 return(0);
243 litoff = off - loff;
244 }
245 if (litoff >= sec->size)
246 return(0);
247 /* all checks passed, proceed */
248 switch (size) {
249 case 1:
250 datum = filemap[sec->data_offset + litoff];
251 break;
252 case 2:
253 datum = get_u16(filemap + sec->data_offset + litoff);
254 break;
255 case 4:
256 datum = get_u32(filemap + sec->data_offset + litoff);
257 break;
258 }
259 printf("=0x%x\t; via 0x%x\n", datum, litoff);
260 return(1);
261 }
262
263 static void
264 ldr_str_imm_pre(sec, off, word)
265 struct internal_scnhdr *sec;
266 unsigned off, word;
267 {
268 unsigned loff = word & 0xFFF;
269
270 printf("%s%s%s\t%s, ", word&0x100000 ? "ldr" : "str",
271 condition_decode[word>>28], word&0x400000 ? "b" : "",
272 regnames[(word>>12)&0xF]);
273 if (check_ldr_litpool(sec, off, word, loff, word&0x400000 ? 1 : 4))
274 return;
275 printf("[%s", regnames[(word>>16)&0xF]);
276 if (loff || word&0x200000)
277 printf(", #%s%u", word&0x800000 ? "" : "-", loff);
278 putchar(']');
279 if (word & 0x200000)
280 putchar('!');
281 if (loff >= 10)
282 printf("\t; 0x%x", loff);
283 putchar('\n');
284 }
285
286 static void
287 ldr_str_imm_post(word)
288 unsigned word;
289 {
290 unsigned loff = word & 0xFFF;
291
292 printf("%s%s%s%s\t%s, [%s], #%s%u", word&0x100000 ? "ldr" : "str",
293 condition_decode[word>>28], word&0x400000 ? "b" : "",
294 word&0x200000 ? "t" : "",
295 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF],
296 word&0x800000 ? "" : "-", loff);
297 if (loff >= 10)
298 printf("\t; 0x%x", loff);
299 putchar('\n');
300 }
301
302 static void
303 ldr_str_reg_pre(word)
304 unsigned word;
305 {
306 if (word & 0x10) {
307 printf("<invalid ldr/str: offset reg shift by reg>\n");
308 return;
309 }
310 printf("%s%s%s\t%s, [%s, ", word&0x100000 ? "ldr" : "str",
311 condition_decode[word>>28], word&0x400000 ? "b" : "",
312 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]);
313 if (!(word & 0x800000))
314 putchar('-');
315 op2_regbyconst(word);
316 putchar(']');
317 if (word & 0x200000)
318 putchar('!');
319 putchar('\n');
320 }
321
322 static void
323 ldr_str_reg_post(word)
324 unsigned word;
325 {
326 if (word & 0x10) {
327 printf("<invalid ldr/str: offset reg shift by reg>\n");
328 return;
329 }
330 printf("%s%s%s%s\t%s, [%s], ", word&0x100000 ? "ldr" : "str",
331 condition_decode[word>>28], word&0x400000 ? "b" : "",
332 word&0x200000 ? "t" : "",
333 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]);
334 if (!(word & 0x800000))
335 putchar('-');
336 op2_regbyconst(word);
337 putchar('\n');
338 }
339
340 static void
341 ldr_str_ext(sec, off, word)
342 struct internal_scnhdr *sec;
343 unsigned off, word;
344 {
345 unsigned loff;
346
347 if (!(word&0x01000000) && word&0x200000) {
348 printf("<invalid ldrh/strh: P=0, W=1>\n");
349 return;
350 }
351 if (!(word&0x400000) && word&0xF00) {
352 printf("<invalid ldrh/strh: SBZ!=0>\n");
353 return;
354 }
355 printf("%s%s%s%c\t%s, ", word&0x100000 ? "ldr" : "str",
356 condition_decode[word>>28],
357 word&0x40 ? "s" : "",
358 word&0x20 ? 'h' : 'b',
359 regnames[(word>>12)&0xF]);
360 if (word & 0x400000)
361 loff = ((word & 0xF00) >> 4) | (word & 0xF);
362 switch (word & 0x01400000) {
363 case 0:
364 /* reg post */
365 printf("[%s], %s%s", regnames[(word>>16)&0xF],
366 word&0x800000 ? "" : "-", regnames[word&0xF]);
367 break;
368 case 0x400000:
369 /* imm post */
370 printf("[%s], #%s%u", regnames[(word>>16)&0xF],
371 word&0x800000 ? "" : "-", loff);
372 if (loff >= 10)
373 printf("\t; 0x%x", loff);
374 break;
375 case 0x01000000:
376 /* reg pre */
377 printf("[%s, %s%s]%s", regnames[(word>>16)&0xF],
378 word&0x800000 ? "" : "-", regnames[word&0xF],
379 word&0x200000 ? "!" : "");
380 break;
381 case 0x01400000:
382 /* imm pre */
383 if (check_ldr_litpool(sec, off, word, loff, word&0x20 ? 2 : 1))
384 return;
385 printf("[%s", regnames[(word>>16)&0xF]);
386 if (loff || word&0x200000)
387 printf(", #%s%u", word&0x800000 ? "" : "-", loff);
388 putchar(']');
389 if (word & 0x200000)
390 putchar('!');
391 if (loff >= 10)
392 printf("\t; 0x%x", loff);
393 break;
394 }
395 putchar('\n');
396 }
397
398 static void
399 dataproc_74_overlay(sec, off, word)
400 struct internal_scnhdr *sec;
401 unsigned off, word;
402 {
403 if (word & 0x60)
404 ldr_str_ext(sec, off, word);
405 else
406 multiply(word);
407 }
408
409 static void
410 ldm_stm(word)
411 unsigned word;
412 {
413 int r, flag;
414
415 printf("%s%s%c%c\t%s", word&0x100000 ? "ldm" : "stm",
416 condition_decode[word>>28],
417 word&0x800000 ? 'i' : 'd', word&0x01000000 ? 'b' : 'a',
418 regnames[(word>>16)&0xF]);
419 if (word & 0x200000)
420 putchar('!');
421 fputs(", {", stdout);
422 flag = 0;
423 for (r = 0; r < 16; r++)
424 if (word & (1 << r)) {
425 if (flag)
426 fputs(", ", stdout);
427 fputs(regnames[r], stdout);
428 flag = 1;
429 }
430 putchar('}');
431 if (word & 0x400000)
432 putchar('^');
433 putchar('\n');
434 }
435
436 void
437 arm_disasm_line(sec, off)
438 struct internal_scnhdr *sec;
439 unsigned off;
440 {
441 unsigned word;
442
443 word = get_u32(filemap + sec->data_offset + off);
444 printf("%08x\t", word);
445 if ((word >> 28) == 0xF) {
446 printf("<invalid-F>\n");
447 return;
448 }
449 switch ((word >> 24) & 0xF) {
450 case 0:
451 case 1:
452 if ((word & 0x90) == 0x90)
453 dataproc_74_overlay(sec, off, word);
454 else
455 dataproc(word);
456 return;
457 case 2:
458 case 3:
459 dataproc(word);
460 return;
461 case 4:
462 ldr_str_imm_post(word);
463 return;
464 case 5:
465 ldr_str_imm_pre(sec, off, word);
466 return;
467 case 6:
468 ldr_str_reg_post(word);
469 return;
470 case 7:
471 ldr_str_reg_pre(word);
472 return;
473 case 8:
474 case 9:
475 ldm_stm(word);
476 return;
477 case 0xA:
478 case 0xB:
479 arm_branch(off, word);
480 return;
481 case 0xC:
482 case 0xD:
483 case 0xE:
484 printf("<COPROCESSOR>\n");
485 return;
486 case 0xF:
487 printf("swi%s\t0x%x\n", condition_decode[word>>28],
488 word & 0xFFFFFF);
489 return;
490 }
491 }