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