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