1 /*
2 ** cpu.c ARM cpu-description file
3 ** (c) in 2004,2006,2010,2011,2014-2016 by Frank Wille
4 */
5
6 #include "vasm.h"
7
8 mnemonic mnemonics[] = {
9 #include "opcodes.h"
10 };
11 int mnemonic_cnt = sizeof(mnemonics)/sizeof(mnemonics[0]);
12
13 char *cpu_copyright = "vasm ARM cpu backend 0.4d (c) 2004,2006,2010,2011,2014-2016 Frank Wille";
14 char *cpuname = "ARM";
15 int bitsperbyte = 8;
16 int bytespertaddr = 4;
17
18 uint32_t cpu_type = AAANY;
19 int arm_be_mode = 0; /* Little-endian is default */
20 int thumb_mode = 0; /* 1: Thumb instruction set (16 bit) is active */
21
22 /* options */
23 static unsigned char opt_ldrpc = 0; /* LDR r,sym -> ADD / LDR */
24 static unsigned char opt_adr = 0; /* ADR r,sym -> ADRL (ADD/ADD|SUB/SUB) */
25
26 /* constant data */
27 static const char *condition_codes = "eqnecsccmiplvsvchilsgeltgtlealnvhsloul";
28
29 static const char *addrmode_strings[] = {
30 "da","ia","db","ib",
31 "fa","fd","ea","ed",
32 "bt","tb","sb","sh","t","b","h","s","l",
33 "p",NULL,"<none>"
34 };
35 enum {
36 AM_DA=0,AM_IA,AM_DB,AM_IB,AM_FA,AM_FD,AM_EA,AM_ED,
37 AM_BT,AM_TB,AM_SB,AM_SH,AM_T,AM_B,AM_H,AM_S,AM_L,
38 AM_P,AM_NULL,AM_NONE
39 };
40
41 #define NUM_SHIFTTYPES 6
42 static const char *shift_strings[NUM_SHIFTTYPES] = {
43 "LSL","LSR","ASR","ROR","RRX","ASL"
44 };
45
46 static int OC_SWP,OC_NOP;
47 static int elfoutput = 0; /* output will be an ELF object file */
48
49 static section *last_section = 0;
50 static int last_data_type = -1; /* for mapping symbol generation */
51 #define TYPE_ARM 0
52 #define TYPE_THUMB 1
53 #define TYPE_DATA 2
54
55 #define THB_PREFETCH 4 /* prefetch-correction for Thumb-branches */
56 #define ARM_PREFETCH 8 /* prefetch-correction for ARM-branches */
57
58
59
new_operand(void)60 operand *new_operand(void)
61 {
62 return mycalloc(sizeof(operand));
63 }
64
65
cpu_available(int idx)66 int cpu_available(int idx)
67 {
68 return (mnemonics[idx].ext.available & cpu_type) != 0;
69 }
70
71
parse_cpu_special(char * start)72 char *parse_cpu_special(char *start)
73 /* parse cpu-specific directives; return pointer to end of
74 cpu-specific text */
75 {
76 char *name=start,*s=start;
77
78 if (ISIDSTART(*s)) {
79 s++;
80 while (ISIDCHAR(*s))
81 s++;
82 if (s-name==6 && !strncmp(name,".thumb",6)) {
83 thumb_mode = 1;
84 return s;
85 }
86 else if (s-name==4 && !strncmp(name,".arm",4)) {
87 thumb_mode = 0;
88 return s;
89 }
90 }
91 return start;
92 }
93
94
parse_instruction(char * s,int * inst_len,char ** ext,int * ext_len,int * ext_cnt)95 char *parse_instruction(char *s,int *inst_len,char **ext,int *ext_len,
96 int *ext_cnt)
97 /* parse instruction and save extension locations */
98 {
99 char *inst = s;
100 int cnt = *ext_cnt;
101
102 while (*s && !isspace((unsigned char)*s))
103 s++;
104
105 if (thumb_mode) { /* no qualifiers in THUMB code */
106 *inst_len = s - inst;
107 }
108
109 else { /* ARM mode - we might have up to 2 different qualifiers */
110 int len = s - inst;
111 char c = tolower((unsigned char)*inst);
112
113 if (len > 2) {
114 if (c=='b' && strnicmp(inst,"bic",3) && (len==3 || len==4)) {
115 *inst_len = len - 2;
116 }
117 else if ((c=='u' || c=='s') &&
118 tolower((unsigned char)*(inst+1))=='m' && len>=5) {
119 *inst_len = 5;
120 }
121 else
122 *inst_len = 3;
123 len -= *inst_len;
124
125 if (len > 0) {
126 char *p = inst + *inst_len;
127
128 if (len >= 2) {
129 const char *cc = condition_codes;
130
131 while (*cc) {
132 if (!strnicmp(p,cc,2))
133 break;
134 cc += 2;
135 }
136 if (*cc) { /* matched against a condition code */
137 ext[cnt] = p;
138 ext_len[cnt++] = 2;
139 p += 2;
140 len -= 2;
141 }
142 }
143 if (len >= 1) {
144 const char **am = addrmode_strings;
145
146 do {
147 if (len==strlen(*am) && !strnicmp(*am,p,len))
148 break;
149 am++;
150 }
151 while (*am);
152 if (*am!=NULL || (len==1 && tolower((unsigned char)*p)=='s')) {
153 ext[cnt] = p;
154 ext_len[cnt++] = len;
155 }
156 }
157 }
158 else if (len < 0)
159 ierror(0);
160 }
161 else
162 *inst_len = len;
163
164 *ext_cnt = cnt;
165 }
166
167 return s;
168 }
169
170
set_default_qualifiers(char ** q,int * q_len)171 int set_default_qualifiers(char **q,int *q_len)
172 /* fill in pointers to default qualifiers, return number of qualifiers */
173 {
174 return 0;
175 }
176
177
parse_reg(char ** pp)178 static int parse_reg(char **pp)
179 /* parse register, return -1 on error */
180 {
181 char *p = *pp;
182 char *name = p;
183 regsym *sym;
184
185 if (ISIDSTART(*p)) {
186 p++;
187 while (ISIDCHAR(*p))
188 p++;
189 if (sym = find_regsym_nc(name,p-name)) {
190 *pp = p;
191 return sym->reg_num;
192 }
193 }
194 return -1; /* no valid register found */
195 }
196
197
parse_reglist(char ** pp)198 static int parse_reglist(char **pp)
199 /* parse register-list, return -1 on error */
200 {
201 int r=0,list=0,lastreg=-1;
202 char *p = *pp;
203 char *name;
204 regsym *sym;
205
206 if (*p++ == '{') {
207 p = skip(p);
208
209 do {
210 if (ISIDSTART(*p)) {
211 name = p++;
212 while (ISIDCHAR(*p))
213 p++;
214 if (sym = find_regsym_nc(name,p-name)) {
215 r = sym->reg_num;
216 if (lastreg >= 0) { /* range-mode? */
217 if (lastreg < r) {
218 r = lastreg;
219 lastreg = sym->reg_num;
220 }
221 for (; r<=lastreg; list |= 1<<r++);
222 }
223 else
224 list |= 1<<r;
225 p = skip(p);
226 }
227 else
228 return -1;
229 }
230 if (*p == ',') {
231 lastreg = -1;
232 p = skip(p+1);
233 }
234 else if (*p == '-') {
235 lastreg = r;
236 p = skip(p+1);
237 }
238 }
239 while (*p!='\0' && *p!='}');
240
241 if (*p) {
242 *pp = ++p;
243 return list;
244 }
245 }
246
247 return -1;
248 }
249
250
parse_operand(char * p,int len,operand * op,int optype)251 int parse_operand(char *p,int len,operand *op,int optype)
252 /* Parses operands, reads expressions and assigns relocation types */
253 {
254 char *start = p;
255
256 op->type = optype;
257 op->flags = 0;
258 op->value = NULL;
259 p = skip(p);
260
261 if (optype == DATA64_OP) {
262 op->value = parse_expr_huge(&p);
263 }
264
265 else if (thumb_mode) {
266 if (ARMOPER(optype)) { /* standard ARM instruction */
267 return PO_NOMATCH;
268 }
269
270 else if (THREGOPER(optype)) {
271 /* parse a register */
272 int r;
273
274 if (optype==TR5IN || optype==TPCPR || optype==TSPPR) {
275 if (*p++ != '[')
276 return PO_NOMATCH;
277 p = skip(p);
278 }
279
280 if ((r = parse_reg(&p)) < 0)
281 return PO_NOMATCH;
282 op->value = number_expr((taddr)r);
283
284 if (optype==TPCRG || optype==TPCPR) {
285 if (r != 15)
286 return PO_NOMATCH;
287 }
288 else if (optype==TSPRG || optype==TSPPR) {
289 if (r != 13)
290 return PO_NOMATCH;
291 }
292 else if (optype==THR02 || optype==THR05) {
293 if (r<8 || r>15)
294 return PO_NOMATCH;
295 }
296 else {
297 if (r<0 || r>7)
298 return PO_NOMATCH;
299 }
300 if (optype == TR8IN) {
301 p = skip(p);
302 if (*p++ != ']')
303 return PO_NOMATCH;
304 }
305 else if (optype == TR10W) {
306 if (*p++ != '!')
307 return PO_NOMATCH;
308 }
309 }
310
311 else if (THREGLIST(optype)) {
312 taddr list = parse_reglist(&p);
313
314 if (optype == TRLST) {
315 if (list & ~0xff)
316 return PO_NOMATCH; /* only r0-r7 allowed */
317 }
318 else {
319 if ((list&0x8000) && optype==TRLPC) {
320 list = list&~0x8000 | 0x100;
321 }
322 else if ((list&0x4000) && optype==TRLLR) {
323 list = list&~0x4000 | 0x100;
324 }
325 if (list & ~0x1ff)
326 return PO_NOMATCH; /* only r0-r7 / pc / lr allowed */
327 }
328 op->value = number_expr(list);
329 }
330
331 else { /* just parse an expression */
332 char *q;
333
334 if (THIMMOPER(optype)) {
335 if (*p++ != '#')
336 return PO_NOMATCH;
337 p = skip(p);
338 }
339
340 q = p;
341 if (*q=='+' || *q=='-')
342 q = skip(q+1);
343 if (!ISIDSTART(*q) && !isdigit((unsigned char)*q))
344 return PO_NOMATCH;
345 op->value = parse_expr(&p);
346
347 if (THIMMINDIR(optype)) {
348 p = skip(p);
349 if (*p++ != ']')
350 return PO_NOMATCH;
351 }
352 }
353 }
354
355 else { /* ARM mode */
356 if (THUMBOPER(optype)) { /* Thumb instruction */
357 return PO_NOMATCH;
358 }
359
360 else if (STDOPER(optype)) {
361 /* parse an expression (register, label, imm.) and assign to 'value' */
362 if (IMMEDOPER(optype)) {
363 if (*p++ != '#')
364 return PO_NOMATCH;
365 p = skip(p);
366 }
367 else if (optype==R19PR || optype==R19PO) {
368 if (*p++ != '[')
369 return PO_NOMATCH;
370 p = skip(p);
371 }
372
373 if (UPDOWNOPER(optype)) {
374 if (*p == '-') {
375 p = skip(p+1);
376 }
377 else {
378 if (*p == '+')
379 p = skip(p+1);
380 op->flags |= OFL_UP;
381 }
382 }
383
384 if (REGOPER(optype)) {
385 int r = parse_reg(&p);
386
387 if (r >= 0)
388 op->value = number_expr((taddr)r);
389 else
390 return PO_NOMATCH;
391 }
392 else { /* an expression */
393 if (ISIDSTART(*p) || isdigit((unsigned char)*p) ||
394 (!UPDOWNOPER(optype) && (*p=='-' || *p=='+')))
395 op->value = parse_expr(&p);
396 else
397 return PO_NOMATCH;
398 }
399
400 if (optype==R19PO || optype==R3UD1 || optype==IMUD1 || optype==IMCP1) {
401 p = skip(p);
402 if (*p++ != ']')
403 return PO_NOMATCH;
404 }
405 if (optype==R19WB || optype==R3UD1 || optype==IMUD1 || optype==IMCP1) {
406 if (*p == '!') {
407 p++;
408 op->flags |= OFL_WBACK;
409 }
410 }
411 }
412
413 else if (SHIFTOPER(optype)) {
414 char *name = p;
415 int i;
416
417 p = skip_identifier(p);
418 if (p == NULL)
419 return PO_NOMATCH;
420 for (i=0; i<NUM_SHIFTTYPES; i++) {
421 if (!strnicmp(shift_strings[i],name,p-name))
422 break;
423 }
424 if (i >= NUM_SHIFTTYPES)
425 return PO_NOMATCH;
426 if (i == 4) {
427 /* RRX is ROR with immediate value 0 */
428 op->flags |= OFL_IMMEDSHIFT;
429 op->value = number_expr(0);
430 i = 3; /* ROR */
431 }
432 else {
433 /* parse immediate or register for LSL, LSR, ASR, ROR */
434 p = skip(p);
435 if (i == 5)
436 i = 0; /* ASL -> LSL */
437 if (*p == '#') {
438 p++;
439 op->flags |= OFL_IMMEDSHIFT;
440 op->value = parse_expr(&p);
441 }
442 else if (optype == SHIFT) {
443 int r = parse_reg(&p);
444
445 if (r >= 0)
446 op->value = number_expr((taddr)r);
447 else
448 return PO_NOMATCH;
449 }
450 else
451 return PO_NOMATCH; /* no shift-count in register allowed */
452 }
453 op->flags |= i & OFL_SHIFTOP;
454
455 if (optype == SHIM1) {
456 /* check for pre-indexed with optional write-back */
457 p = skip(p);
458 if (*p++ != ']')
459 return PO_NOMATCH;
460 if (*p == '!') {
461 p++;
462 op->flags |= OFL_WBACK;
463 }
464 }
465 }
466
467 else if (optype == CSPSR) {
468 char *name = p;
469
470 p = skip_identifier(p);
471 if (p == NULL)
472 return PO_NOMATCH;
473 if (!strnicmp(name,"CPSR",p-name))
474 op->flags &= ~OFL_SPSR;
475 else if (!strnicmp(name,"SPSR",p-name))
476 op->flags |= OFL_SPSR;
477 else
478 return PO_NOMATCH;
479 op->value = number_expr(0xf); /* all fields f,s,x,c */
480 }
481
482 else if (optype == PSR_F) {
483 char *name = p;
484 taddr fields = 0xf;
485
486 p = skip_identifier(p);
487 if (p==NULL || (p-name)<4)
488 return PO_NOMATCH;
489 if (!strnicmp(name,"CPSR",4))
490 op->flags &= ~OFL_SPSR;
491 else if (!strnicmp(name,"SPSR",4))
492 op->flags |= OFL_SPSR;
493 else
494 return PO_NOMATCH;
495
496 if ((p-name)>5 && *(name+4)=='_') {
497 fields = 0;
498 name += 5;
499 while (name < p) {
500 switch (tolower((unsigned char)*name++)) {
501 case 'f': fields |= 1; break;
502 case 's': fields |= 2; break;
503 case 'x': fields |= 4; break;
504 case 'c': fields |= 8; break;
505 default: return PO_NOMATCH;
506 }
507 }
508 }
509 else if ((p-name) > 4)
510 return PO_NOMATCH;
511 op->value = number_expr(fields);
512 }
513
514 else if (optype == RLIST) {
515 taddr list = parse_reglist(&p);
516
517 if (list >= 0) {
518 op->value = number_expr(list);
519 if (*p == '^') {
520 p++;
521 op->flags |= OFL_FORCE; /* set "load PSR / force user mode" flag */
522 }
523 }
524 else
525 return PO_NOMATCH;
526 }
527
528 else
529 ierror(0);
530 }
531
532 return (skip(p)-start < len) ? PO_NOMATCH : PO_MATCH;
533 }
534
535
create_mapping_symbol(int type,section * sec,taddr pc)536 static void create_mapping_symbol(int type,section *sec,taddr pc)
537 /* create mapping symbol ($a, $t, $d) as required by ARM ELF ABI */
538 {
539 static char names[3][4] = { "$a","$t","$d" };
540 static int types[3] = { TYPE_FUNCTION,TYPE_FUNCTION,TYPE_OBJECT };
541 symbol *sym;
542
543 if (type<TYPE_ARM || type>TYPE_DATA)
544 ierror(0);
545 if (elfoutput) {
546 sym = mymalloc(sizeof(symbol));
547 sym->type = LABSYM;
548 sym->flags = types[type];
549 sym->name = names[type];
550 sym->sec = sec;
551 sym->pc = pc;
552 sym->expr = 0;
553 sym->size = 0;
554 sym->align = 0;
555 add_symbol(sym);
556 }
557 last_data_type = type;
558 }
559
560
eval_thumb_operands(instruction * ip,section * sec,taddr pc,uint16_t * insn,dblock * db)561 size_t eval_thumb_operands(instruction *ip,section *sec,taddr pc,
562 uint16_t *insn,dblock *db)
563 /* evaluate expressions and try to optimize THUMB instruction,
564 return size of instruction */
565 {
566 operand op;
567 mnemonic *mnemo = &mnemonics[ip->code];
568 int opcnt = 0;
569 size_t isize = 2;
570
571 if (insn) {
572 if (pc & 1)
573 cpu_error(27); /* instruction at unaligned address */
574
575 if (ip->op[0] == NULL) {
576 /* handle inst. without operands, which don't have Thumb entries */
577 if (ip->code == OC_NOP)
578 *insn = 0x46c0; /* nop => mov r0,r0 */
579
580 return 2;
581 }
582 else
583 *insn = (uint16_t)mnemo->ext.opcode;
584 }
585
586 for (opcnt=0; opcnt<MAX_OPERANDS && ip->op[opcnt]!=NULL; opcnt++) {
587 taddr val;
588 symbol *base = NULL;
589 int btype;
590
591 op = *(ip->op[opcnt]);
592 if (!eval_expr(op.value,&val,sec,pc))
593 btype = find_base(op.value,&base,sec,pc);
594
595 /* do optimizations first */
596
597 if (op.type==TPCLW || THBRANCH(op.type)) {
598 /* PC-relative offsets (take prefetch into account: PC+4) */
599 if (base!=NULL && btype==BASE_OK) {
600 if (!is_pc_reloc(base,sec)) {
601 /* no relocation required, can be resolved immediately */
602 if (op.type == TPCLW) {
603 /* bit 1 of PC is forced to 0 */
604 val -= (pc&~2) + 4;
605 }
606 else
607 val -= pc + 4;
608
609 if (op.type == TBR08) {
610 if (val<-0x100 || val>0xfe) {
611 /* optimize to: B<!cc> .+4 ; B label */
612 if (insn) {
613 *insn++ ^= 0x100; /* negate branch-condition */
614 *insn = 0xe000; /* B unconditional to label */
615 }
616 if (val < 0)
617 val -= 2; /* backward-branches are 2 bytes longer */
618 isize += 2;
619 op.type = TBR11;
620 }
621 }
622 else if (op.type == TBRHL) {
623 /* BL always consists of two instructions */
624 isize += 2;
625 }
626 else if (op.type == TPCLW) {
627 /* @@@ optimization makes any sense? */
628 op.type = TUIMA;
629 base = NULL; /* no more checks */
630 }
631 }
632 else {
633 /* symbol is in a different section or externally declared */
634 if (op.type == TBRHL) {
635 val -= THB_PREFETCH;
636 if (db) {
637 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
638 arm_be_mode?5:0,11,0,0x7ff000);
639 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
640 arm_be_mode?16+5:16+0,11,0,0xffe);
641 }
642 isize += 2; /* we need two instructions for a 23-bit branch */
643 }
644 else if (op.type == TPCLW) {
645 /* val -= THB_PREFETCH; @@@ only positive offsets allowed! */
646 op.type = TUIMA;
647 if (db)
648 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
649 arm_be_mode?8:0,8,0,0x3fc);
650 base = NULL; /* no more checks */
651 }
652 else if (insn)
653 cpu_error(22); /* operation not allowed on external symbols */
654 }
655 }
656 else if (insn)
657 cpu_error(2); /* label from current section required */
658 }
659
660 /* optimizations should be finished at this stage -
661 inserts operands into the opcode now: */
662
663 if (insn) {
664
665 if (THREGOPER(op.type)) {
666 /* insert register operand, check was already done in parse_operand */
667 if (!THPCORSP(op.type)) {
668 switch (op.type) {
669 case TRG02:
670 case THR02:
671 *insn |= val&7;
672 break;
673 case TRG05:
674 case THR05:
675 case TR5IN:
676 *insn |= (val&7) << 3;
677 break;
678 case TRG08:
679 case TR8IN:
680 *insn |= (val&7) << 6;
681 break;
682 case TRG10:
683 case TR10W:
684 *insn |= (val&7) << 8;
685 break;
686 default:
687 ierror(0);
688 break;
689 }
690 }
691 }
692
693 else if (THREGLIST(op.type)) {
694 /* register list was already checked in parse_operand - just insert */
695 *insn |= val;
696 }
697
698 else if (THIMMOPER(op.type) || op.type==TSWI8) {
699 /* immediate operand */
700 switch (op.type) {
701 case TUIM3:
702 if (val>=0 && val<=7) {
703 *insn |= val<<6;
704 }
705 else
706 cpu_error(25,3,(long)val); /* immediate offset out of range */
707 break;
708 case TUIM5:
709 case TUI5I:
710 if (val>=0 && val<=0x1f) {
711 *insn |= val<<6;
712 }
713 else
714 cpu_error(25,5,(long)val); /* immediate offset out of range */
715 break;
716 case TUI6I:
717 if (val>=0 && val<=0x3e) {
718 if ((val & 1) == 0)
719 *insn |= (val&0x3e)<<5;
720 else
721 cpu_error(26,2); /* offset has to be a multiple of 2 */
722 }
723 else
724 cpu_error(25,6,(long)val); /* immediate offset out of range */
725 break;
726 case TUI7I:
727 if (val>=0 && val<=0x7c) {
728 if ((val & 3) == 0)
729 *insn |= (val&0x7c)<<4;
730 else
731 cpu_error(26,4); /* offset has to be a multiple of 4 */
732 }
733 else
734 cpu_error(25,7,(long)val); /* immediate offset out of range */
735 break;
736 case TUIM8:
737 case TSWI8:
738 if (val>=0 && val<=0xff) {
739 *insn |= val;
740 }
741 else
742 cpu_error(25,8,(long)val); /* immediate offset out of range */
743 break;
744 case TUIM9:
745 if (val>=0 && val<=0x1fc) {
746 if ((val & 3) == 0)
747 *insn |= val>>2;
748 else
749 cpu_error(26,4); /* offset has to be a multiple of 4 */
750 }
751 else
752 cpu_error(25,9,(long)val); /* immediate offset out of range */
753 break;
754 case TUIMA:
755 case TUIAI:
756 if (val>=0 && val<=0x3fc) {
757 if ((val & 3) == 0)
758 *insn |= val>>2;
759 else
760 cpu_error(26,4); /* offset has to be a multiple of 4 */
761 }
762 else
763 cpu_error(25,10,(long)val); /* immediate offset out of range */
764 break;
765 }
766
767 if (base!=NULL && db!=NULL) {
768 if (btype == BASE_OK) {
769 if (op.type==TUIM5 || op.type==TUI5I)
770 add_extnreloc_masked(&db->relocs,base,val,REL_ABS,
771 arm_be_mode?5:6,5,0,0x1f);
772 else if (op.type == TSWI8)
773 add_extnreloc_masked(&db->relocs,base,val,REL_ABS,
774 arm_be_mode?8:0,8,0,0xff);
775 else
776 cpu_error(6); /* constant integer expression required */
777 }
778 else
779 general_error(38); /* illegal relocation */
780 }
781 }
782
783 else if (op.type == TBR08) {
784 /* only write offset, relocs and optimizations are handled above */
785 if (val & 1)
786 cpu_error(8,(long)val); /* branch to unaligned address */
787 *insn |= (val>>1) & 0xff;
788 }
789
790 else if (op.type == TBR11) {
791 /* only write offset, relocs and optimizations are handled above */
792 if (val<-0x800 || val>0x7fe)
793 cpu_error(3,(long)val); /* branch offset is out of range */
794 if (val & 1)
795 cpu_error(8,(long)val); /* branch to unaligned address */
796 *insn |= (val>>1) & 0x7ff;
797 }
798
799 else if (op.type == TBRHL) {
800 /* split 23-bit offset over two instructions, ignoring bit 0 */
801 if (val<-0x400000 || val>0x3ffffe)
802 cpu_error(3,(long)val); /* branch offset is out of range */
803 if (val & 1)
804 cpu_error(8,(long)val); /* branch to unaligned address */
805 *insn++ |= (val>>12) & 0x7ff;
806 *insn = 0xf800 | ((val>>1) & 0x7ff);
807 }
808
809 else
810 ierror(0);
811 }
812 }
813
814 return isize;
815 }
816
817
818 #define ROTFAIL (0xffffff)
819
rotated_immediate(uint32_t val)820 static uint32_t rotated_immediate(uint32_t val)
821 /* check if a 32-bit value can be represented as 8-bit-rotated,
822 return ROTFAIL when impossible */
823 {
824 uint32_t i,a;
825
826 for (i=0; i<32; i+=2) {
827 if ((a = val<<i | val>>(32-i)) <= 0xff)
828 return (i<<7) | a;
829 }
830 return ROTFAIL;
831 }
832
833
negated_rot_immediate(uint32_t val,mnemonic * mnemo,uint32_t * insn)834 static int negated_rot_immediate(uint32_t val,mnemonic *mnemo,
835 uint32_t *insn)
836 /* check if negating the ALU-operation makes a valid 8-bit-rotated value,
837 insert it into the current instruction, when successful */
838 {
839 uint32_t neg = rotated_immediate(-val);
840 uint32_t inv = rotated_immediate(~val);
841 uint32_t op = (mnemo->ext.opcode & 0x01e00000) >> 21;
842
843 switch (op) {
844 /* AND <-> BIC */
845 case 0: op=14; val=inv; break;
846 case 14: op=0; val=inv; break;
847 /* ADD <-> SUB */
848 case 2: op=4; val=neg; break;
849 case 4: op=2; val=neg; break;
850 /* ADC <-> SBC */
851 case 5: op=6; val=inv; break;
852 case 6: op=5; val=inv; break;
853 /* CMP <-> CMN */
854 case 10: op=11; val=neg; break;
855 case 11: op=10; val=neg; break;
856 /* MOV <-> MVN */
857 case 13: op=15; val=inv; break;
858 case 15: op=13; val=inv; break;
859
860 default: return 0;
861 }
862
863 if (val == ROTFAIL)
864 return 0;
865
866 if (insn) {
867 *insn &= ~0x01e00000;
868 *insn |= (op<<21) | val;
869 }
870 return 1;
871 }
872
873
double_rot_immediate(uint32_t val,uint32_t * hi)874 static uint32_t double_rot_immediate(uint32_t val,uint32_t *hi)
875 /* check if a 32-bit value can be represented by combining two
876 8-bit rotated values, return ROTFAIL otherwise */
877 {
878 uint32_t i,a;
879
880 for (i=0; i<32; i+=2) {
881 if (((a = val<<i | val>>(32-i)) & 0xff) != 0) {
882 if (a & 0xff00) {
883 if (a & 0xffff0000)
884 continue;
885 *hi = ((i+24)<<7) | (a>>8);
886 }
887 else if (a & 0xff0000) {
888 if (a & 0xff000000)
889 continue;
890 *hi = ((i+16)<<7) | (a>>16);
891 }
892 else if (a & 0xff000000)
893 *hi = ((i+8)<<7) | (a>>24);
894 else
895 ierror(0);
896
897 return (i<<7) | (a&0xff);
898 }
899 }
900
901 return ROTFAIL;
902 }
903
904
calc_2nd_rot_opcode(uint32_t op)905 static uint32_t calc_2nd_rot_opcode(uint32_t op)
906 /* calculates ALU operation for second instruction */
907 {
908 if (op == 13)
909 op = 12; /* MOV + ORR */
910 else if (op == 15)
911 op = 1; /* MVN + EOR */
912 /* ADD and SUB stay the same */
913
914 return op << 21;
915 }
916
917
negated_double_rot_immediate(uint32_t val,uint32_t * insn)918 static int negated_double_rot_immediate(uint32_t val,uint32_t *insn)
919 /* check if negating the ALU-operation and/or a second ADD/SUB operation
920 makes a valid 8-bit-rotated value, insert it into the current
921 instruction, when successful */
922 {
923 uint32_t op = (*insn & 0x01e00000) >> 21;
924
925 if ((op==2 || op==4 || op==13 || op==15) && insn!=NULL) {
926 /* combined instructions only possible for ADD/SUB/MOV/MVN */
927 uint32_t lo,hi;
928
929 *(insn+1) = *insn & ~0x01ef0000;
930 *(insn+1) |= (*insn&0xf000) << 4; /* Rn = Rd of first instruction */
931
932 if ((lo = double_rot_immediate(val,&hi)) != ROTFAIL) {
933 *insn++ |= hi;
934 *insn |= calc_2nd_rot_opcode(op) | lo;
935 return 1;
936 }
937
938 /* @@@ try negated or inverted values */
939 }
940
941 return 0;
942 }
943
944
get_condcode(instruction * ip)945 static uint32_t get_condcode(instruction *ip)
946 /* returns condition (bit 31-28) from instruction's qualifiers */
947 {
948 const char *cc = condition_codes;
949 char *q;
950
951 if (q = ip->qualifiers[0]) {
952 uint32_t code = 0;
953
954 while (*cc) {
955 if (!strnicmp(q,cc,2) && *(q+2)=='\0')
956 break;
957 cc += 2;
958 code++;
959 }
960 if (*cc) { /* condition code in qualifier valid */
961 if (code == 16) /* hs -> cs */
962 code = 2;
963 else if (code==17 || code==18) /* lo/ul -> cc */
964 code = 3;
965
966 return code<<28;
967 }
968 }
969
970 return 0xe0000000; /* AL - always */
971 }
972
973
get_addrmode(instruction * ip)974 static int get_addrmode(instruction *ip)
975 /* return addressing mode from instruction's qualifiers */
976 {
977 char *q;
978
979 if ((q = ip->qualifiers[1]) == NULL)
980 q = ip->qualifiers[0];
981
982 if (q) {
983 const char **am = addrmode_strings;
984 int mode = AM_DA;
985
986 do {
987 if (!stricmp(*am,q))
988 break;
989 am++;
990 mode++;
991 }
992 while (*am);
993
994 if (*am != NULL)
995 return mode;
996 }
997
998 return AM_NONE;
999 }
1000
1001
eval_arm_operands(instruction * ip,section * sec,taddr pc,uint32_t * insn,dblock * db)1002 size_t eval_arm_operands(instruction *ip,section *sec,taddr pc,
1003 uint32_t *insn,dblock *db)
1004 /* evaluate expressions and try to optimize ARM instruction,
1005 return size of instruction */
1006 {
1007 operand op;
1008 mnemonic *mnemo = &mnemonics[ip->code];
1009 int am = get_addrmode(ip);
1010 int aa4ldst = 0;
1011 int opcnt = 0;
1012 size_t isize = 4;
1013 taddr chkreg = -1;
1014
1015 if (insn) {
1016 if (pc & 3)
1017 cpu_error(27); /* instruction at unaligned address */
1018
1019 *insn = mnemo->ext.opcode | get_condcode(ip);
1020
1021 if ((mnemo->ext.flags & SETCC)!=0 && am==AM_S)
1022 *insn |= 0x00100000; /* set-condition-codes flag */
1023
1024 if ((mnemo->ext.flags & SETPSR)!=0 && am==AM_P) {
1025 /* Rd = R15 for changing the PSR. Recommended for ARM2/250/3 only. */
1026 *insn |= 0x0000f000;
1027 if (cpu_type & ~AA2)
1028 cpu_error(28); /* deprecated on 32-bit architectures */
1029 }
1030
1031 if (!strcmp(mnemo->name,"ldr") || !strcmp(mnemo->name,"str")) {
1032 if (am==AM_T || am==AM_B || am==AM_BT || am==AM_TB) { /* std. ldr/str */
1033 if (am != AM_B) {
1034 *insn |= 0x00200000; /* W-flag for post-indexed mode */
1035 *insn &= ~0x01000000; /* force post-indexed */
1036 }
1037 if (am != AM_T)
1038 *insn |= 0x00400000; /* B-flag for byte-transfer */
1039 }
1040 else if (am==AM_SB || am==AM_H || am==AM_SH) { /* arch.4 ldr/str */
1041 if (cpu_type & AA4UP) {
1042 /* take P-, I- and L-bit from previous standard instruction */
1043 *insn = (*insn&0xf1100000)
1044 | (((*insn&0x02000000)^0x02000000)>>3) /* I-bit is flipped */
1045 | 0x90;
1046 if (am != AM_H) {
1047 if (*insn & 0x00100000) /* load */
1048 *insn |= 0x40; /* signed transfer */
1049 else
1050 cpu_error(18,addrmode_strings[am]); /* illegal addr. mode */
1051 }
1052 if (am != AM_SB)
1053 *insn |= 0x20; /* halfword-transfer */
1054 aa4ldst = 1;
1055 }
1056 else
1057 cpu_error(0); /* instruction not supported on selected arch. */
1058 }
1059 else if (am != AM_NONE)
1060 cpu_error(18,addrmode_strings[am]); /* illegal addr. mode */
1061 }
1062 else if (ip->code == OC_SWP) {
1063 if (am == AM_B)
1064 *insn |= 0x00400000; /* swap bytes */
1065 else if (am != AM_NONE)
1066 cpu_error(18,addrmode_strings[am]); /* illegal addr. mode */
1067 }
1068 }
1069 else { /* called by instruction_size() */
1070 if (am==AM_SB || am==AM_H || am==AM_SH)
1071 aa4ldst = 1;
1072 }
1073
1074 for (opcnt=0; opcnt<MAX_OPERANDS && ip->op[opcnt]!=NULL; opcnt++) {
1075 taddr val;
1076 symbol *base = NULL;
1077 int btype;
1078
1079 op = *(ip->op[opcnt]);
1080 if (!eval_expr(op.value,&val,sec,pc))
1081 btype = find_base(op.value,&base,sec,pc);
1082
1083 /* do optimizations first */
1084
1085 if (op.type==PCL12 || op.type==PCLRT ||
1086 op.type==PCLCP || op.type==BRA24) {
1087 /* PC-relative offsets (take prefetch into account: PC+8) */
1088 if (base!=NULL && btype==BASE_OK) {
1089 if (!is_pc_reloc(base,sec)) {
1090 /* no relocation required, can be resolved immediately */
1091 val -= pc + 8;
1092
1093 switch (op.type) {
1094 case BRA24:
1095 if (val>=0x2000000 || val<-0x2000000) {
1096 /* @@@ optimize? to what? */
1097 if (insn)
1098 cpu_error(3,(long)val); /* branch offset is out of range */
1099 }
1100 break;
1101
1102 case PCL12:
1103 if ((!aa4ldst && val<0x1000 && val>-0x1000) ||
1104 (aa4ldst && val<0x100 && val>-0x100)) {
1105 op.type = IMUD2; /* handle as normal #+/-Imm12 */
1106 if (val < 0)
1107 val = -val;
1108 else
1109 op.flags |= OFL_UP;
1110 base = NULL; /* no more checks */
1111 }
1112 else {
1113 if (opt_ldrpc &&
1114 ((!aa4ldst && val<0x100000 && val>-0x100000) ||
1115 (aa4ldst && val<0x10000 && val>-0x10000))) {
1116 /* ADD/SUB Rd,PC,#offset&0xff000 */
1117 /* LDR/STR Rd,[Rd,#offset&0xfff] */
1118 if (insn) {
1119 taddr v;
1120
1121 *(insn+1) = *insn;
1122 *insn &= 0xf0000000; /* clear all except cond. */
1123 if (val < 0) {
1124 v = -val;
1125 *insn |= 0x024f0a00; /* SUB */
1126 *(insn+1) &= ~0x00800000; /* clear U-bit */
1127 }
1128 else {
1129 v = val;
1130 *insn |= 0x028f0a00; /* ADD */
1131 *(insn+1) |= 0x00800000; /* set U-bit */
1132 }
1133 if (aa4ldst)
1134 *insn |= (*(insn+1)&0xf000) | ((v&0xff00)>>8);
1135 else
1136 *insn |= (*(insn+1)&0xf000) | ((v&0xff000)>>12);
1137 *(insn+1) &= ~0x000f0000; /* replace PC by Rd */
1138 *(insn+1) |= (*insn & 0xf000) << 4;
1139 insn++;
1140 }
1141 if (val < 0)
1142 val = -val;
1143 else
1144 op.flags |= OFL_UP;
1145 val = aa4ldst ? (val & 0xff) : (val & 0xfff);
1146 isize += 4;
1147 op.type = IMUD2;
1148 base = NULL; /* no more checks */
1149 }
1150 else {
1151 op.type = NOOP;
1152 if (insn)
1153 cpu_error(4,val); /* PC-relative ldr/str out of range */
1154 }
1155 }
1156 break;
1157
1158 case PCLCP:
1159 if (val<0x400 && val>-0x400) {
1160 op.type = IMCP2; /* handle as normal #+/-Imm10>>2 */
1161 if (val < 0)
1162 val = -val;
1163 else
1164 op.flags |= OFL_UP;
1165 base = NULL; /* no more checks */
1166 }
1167 else {
1168 /* no optimization, because we don't have a free register */
1169 op.type = NOOP;
1170 if (insn)
1171 cpu_error(4,val); /* PC-relative ldc/stc out of range */
1172 }
1173 break;
1174
1175 case PCLRT:
1176 op.type = NOOP; /* is handled here */
1177 if (val < 0) {
1178 /* use SUB instead of ADD */
1179 if (insn)
1180 *insn ^= 0x00c00000;
1181 val = -val;
1182 }
1183 if ((val = rotated_immediate(val)) != ROTFAIL) {
1184 if (insn)
1185 *insn |= val;
1186 }
1187 else if (opt_adr || am==AM_L) {
1188 /* ADRL or optimize ADR automatically to ADRL */
1189 uint32_t hi,lo;
1190
1191 isize += 4;
1192 if ((lo = double_rot_immediate(val,&hi)) != ROTFAIL) {
1193 /* ADD/SUB Rd,PC,#hi8rotated */
1194 /* ADD/SUB Rd,Rd,#lo8rotated */
1195 if (insn) {
1196 *(insn+1) = *insn & ~0xf0000;
1197 *(insn+1) |= (*insn&0xf000) << 4;
1198 *insn++ |= hi;
1199 *insn |= lo;
1200 }
1201 }
1202 else if (insn)
1203 cpu_error(5,(uint32_t)val); /* Cannot make rot.immed.*/
1204 }
1205 else if (insn)
1206 cpu_error(5,(uint32_t)val); /* Cannot make rot.immed.*/
1207 break;
1208
1209 default:
1210 ierror(0);
1211 }
1212 }
1213 else {
1214 /* symbol is in a different section or externally declared */
1215 switch (op.type) {
1216 case BRA24:
1217 val -= ARM_PREFETCH;
1218 if (db)
1219 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
1220 arm_be_mode?8:0,24,0,0x3fffffc);
1221 break;
1222 case PCL12:
1223 op.type = IMUD2;
1224 if (db) {
1225 if (val<0x1000 && val>-0x1000) {
1226 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
1227 arm_be_mode?20:0,12,0,0x1fff);
1228 base = NULL; /* don't add another REL_ABS below */
1229 }
1230 else
1231 cpu_error(22); /* operation not allowed on external symbols */
1232 }
1233 break;
1234 case PCLCP:
1235 if (db)
1236 cpu_error(22); /* operation not allowed on external symbols */
1237 break;
1238 case PCLRT:
1239 op.type = NOOP;
1240 if (am==AM_L && val==0) { /* ADRL */
1241 isize += 4; /* always reserve two ADD instructions */
1242 if (insn!=NULL && db!=NULL) {
1243 *(insn+1) = *insn & ~0xf0000;
1244 *(insn+1) |= (*insn&0xf000) << 4;
1245 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
1246 arm_be_mode?24:0,8,0,0xff00);
1247 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
1248 arm_be_mode?32+24:32+0,8,0,0xff);
1249 }
1250 }
1251 else if (val == 0) { /* ADR */
1252 if (db)
1253 add_extnreloc_masked(&db->relocs,base,val,REL_PC,
1254 arm_be_mode?24:0,8,0,0xff);
1255 }
1256 else if (db)
1257 cpu_error(22); /* operation not allowed on external symbols */
1258 break;
1259 default:
1260 ierror(0);
1261 }
1262 }
1263 }
1264 else if (insn) {
1265 op.type = NOOP;
1266 cpu_error(2); /* label from current section required */
1267 }
1268 }
1269
1270 else if (op.type == IMROT) {
1271 op.type = NOOP; /* is handled here */
1272
1273 if (base == NULL) {
1274 uint32_t rotval;
1275
1276 if ((rotval = rotated_immediate(val)) != ROTFAIL) {
1277 if (insn)
1278 *insn |= rotval;
1279 }
1280 else if (!negated_rot_immediate(val,mnemo,insn)) {
1281 /* rotation, negation and inversion failed - try a 2nd operation */
1282 isize += 4;
1283 if (insn) {
1284 if (!negated_double_rot_immediate(val,insn))
1285 cpu_error(7,(uint32_t)val); /* const not suitable */
1286 }
1287 }
1288 }
1289 else if (insn)
1290 cpu_error(6); /* constant integer expression required */
1291 }
1292
1293 /* optimizations should be finished at this stage -
1294 inserts operands into the opcode now: */
1295
1296 if (insn) {
1297
1298 if (REGOPER(op.type)) {
1299 /* insert register operand */
1300 if (base!=NULL || val<0 || val>15)
1301 cpu_error(9); /* not a valid ARM register */
1302
1303 if (REG19OPER(op.type))
1304 *insn |= val<<16;
1305 else if (REG15OPER(op.type))
1306 *insn |= val<<12;
1307 else if (REG11OPER(op.type))
1308 *insn |= val<<8;
1309 else if (REG03OPER(op.type))
1310 *insn |= val;
1311
1312 if (op.type==R3UD1 && !(*insn&0x01000000))
1313 cpu_error(21); /* post-indexed addressing mode expected */
1314 if (op.flags & OFL_WBACK)
1315 *insn |= 0x00200000;
1316 if (op.flags & OFL_UP)
1317 *insn |= 0x00800000;
1318
1319 /* some more checks: */
1320 if ((mnemo->ext.flags&NOPC) && val==15)
1321 cpu_error(10); /* PC (r15) not allowed in this mode */
1322 if ((mnemo->ext.flags&NOPCR03) && val==15 && REG03OPER(op.type))
1323 cpu_error(11); /* PC (r15) not allowed for offset register Rm */
1324 if ((mnemo->ext.flags&NOPC) && val==15 && (op.flags&OFL_WBACK))
1325 cpu_error(12); /* PC (r15) not allowed with write-back */
1326
1327 /* check for illegal double register specifications */
1328 if (((mnemo->ext.flags&DIFR03) && REG03OPER(op.type)) ||
1329 ((mnemo->ext.flags&DIFR11) && REG11OPER(op.type)) ||
1330 ((mnemo->ext.flags&DIFR15) && REG15OPER(op.type)) ||
1331 ((mnemo->ext.flags&DIFR19) && REG19OPER(op.type))) {
1332 if (chkreg != -1) {
1333 if (val == chkreg)
1334 cpu_error(13,(long)val); /* register was used multiple times */
1335 }
1336 else
1337 chkreg = val;
1338 }
1339 }
1340
1341 else if (op.type == BRA24) {
1342 /* only write offset, relocs and optimizations are handled above */
1343 if (val & 3)
1344 cpu_error(8,(long)val); /* branch to unaligned address */
1345 *insn |= (val>>2) & 0xffffff;
1346 }
1347
1348 else if (op.type==IMUD1 || op.type==IMUD2) {
1349 if (aa4ldst) {
1350 /* insert splitted 8-bit immediate for signed/halfword ldr/str */
1351 if (val>=0 && val<=0xff) {
1352 *insn |= ((val&0xf0)<<4) | (val&0x0f);
1353 }
1354 else
1355 cpu_error(20,8,(long)val); /* immediate offset out of range */
1356 }
1357 else {
1358 /* insert immediate 12-bit with up/down flag */
1359 if (val>=0 && val<=0xfff) {
1360 *insn |= val;
1361 }
1362 else
1363 cpu_error(20,12,(long)val); /* immediate offset out of range */
1364 }
1365
1366 if (op.type==IMUD1 && !(*insn&0x01000000))
1367 cpu_error(21); /* post-indexed addressing mode exptected */
1368 if (op.flags & OFL_WBACK)
1369 *insn |= 0x00200000; /* set write-back flag */
1370 if (op.flags & OFL_UP)
1371 *insn |= 0x00800000; /* set UP-flag */
1372
1373 if (base) {
1374 if (btype == BASE_OK) {
1375 if (EXTREF(base)) {
1376 if (!aa4ldst) {
1377 /* @@@ does this make any sense? */
1378 *insn |= 0x00800000; /* only UP */
1379 add_extnreloc_masked(&db->relocs,base,val,REL_ABS,
1380 arm_be_mode?20:0,12,0,0xfff);
1381 }
1382 else
1383 cpu_error(22); /* operation not allowed on external symbols */
1384 }
1385 else
1386 cpu_error(6); /* constant integer expression required */
1387 }
1388 else
1389 general_error(38); /* illegal relocation */
1390 }
1391 }
1392
1393 else if (op.type==IMCP1 || op.type==IMCP2) {
1394 /* insert immediate 10-bit shifted left by 2, with up/down flag */
1395 if (val>=0 && val<=0x3ff) {
1396 if ((val & 3) == 0)
1397 *insn |= val>>2;
1398 else
1399 cpu_error(23); /* ldc/stc offset has to be a multiple of 4 */
1400 }
1401 else
1402 cpu_error(20,10,(long)val); /* immediate offset out of range */
1403
1404 if (op.flags & OFL_WBACK)
1405 *insn |= 0x00200000; /* set write-back flag */
1406 if (op.flags & OFL_UP)
1407 *insn |= 0x00800000; /* set UP-flag */
1408
1409 if (base)
1410 cpu_error(6); /* constant integer expression required */
1411 }
1412
1413 else if (op.type == SWI24) {
1414 /* insert 24-bit immediate (SWI instruction) */
1415 if (val>=0 && val<0x1000000) {
1416 *insn |= val;
1417 if (base!=NULL && db!=NULL)
1418 add_extnreloc_masked(&db->relocs,base,val,REL_ABS,
1419 arm_be_mode?8:0,24,0,0xffffff);
1420 }
1421 else
1422 cpu_error(16); /* 24-bit unsigned immediate expected */
1423 if (base)
1424 cpu_error(6); /* constant integer expression required */
1425 }
1426
1427 else if (op.type == IROTV) {
1428 /* insert 4-bit rotate constant (even value, shifted right) */
1429 if (val>=0 && val<=30 && (val&1)==0)
1430 *insn |= val << 7;
1431 else
1432 cpu_error(29,(long)val); /* must be even number between 0 and 30 */
1433 if (base)
1434 cpu_error(6); /* constant integer expression required */
1435 }
1436
1437 else if (op.type == IMMD8) {
1438 /* unsigned 8-bit immediate constant, used together with IROTV */
1439 if (val>=0 && val<0x100 && base==NULL)
1440 *insn |= val;
1441 else
1442 cpu_error(30,8,(long)val); /* 8-bit unsigned constant required */
1443 }
1444
1445 else if (SHIFTOPER(op.type)) {
1446 /* insert a register- or immediate shift */
1447 int sh_op = op.flags & OFL_SHIFTOP;
1448
1449 if (aa4ldst)
1450 cpu_error(19); /* signed/halfword ldr/str doesn't support shifts */
1451 if (op.type==SHIM1 && !(*insn&0x01000000))
1452 cpu_error(21); /* post-indexed addressing mode exptected */
1453
1454 if (op.flags & OFL_IMMEDSHIFT) {
1455 if (sh_op==1 || sh_op==2) { /* lsr/asr permit shift-count #32 */
1456 if (val == 32)
1457 val = 0;
1458 }
1459 if (base==NULL && val>=0 && val<32) {
1460 *insn |= (val<<7) | ((op.flags&OFL_SHIFTOP)<<5);
1461 if (op.flags & OFL_WBACK)
1462 *insn |= 0x00200000;
1463 }
1464 else
1465 cpu_error(14,(long)val); /* illegal immediate shift count */
1466 }
1467 else { /* shift count in register */
1468 if (base==NULL && val>=0 && val<16) {
1469 *insn |= (val<<8) | ((op.flags&OFL_SHIFTOP)<<5) | 0x10;
1470 }
1471 else
1472 cpu_error(15); /* not a valid shift register */
1473 }
1474 }
1475
1476 else if (CPOPCODE(op.type)) {
1477 /* insert coprocessor operation/type */
1478 if (base == NULL) {
1479 switch (op.type) {
1480 case CPOP3:
1481 if (val>=0 && val<8)
1482 *insn |= val<<21;
1483 else
1484 cpu_error(24,val); /* illegal coprocessor operation */
1485 break;
1486 case CPOP4:
1487 if (val>=0 && val<16)
1488 *insn |= val<<20;
1489 else
1490 cpu_error(24,val); /* illegal coprocessor operation */
1491 break;
1492 case CPTYP:
1493 if (val>=0 && val<8)
1494 *insn |= val<<5;
1495 else
1496 cpu_error(24,val); /* illegal coprocessor operation */
1497 break;
1498 default: ierror(0);
1499 }
1500 }
1501 else
1502 cpu_error(24,val); /* illegal coprocessor operation */
1503 }
1504
1505 else if (op.type==CSPSR || op.type==PSR_F) {
1506 /* insert PSR type - no checks needed */
1507 *insn |= val<<16;
1508 if (op.flags & OFL_SPSR)
1509 *insn |= 0x00400000;
1510 }
1511
1512 else if (op.type == RLIST) {
1513 /* insert register-list field */
1514 if (am<AM_DA || am>AM_ED)
1515 cpu_error(18,addrmode_strings[am]); /* illegal addr. mode */
1516 if (am>=AM_FA && am<=AM_ED) {
1517 /* fix stack-addressing mode */
1518 if (!(mnemo->ext.opcode & 0x00100000))
1519 am ^= 3; /* invert P/U modes for store operations */
1520 }
1521 *insn |= ((am&3)<<23) | val;
1522 if (op.flags & OFL_FORCE)
1523 *insn |= 0x00400000;
1524 }
1525
1526 else if (op.type != NOOP)
1527 ierror(0);
1528 }
1529 }
1530
1531 return isize;
1532 }
1533
1534
instruction_size(instruction * ip,section * sec,taddr pc)1535 size_t instruction_size(instruction *ip,section *sec,taddr pc)
1536 /* Calculate the size of the current instruction; must be identical
1537 to the data created by eval_instruction. */
1538 {
1539 if (mnemonics[ip->code].ext.flags & THUMB)
1540 return eval_thumb_operands(ip,sec,pc,NULL,NULL);
1541
1542 /* ARM mode */
1543 return eval_arm_operands(ip,sec,pc,NULL,NULL);
1544 }
1545
1546
eval_instruction(instruction * ip,section * sec,taddr pc)1547 dblock *eval_instruction(instruction *ip,section *sec,taddr pc)
1548 /* Convert an instruction into a DATA atom including relocations,
1549 if necessary. */
1550 {
1551 dblock *db = new_dblock();
1552 int inst_type;
1553
1554 if (sec != last_section) {
1555 last_section = sec;
1556 last_data_type = -1;
1557 }
1558 inst_type = (mnemonics[ip->code].ext.flags & THUMB) ? TYPE_THUMB : TYPE_ARM;
1559
1560 if (inst_type == TYPE_THUMB) {
1561 uint16_t insn[2];
1562
1563 if (db->size = eval_thumb_operands(ip,sec,pc,insn,db)) {
1564 unsigned char *d = db->data = mymalloc(db->size);
1565 int i;
1566
1567 for (i=0; i<db->size/2; i++)
1568 d = setval(arm_be_mode,d,2,insn[i]);
1569 }
1570 }
1571
1572 else { /* ARM mode */
1573 uint32_t insn[2];
1574
1575 if (db->size = eval_arm_operands(ip,sec,pc,insn,db)) {
1576 unsigned char *d = db->data = mymalloc(db->size);
1577 int i;
1578
1579 for (i=0; i<db->size/4; i++)
1580 d = setval(arm_be_mode,d,4,insn[i]);
1581 }
1582 }
1583
1584 if (inst_type != last_data_type)
1585 create_mapping_symbol(inst_type,sec,pc);
1586
1587 return db;
1588 }
1589
1590
eval_data(operand * op,size_t bitsize,section * sec,taddr pc)1591 dblock *eval_data(operand *op,size_t bitsize,section *sec,taddr pc)
1592 /* Create a dblock (with relocs, if necessary) for size bits of data. */
1593 {
1594 dblock *db = new_dblock();
1595 taddr val;
1596
1597 if (sec != last_section) {
1598 last_section = sec;
1599 last_data_type = -1;
1600 }
1601
1602 if ((bitsize & 7) || bitsize > 64)
1603 cpu_error(17,bitsize); /* data size not supported */
1604
1605 if (op->type!=DATA_OP && op->type!=DATA64_OP)
1606 ierror(0);
1607
1608 db->size = bitsize >> 3;
1609 db->data = mymalloc(db->size);
1610
1611 if (op->type == DATA64_OP) {
1612 thuge hval;
1613
1614 if (!eval_expr_huge(op->value,&hval))
1615 general_error(59); /* cannot evaluate huge integer */
1616 huge_to_mem(arm_be_mode,db->data,db->size,hval);
1617 }
1618 else {
1619 if (!eval_expr(op->value,&val,sec,pc)) {
1620 symbol *base;
1621 int btype;
1622
1623 btype = find_base(op->value,&base,sec,pc);
1624 if (base)
1625 add_extnreloc(&db->relocs,base,val,
1626 btype==BASE_PCREL?REL_PC:REL_ABS,0,bitsize,0);
1627 else if (btype != BASE_NONE)
1628 general_error(38); /* illegal relocation */
1629 }
1630 switch (db->size) {
1631 case 1:
1632 db->data[0] = val & 0xff;
1633 break;
1634 case 2:
1635 case 4:
1636 setval(arm_be_mode,db->data,db->size,val);
1637 break;
1638 default:
1639 ierror(0);
1640 break;
1641 }
1642 }
1643
1644 if (last_data_type != TYPE_DATA)
1645 create_mapping_symbol(TYPE_DATA,sec,pc);
1646
1647 return db;
1648 }
1649
1650
init_cpu()1651 int init_cpu()
1652 {
1653 char r[4];
1654 int i;
1655
1656 for (i=0; i<mnemonic_cnt; i++) {
1657 if (!strcmp(mnemonics[i].name,"swp"))
1658 OC_SWP = i;
1659 else if (!strcmp(mnemonics[i].name,"nop"))
1660 OC_NOP = i;
1661 }
1662
1663 if (!strcmp(output_format,"elf"))
1664 elfoutput = 1;
1665
1666 /* define register symbols */
1667 for (i=0; i<16; i++) {
1668 sprintf(r,"r%d",i);
1669 new_regsym(0,1,r,0,0,i);
1670 sprintf(r,"c%d",i);
1671 new_regsym(0,1,r,0,0,i);
1672 sprintf(r,"p%d",i);
1673 new_regsym(0,1,r,0,0,i);
1674 }
1675 /* ATPCS synonyms */
1676 for (i=0; i<8; i++) {
1677 if (i < 4) {
1678 sprintf(r,"a%d",i+1);
1679 new_regsym(0,1,r,0,0,i);
1680 }
1681 sprintf(r,"v%d",i+1);
1682 new_regsym(0,1,r,0,0,i+4);
1683 }
1684 /* well known aliases */
1685 new_regsym(0,1,"wr",0,0,7);
1686 new_regsym(0,1,"sb",0,0,9);
1687 new_regsym(0,1,"sl",0,0,10);
1688 new_regsym(0,1,"fp",0,0,11);
1689 new_regsym(0,1,"ip",0,0,12);
1690 new_regsym(0,1,"sp",0,0,13);
1691 new_regsym(0,1,"lr",0,0,14);
1692 new_regsym(0,1,"pc",0,0,15);
1693
1694 return 1;
1695 }
1696
1697
cpu_args(char * p)1698 int cpu_args(char *p)
1699 {
1700 if (!strncmp(p,"-m",2)) {
1701 p += 2;
1702 if (!strcmp(p,"2")) cpu_type = ARM2;
1703 else if (!strcmp(p,"250")) cpu_type = ARM250;
1704 else if (!strcmp(p,"3")) cpu_type = ARM3;
1705 else if (!strcmp(p,"6")) cpu_type = ARM6;
1706 else if (!strcmp(p,"600")) cpu_type = ARM600;
1707 else if (!strcmp(p,"610")) cpu_type = ARM610;
1708 else if (!strcmp(p,"7")) cpu_type = ARM7;
1709 else if (!strcmp(p,"710")) cpu_type = ARM710;
1710 else if (!strcmp(p,"7500")) cpu_type = ARM7500;
1711 else if (!strcmp(p,"7d")) cpu_type = ARM7d;
1712 else if (!strcmp(p,"7di")) cpu_type = ARM7di;
1713 else if (!strcmp(p,"7dm")) cpu_type = ARM7dm;
1714 else if (!strcmp(p,"7dmi")) cpu_type = ARM7dmi;
1715 else if (!strcmp(p,"7tdmi")) cpu_type = ARM7tdmi;
1716 else if (!strcmp(p,"8")) cpu_type = ARM8;
1717 else if (!strcmp(p,"810")) cpu_type = ARM810;
1718 else if (!strcmp(p,"9")) cpu_type = ARM9;
1719 else if (!strcmp(p,"920")) cpu_type = ARM920;
1720 else if (!strcmp(p,"920t")) cpu_type = ARM920t;
1721 else if (!strcmp(p,"9tdmi")) cpu_type = ARM9tdmi;
1722 else if (!strcmp(p,"sa1")) cpu_type = SA1;
1723 else if (!strcmp(p,"strongarm")) cpu_type = STRONGARM;
1724 else if (!strcmp(p,"strongarm110")) cpu_type = STRONGARM110;
1725 else if (!strcmp(p,"strongarm1100")) cpu_type = STRONGARM1100;
1726 else return 0;
1727 }
1728 else if (!strncmp(p,"-a",2)) {
1729 p += 2;
1730 if (!strcmp(p,"2")) cpu_type = AA2;
1731 else if (!strcmp(p,"3")) cpu_type = AA3;
1732 else if (!strcmp(p,"3m")) cpu_type = AA3M;
1733 else if (!strcmp(p,"4")) cpu_type = AA4;
1734 else if (!strcmp(p,"4t")) cpu_type = AA4T;
1735 else return 0;
1736 }
1737 else if (!strcmp(p,"-little"))
1738 arm_be_mode = 0;
1739 else if (!strcmp(p,"-big"))
1740 arm_be_mode = 1;
1741 else if (!strcmp(p,"-thumb"))
1742 thumb_mode = 1;
1743 else if (!strcmp(p,"-opt-ldrpc"))
1744 opt_ldrpc = 1;
1745 else if (!strcmp(p,"-opt-adr"))
1746 opt_adr = 1;
1747
1748 return 1;
1749 }
1750