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 }