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