comparison leo-obj/tool/armdis.c @ 130:87b82398a08b

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