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