tc-moxie.c revision 1.1.1.1 1 /* tc-moxie.c -- Assemble code for moxie
2 Copyright 2009
3 Free Software Foundation, Inc.
4
5 This file is part of GAS, the GNU Assembler.
6
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to
19 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22 /* Contributed by Anthony Green <green (at) moxielogic.com>. */
23
24 #include "as.h"
25 #include "safe-ctype.h"
26 #include "opcode/moxie.h"
27 #include "elf/moxie.h"
28
29 extern const moxie_opc_info_t moxie_opc_info[128];
30
31 const char comment_chars[] = "#";
32 const char line_separator_chars[] = ";";
33 const char line_comment_chars[] = "#";
34
35 static int pending_reloc;
36 static struct hash_control *opcode_hash_control;
37
38 const pseudo_typeS md_pseudo_table[] =
39 {
40 {0, 0, 0}
41 };
42
43 const char FLT_CHARS[] = "rRsSfFdDxXpP";
44 const char EXP_CHARS[] = "eE";
45
46 static int md_chars_to_number (char *val, int n);
47
48 void
49 md_operand (expressionS *op __attribute__((unused)))
50 {
51 /* Empty for now. */
52 }
53
54 /* This function is called once, at assembler startup time. It sets
55 up the hash table with all the opcodes in it, and also initializes
56 some aliases for compatibility with other assemblers. */
57
58 void
59 md_begin (void)
60 {
61 int count;
62 const moxie_opc_info_t *opcode;
63 opcode_hash_control = hash_new ();
64
65 /* Insert names into hash table. */
66 for (count = 0, opcode = moxie_form1_opc_info; count++ < 64; opcode++)
67 hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
68
69 for (count = 0, opcode = moxie_form2_opc_info; count++ < 4; opcode++)
70 hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
71
72 for (count = 0, opcode = moxie_form3_opc_info; count++ < 10; opcode++)
73 hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
74
75 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
76 }
77
78 /* Parse an expression and then restore the input line pointer. */
79
80 static char *
81 parse_exp_save_ilp (char *s, expressionS *op)
82 {
83 char *save = input_line_pointer;
84
85 input_line_pointer = s;
86 expression (op);
87 s = input_line_pointer;
88 input_line_pointer = save;
89 return s;
90 }
91
92 static int
93 parse_register_operand (char **ptr)
94 {
95 int reg;
96 char *s = *ptr;
97
98 if (*s != '$')
99 {
100 as_bad (_("expecting register"));
101 ignore_rest_of_line ();
102 return -1;
103 }
104 if (s[1] == 'f' && s[2] == 'p')
105 {
106 *ptr += 3;
107 return 0;
108 }
109 if (s[1] == 's' && s[2] == 'p')
110 {
111 *ptr += 3;
112 return 1;
113 }
114 if (s[1] == 'r')
115 {
116 reg = s[2] - '0';
117 if ((reg < 0) || (reg > 9))
118 {
119 as_bad (_("illegal register number"));
120 ignore_rest_of_line ();
121 return -1;
122 }
123 if (reg == 1)
124 {
125 int r2 = s[3] - '0';
126 if ((r2 >= 0) && (r2 <= 3))
127 {
128 reg = 10 + r2;
129 *ptr += 1;
130 }
131 }
132 }
133 else
134 {
135 as_bad (_("illegal register number"));
136 ignore_rest_of_line ();
137 return -1;
138 }
139
140 *ptr += 3;
141
142 return reg + 2;
143 }
144
145 /* This is the guts of the machine-dependent assembler. STR points to
146 a machine dependent instruction. This function is supposed to emit
147 the frags/bytes it assembles to. */
148
149 void
150 md_assemble (char *str)
151 {
152 char *op_start;
153 char *op_end;
154
155 moxie_opc_info_t *opcode;
156 char *p;
157 char pend;
158
159 unsigned short iword = 0;
160
161 int nlen = 0;
162
163 /* Drop leading whitespace. */
164 while (*str == ' ')
165 str++;
166
167 /* Find the op code end. */
168 op_start = str;
169 for (op_end = str;
170 *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
171 op_end++)
172 nlen++;
173
174 pend = *op_end;
175 *op_end = 0;
176
177 if (nlen == 0)
178 as_bad (_("can't find opcode "));
179 opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start);
180 *op_end = pend;
181
182 if (opcode == NULL)
183 {
184 as_bad (_("unknown opcode %s"), op_start);
185 return;
186 }
187
188 p = frag_more (2);
189
190 switch (opcode->itype)
191 {
192 case MOXIE_F2_A8V:
193 iword = (1<<15) | (opcode->opcode << 12);
194 while (ISSPACE (*op_end))
195 op_end++;
196 {
197 expressionS arg;
198 int reg;
199 reg = parse_register_operand (&op_end);
200 iword += (reg << 8);
201 if (*op_end != ',')
202 as_warn (_("expecting comma delimited register operands"));
203 op_end++;
204 op_end = parse_exp_save_ilp (op_end, &arg);
205 fix_new_exp (frag_now,
206 ((p+1) - frag_now->fr_literal),
207 1,
208 &arg,
209 0,
210 BFD_RELOC_8);
211 }
212 break;
213 case MOXIE_F1_AB:
214 iword = opcode->opcode << 8;
215 while (ISSPACE (*op_end))
216 op_end++;
217 {
218 int dest, src;
219 dest = parse_register_operand (&op_end);
220 if (*op_end != ',')
221 as_warn (_("expecting comma delimited register operands"));
222 op_end++;
223 src = parse_register_operand (&op_end);
224 iword += (dest << 4) + src;
225 while (ISSPACE (*op_end))
226 op_end++;
227 if (*op_end != 0)
228 as_warn (_("extra stuff on line ignored"));
229 }
230 break;
231 case MOXIE_F1_A4:
232 iword = opcode->opcode << 8;
233 while (ISSPACE (*op_end))
234 op_end++;
235 {
236 expressionS arg;
237 char *where;
238 int regnum;
239
240 regnum = parse_register_operand (&op_end);
241 while (ISSPACE (*op_end))
242 op_end++;
243
244 iword += (regnum << 4);
245
246 if (*op_end != ',')
247 {
248 as_bad (_("expecting comma delimited operands"));
249 ignore_rest_of_line ();
250 return;
251 }
252 op_end++;
253
254 op_end = parse_exp_save_ilp (op_end, &arg);
255 where = frag_more (4);
256 fix_new_exp (frag_now,
257 (where - frag_now->fr_literal),
258 4,
259 &arg,
260 0,
261 BFD_RELOC_32);
262 }
263 break;
264 case MOXIE_F1_M:
265 case MOXIE_F1_4:
266 iword = opcode->opcode << 8;
267 while (ISSPACE (*op_end))
268 op_end++;
269 {
270 expressionS arg;
271 char *where;
272
273 op_end = parse_exp_save_ilp (op_end, &arg);
274 where = frag_more (4);
275 fix_new_exp (frag_now,
276 (where - frag_now->fr_literal),
277 4,
278 &arg,
279 0,
280 BFD_RELOC_32);
281 }
282 break;
283 case MOXIE_F1_NARG:
284 iword = opcode->opcode << 8;
285 while (ISSPACE (*op_end))
286 op_end++;
287 if (*op_end != 0)
288 as_warn (_("extra stuff on line ignored"));
289 break;
290 case MOXIE_F1_A:
291 iword = opcode->opcode << 8;
292 while (ISSPACE (*op_end))
293 op_end++;
294 {
295 int reg;
296 reg = parse_register_operand (&op_end);
297 while (ISSPACE (*op_end))
298 op_end++;
299 if (*op_end != 0)
300 as_warn (_("extra stuff on line ignored"));
301 iword += (reg << 4);
302 }
303 break;
304 case MOXIE_F1_ABi:
305 iword = opcode->opcode << 8;
306 while (ISSPACE (*op_end))
307 op_end++;
308 {
309 int a, b;
310 a = parse_register_operand (&op_end);
311 if (*op_end != ',')
312 as_warn (_("expecting comma delimited register operands"));
313 op_end++;
314 if (*op_end != '(')
315 {
316 as_bad (_("expecting indirect register `($rA)'"));
317 ignore_rest_of_line ();
318 return;
319 }
320 op_end++;
321 b = parse_register_operand (&op_end);
322 if (*op_end != ')')
323 {
324 as_bad (_("missing closing parenthesis"));
325 ignore_rest_of_line ();
326 return;
327 }
328 op_end++;
329 iword += (a << 4) + b;
330 while (ISSPACE (*op_end))
331 op_end++;
332 if (*op_end != 0)
333 as_warn (_("extra stuff on line ignored"));
334 }
335 break;
336 case MOXIE_F1_AiB:
337 iword = opcode->opcode << 8;
338 while (ISSPACE (*op_end))
339 op_end++;
340 {
341 int a, b;
342 if (*op_end != '(')
343 {
344 as_bad (_("expecting indirect register `($rA)'"));
345 ignore_rest_of_line ();
346 return;
347 }
348 op_end++;
349 a = parse_register_operand (&op_end);
350 if (*op_end != ')')
351 {
352 as_bad (_("missing closing parenthesis"));
353 ignore_rest_of_line ();
354 return;
355 }
356 op_end++;
357 if (*op_end != ',')
358 as_warn (_("expecting comma delimited register operands"));
359 op_end++;
360 b = parse_register_operand (&op_end);
361 iword += (a << 4) + b;
362 while (ISSPACE (*op_end))
363 op_end++;
364 if (*op_end != 0)
365 as_warn (_("extra stuff on line ignored"));
366 }
367 break;
368 case MOXIE_F1_4A:
369 iword = opcode->opcode << 8;
370 while (ISSPACE (*op_end))
371 op_end++;
372 {
373 expressionS arg;
374 char *where;
375 int a;
376
377 op_end = parse_exp_save_ilp (op_end, &arg);
378 where = frag_more (4);
379 fix_new_exp (frag_now,
380 (where - frag_now->fr_literal),
381 4,
382 &arg,
383 0,
384 BFD_RELOC_32);
385
386 if (*op_end != ',')
387 {
388 as_bad (_("expecting comma delimited operands"));
389 ignore_rest_of_line ();
390 return;
391 }
392 op_end++;
393
394 a = parse_register_operand (&op_end);
395 while (ISSPACE (*op_end))
396 op_end++;
397 if (*op_end != 0)
398 as_warn (_("extra stuff on line ignored"));
399
400 iword += (a << 4);
401 }
402 break;
403 case MOXIE_F1_ABi4:
404 iword = opcode->opcode << 8;
405 while (ISSPACE (*op_end))
406 op_end++;
407 {
408 expressionS arg;
409 char *offset;
410 int a, b;
411
412 a = parse_register_operand (&op_end);
413 while (ISSPACE (*op_end))
414 op_end++;
415
416 if (*op_end != ',')
417 {
418 as_bad (_("expecting comma delimited operands"));
419 ignore_rest_of_line ();
420 return;
421 }
422 op_end++;
423
424 op_end = parse_exp_save_ilp (op_end, &arg);
425 offset = frag_more (4);
426 fix_new_exp (frag_now,
427 (offset - frag_now->fr_literal),
428 4,
429 &arg,
430 0,
431 BFD_RELOC_32);
432
433 if (*op_end != '(')
434 {
435 as_bad (_("expecting indirect register `($rX)'"));
436 ignore_rest_of_line ();
437 return;
438 }
439 op_end++;
440 b = parse_register_operand (&op_end);
441 if (*op_end != ')')
442 {
443 as_bad (_("missing closing parenthesis"));
444 ignore_rest_of_line ();
445 return;
446 }
447 op_end++;
448
449 while (ISSPACE (*op_end))
450 op_end++;
451 if (*op_end != 0)
452 as_warn (_("extra stuff on line ignored"));
453
454 iword += (a << 4) + b;
455 }
456 break;
457 case MOXIE_F1_AiB4:
458 iword = opcode->opcode << 8;
459 while (ISSPACE (*op_end))
460 op_end++;
461 {
462 expressionS arg;
463 char *offset;
464 int a, b;
465
466 op_end = parse_exp_save_ilp (op_end, &arg);
467 offset = frag_more (4);
468 fix_new_exp (frag_now,
469 (offset - frag_now->fr_literal),
470 4,
471 &arg,
472 0,
473 BFD_RELOC_32);
474
475 if (*op_end != '(')
476 {
477 as_bad (_("expecting indirect register `($rX)'"));
478 ignore_rest_of_line ();
479 return;
480 }
481 op_end++;
482 a = parse_register_operand (&op_end);
483 if (*op_end != ')')
484 {
485 as_bad (_("missing closing parenthesis"));
486 ignore_rest_of_line ();
487 return;
488 }
489 op_end++;
490
491 if (*op_end != ',')
492 {
493 as_bad (_("expecting comma delimited operands"));
494 ignore_rest_of_line ();
495 return;
496 }
497 op_end++;
498
499 b = parse_register_operand (&op_end);
500 while (ISSPACE (*op_end))
501 op_end++;
502
503 while (ISSPACE (*op_end))
504 op_end++;
505 if (*op_end != 0)
506 as_warn (_("extra stuff on line ignored"));
507
508 iword += (a << 4) + b;
509 }
510 break;
511 case MOXIE_F2_NARG:
512 iword = opcode->opcode << 12;
513 while (ISSPACE (*op_end))
514 op_end++;
515 if (*op_end != 0)
516 as_warn (_("extra stuff on line ignored"));
517 break;
518 case MOXIE_F3_PCREL:
519 iword = (3<<14) | (opcode->opcode << 10);
520 while (ISSPACE (*op_end))
521 op_end++;
522 {
523 expressionS arg;
524
525 op_end = parse_exp_save_ilp (op_end, &arg);
526 fix_new_exp (frag_now,
527 (p - frag_now->fr_literal),
528 2,
529 &arg,
530 TRUE,
531 BFD_RELOC_MOXIE_10_PCREL);
532 }
533 break;
534 default:
535 abort ();
536 }
537
538 md_number_to_chars (p, iword, 2);
539
540 while (ISSPACE (*op_end))
541 op_end++;
542
543 if (*op_end != 0)
544 as_warn (_("extra stuff on line ignored"));
545
546 if (pending_reloc)
547 as_bad (_("Something forgot to clean up\n"));
548 }
549
550 /* Turn a string in input_line_pointer into a floating point constant
551 of type type, and store the appropriate bytes in *LITP. The number
552 of LITTLENUMS emitted is stored in *SIZEP . An error message is
553 returned, or NULL on OK. */
554
555 char *
556 md_atof (int type, char *litP, int *sizeP)
557 {
558 int prec;
559 LITTLENUM_TYPE words[4];
560 char *t;
561 int i;
562
563 switch (type)
564 {
565 case 'f':
566 prec = 2;
567 break;
568
569 case 'd':
570 prec = 4;
571 break;
572
573 default:
574 *sizeP = 0;
575 return _("bad call to md_atof");
576 }
577
578 t = atof_ieee (input_line_pointer, type, words);
579 if (t)
580 input_line_pointer = t;
581
582 *sizeP = prec * 2;
583
584 for (i = prec - 1; i >= 0; i--)
585 {
586 md_number_to_chars (litP, (valueT) words[i], 2);
587 litP += 2;
588 }
589
590 return NULL;
591 }
592
593 const char *md_shortopts = "";
595
596 struct option md_longopts[] =
597 {
598 {NULL, no_argument, NULL, 0}
599 };
600 size_t md_longopts_size = sizeof (md_longopts);
601
602 /* We have no target specific options yet, so these next
603 two functions are empty. */
604 int
605 md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
606 {
607 return 0;
608 }
609
610 void
611 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
612 {
613 }
614
615 /* Apply a fixup to the object file. */
616
617 void
618 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
619 valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
620 {
621 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
622 long val = *valP;
623 long newval;
624 long max, min;
625
626 max = min = 0;
627 switch (fixP->fx_r_type)
628 {
629 case BFD_RELOC_32:
630 *buf++ = val >> 24;
631 *buf++ = val >> 16;
632 *buf++ = val >> 8;
633 *buf++ = val >> 0;
634 break;
635
636 case BFD_RELOC_16:
637 *buf++ = val >> 8;
638 *buf++ = val >> 0;
639 break;
640
641 case BFD_RELOC_8:
642 *buf++ = val;
643 break;
644
645 case BFD_RELOC_MOXIE_10_PCREL:
646 if (!val)
647 break;
648 if (val < -1024 || val > 1022)
649 as_bad_where (fixP->fx_file, fixP->fx_line,
650 _("pcrel too far BFD_RELOC_MOXIE_10"));
651 /* 11 bit offset even numbered, so we remove right bit. */
652 val >>= 1;
653 newval = md_chars_to_number (buf, 2);
654 newval |= val & 0x03ff;
655 md_number_to_chars (buf, newval, 2);
656 break;
657
658 default:
659 abort ();
660 }
661
662 if (max != 0 && (val < min || val > max))
663 as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
664
665 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
666 fixP->fx_done = 1;
667 }
668
669 /* Put number into target byte order (big endian). */
670
671 void
672 md_number_to_chars (char *ptr, valueT use, int nbytes)
673 {
674 number_to_chars_bigendian (ptr, use, nbytes);
675 }
676
677 /* Convert from target byte order to host byte order. */
678
679 static int
680 md_chars_to_number (char *val, int n)
681 {
682 int retval = 0;
683
684 while (n--)
685 {
686 retval <<= 8;
687 retval |= (*val++ & 255);
688 }
689
690 return retval;
691 }
692
693 /* Generate a machine-dependent relocation. */
694 arelent *
695 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
696 {
697 arelent *relP;
698 bfd_reloc_code_real_type code;
699
700 switch (fixP->fx_r_type)
701 {
702 case BFD_RELOC_32:
703 code = fixP->fx_r_type;
704 break;
705 case BFD_RELOC_MOXIE_10_PCREL:
706 code = fixP->fx_r_type;
707 break;
708 default:
709 as_bad_where (fixP->fx_file, fixP->fx_line,
710 _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant"));
711 return 0;
712 }
713
714 relP = xmalloc (sizeof (arelent));
715 gas_assert (relP != 0);
716 relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
717 *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
718 relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
719
720 relP->addend = fixP->fx_offset;
721
722 /* This is the standard place for KLUDGEs to work around bugs in
723 bfd_install_relocation (first such note in the documentation
724 appears with binutils-2.8).
725
726 That function bfd_install_relocation does the wrong thing with
727 putting stuff into the addend of a reloc (it should stay out) for a
728 weak symbol. The really bad thing is that it adds the
729 "segment-relative offset" of the symbol into the reloc. In this
730 case, the reloc should instead be relative to the symbol with no
731 other offset than the assembly code shows; and since the symbol is
732 weak, any local definition should be ignored until link time (or
733 thereafter).
734 To wit: weaksym+42 should be weaksym+42 in the reloc,
735 not weaksym+(offset_from_segment_of_local_weaksym_definition)
736
737 To "work around" this, we subtract the segment-relative offset of
738 "known" weak symbols. This evens out the extra offset.
739
740 That happens for a.out but not for ELF, since for ELF,
741 bfd_install_relocation uses the "special function" field of the
742 howto, and does not execute the code that needs to be undone. */
743
744 if (OUTPUT_FLAVOR == bfd_target_aout_flavour
745 && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)
746 && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy)))
747 {
748 relP->addend -= S_GET_VALUE (fixP->fx_addsy);
749 }
750
751 relP->howto = bfd_reloc_type_lookup (stdoutput, code);
752 if (! relP->howto)
753 {
754 const char *name;
755
756 name = S_GET_NAME (fixP->fx_addsy);
757 if (name == NULL)
758 name = _("<unknown>");
759 as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
760 name, bfd_get_reloc_code_name (code));
761 }
762
763 return relP;
764 }
765
766 /* Decide from what point a pc-relative relocation is relative to,
767 relative to the pc-relative fixup. Er, relatively speaking. */
768 long
769 md_pcrel_from (fixS *fixP)
770 {
771 valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
772
773 switch (fixP->fx_r_type)
774 {
775 case BFD_RELOC_32:
776 return addr + 4;
777 case BFD_RELOC_MOXIE_10_PCREL:
778 return addr;
779 default:
780 abort ();
781 return addr;
782 }
783 }
784