1/* tc-pj.c -- Assemble code for Pico Java
2   Copyright (C) 1999-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 Steve Chamberlain of Transmeta <sac@pobox.com>.  */
22
23#include "as.h"
24#include "safe-ctype.h"
25#include "opcode/pj.h"
26
27extern const pj_opc_info_t pj_opc_info[512];
28
29const char comment_chars[]        = "!/";
30const char line_separator_chars[] = ";";
31const char line_comment_chars[]   = "/!#";
32
33static int pending_reloc;
34static struct hash_control *opcode_hash_control;
35
36static void
37little (int ignore ATTRIBUTE_UNUSED)
38{
39  target_big_endian = 0;
40}
41
42static void
43big (int ignore ATTRIBUTE_UNUSED)
44{
45  target_big_endian = 1;
46}
47
48const pseudo_typeS md_pseudo_table[] =
49{
50  {"ml",    little, 0},
51  {"mb",    big,    0},
52  {0, 0, 0}
53};
54
55const char FLT_CHARS[] = "rRsSfFdDxXpP";
56const char EXP_CHARS[] = "eE";
57
58void
59md_operand (expressionS *op)
60{
61  if (strncmp (input_line_pointer, "%hi16", 5) == 0)
62    {
63      if (pending_reloc)
64	as_bad (_("confusing relocation expressions"));
65      pending_reloc = BFD_RELOC_PJ_CODE_HI16;
66      input_line_pointer += 5;
67      expression (op);
68    }
69
70  if (strncmp (input_line_pointer, "%lo16", 5) == 0)
71    {
72      if (pending_reloc)
73	as_bad (_("confusing relocation expressions"));
74      pending_reloc = BFD_RELOC_PJ_CODE_LO16;
75      input_line_pointer += 5;
76      expression (op);
77    }
78}
79
80/* Parse an expression and then restore the input line pointer.  */
81
82static char *
83parse_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/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
95   reloc for a cons.  We could use the definition there, except that
96   we want to handle magic pending reloc expressions specially.  */
97
98void
99pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp,
100		    bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
101{
102  static int rv[5][2] =
103  { { 0, 0 },
104    { BFD_RELOC_8, BFD_RELOC_8 },
105    { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
106    { 0, 0 },
107    { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
108
109  fix_new_exp (frag, where, nbytes, exp, 0,
110	       pending_reloc ? pending_reloc
111	       : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
112
113  pending_reloc = 0;
114}
115
116/* Turn a reloc description character from the pj-opc.h table into
117   code which BFD can handle.  */
118
119static int
120c_to_r (int x)
121{
122  switch (x)
123    {
124    case O_R8:
125      return BFD_RELOC_8_PCREL;
126    case O_U8:
127    case O_8:
128      return BFD_RELOC_8;
129    case O_R16:
130      return BFD_RELOC_PJ_CODE_REL16;
131    case O_U16:
132    case O_16:
133      return BFD_RELOC_PJ_CODE_DIR16;
134    case O_R32:
135      return BFD_RELOC_PJ_CODE_REL32;
136    case O_32:
137      return BFD_RELOC_PJ_CODE_DIR32;
138    }
139  abort ();
140  return 0;
141}
142
143/* Handler for the ipush fake opcode,
144   turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>.  */
145
146static void
147ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str)
148{
149  char *b = frag_more (6);
150  expressionS arg;
151
152  b[0] = 0x11;
153  b[3] = 0xed;
154  parse_exp_save_ilp (str + 1, &arg);
155  if (pending_reloc)
156    {
157      as_bad (_("can't have relocation for ipush"));
158      pending_reloc = 0;
159    }
160
161  fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
162	       &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
163  fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
164	       &arg, 0, BFD_RELOC_PJ_CODE_HI16);
165}
166
167/* Insert names into the opcode table which are really mini macros,
168   not opcodes.  The fakeness is indicated with an opcode of -1.  */
169
170static void
171fake_opcode (const char *name,
172	     void (*func) (struct pj_opc_info_t *, char *))
173{
174  pj_opc_info_t * fake = XNEW (pj_opc_info_t);
175
176  fake->opcode = -1;
177  fake->opcode_next = -1;
178  fake->u.func = func;
179  hash_insert (opcode_hash_control, name, (char *) fake);
180}
181
182/* Enter another entry into the opcode hash table so the same opcode
183   can have another name.  */
184
185static void
186alias (const char *new_name, const char *old)
187{
188  hash_insert (opcode_hash_control, new_name,
189	       (char *) hash_find (opcode_hash_control, old));
190}
191
192/* This function is called once, at assembler startup time.  It sets
193   up the hash table with all the opcodes in it, and also initializes
194   some aliases for compatibility with other assemblers.  */
195
196void
197md_begin (void)
198{
199  const pj_opc_info_t *opcode;
200  opcode_hash_control = hash_new ();
201
202  /* Insert names into hash table.  */
203  for (opcode = pj_opc_info; opcode->u.name; opcode++)
204    hash_insert (opcode_hash_control, opcode->u.name, (char *) opcode);
205
206  /* Insert the only fake opcode.  */
207  fake_opcode ("ipush", ipush_code);
208
209  /* Add some aliases for opcode names.  */
210  alias ("ifeq_s", "ifeq");
211  alias ("ifne_s", "ifne");
212  alias ("if_icmpge_s", "if_icmpge");
213  alias ("if_icmpne_s", "if_icmpne");
214  alias ("if_icmpeq_s", "if_icmpeq");
215  alias ("if_icmpgt_s", "if_icmpgt");
216  alias ("goto_s", "goto");
217
218  bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
219}
220
221/* This is the guts of the machine-dependent assembler.  STR points to
222   a machine dependent instruction.  This function is supposed to emit
223   the frags/bytes it assembles to.  */
224
225void
226md_assemble (char *str)
227{
228  char *op_start;
229  char *op_end;
230
231  pj_opc_info_t *opcode;
232  char *output;
233  int idx = 0;
234  char pend;
235
236  int nlen = 0;
237
238  /* Drop leading whitespace.  */
239  while (*str == ' ')
240    str++;
241
242  /* Find the op code end.  */
243  op_start = str;
244  for (op_end = str;
245       *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
246       op_end++)
247    nlen++;
248
249  pend = *op_end;
250  *op_end = 0;
251
252  if (nlen == 0)
253    as_bad (_("can't find opcode "));
254
255  opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
256  *op_end = pend;
257
258  if (opcode == NULL)
259    {
260      as_bad (_("unknown opcode %s"), op_start);
261      return;
262    }
263
264  dwarf2_emit_insn (0);
265  if (opcode->opcode == -1)
266    {
267      /* It's a fake opcode.  Dig out the args and pretend that was
268         what we were passed.  */
269      (*opcode->u.func) (opcode, op_end);
270    }
271  else
272    {
273      int an;
274
275      output = frag_more (opcode->len);
276      output[idx++] = opcode->opcode;
277
278      if (opcode->opcode_next != -1)
279	output[idx++] = opcode->opcode_next;
280
281      for (an = 0; opcode->arg[an]; an++)
282	{
283	  expressionS arg;
284
285	  if (*op_end == ',' && an != 0)
286	    op_end++;
287
288	  if (*op_end == 0)
289	    as_bad (_("expected expression"));
290
291	  op_end = parse_exp_save_ilp (op_end, &arg);
292
293	  fix_new_exp (frag_now,
294		       output - frag_now->fr_literal + idx,
295		       ASIZE (opcode->arg[an]),
296		       &arg,
297		       PCREL (opcode->arg[an]),
298		       pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
299
300	  idx += ASIZE (opcode->arg[an]);
301	  pending_reloc = 0;
302	}
303
304      while (ISSPACE (*op_end))
305	op_end++;
306
307      if (*op_end != 0)
308	as_warn (_("extra stuff on line ignored"));
309
310    }
311
312  if (pending_reloc)
313    as_bad (_("Something forgot to clean up\n"));
314}
315
316const char *
317md_atof (int type, char *litP, int *sizeP)
318{
319  return ieee_md_atof (type, litP, sizeP, target_big_endian);
320}
321
322const char *md_shortopts = "";
323
324struct option md_longopts[] =
325{
326#define OPTION_LITTLE (OPTION_MD_BASE)
327#define OPTION_BIG    (OPTION_LITTLE + 1)
328
329  {"little", no_argument, NULL, OPTION_LITTLE},
330  {"big", no_argument, NULL, OPTION_BIG},
331  {NULL, no_argument, NULL, 0}
332};
333size_t md_longopts_size = sizeof (md_longopts);
334
335int
336md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
337{
338  switch (c)
339    {
340    case OPTION_LITTLE:
341      little (0);
342      break;
343    case OPTION_BIG:
344      big (0);
345      break;
346    default:
347      return 0;
348    }
349  return 1;
350}
351
352void
353md_show_usage (FILE *stream)
354{
355  fprintf (stream, _("\
356PJ options:\n\
357-little			generate little endian code\n\
358-big			generate big endian code\n"));
359}
360
361/* Apply a fixup to the object file.  */
362
363void
364md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
365{
366  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
367  long val = *valP;
368  long max, min;
369
370  max = min = 0;
371  switch (fixP->fx_r_type)
372    {
373    case BFD_RELOC_VTABLE_INHERIT:
374    case BFD_RELOC_VTABLE_ENTRY:
375      fixP->fx_done = 0;
376      return;
377
378    case BFD_RELOC_PJ_CODE_REL16:
379      if (val < -0x8000 || val >= 0x7fff)
380	as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
381      buf[0] |= (val >> 8) & 0xff;
382      buf[1] = val & 0xff;
383      break;
384
385    case BFD_RELOC_PJ_CODE_HI16:
386      *buf++ = val >> 24;
387      *buf++ = val >> 16;
388      fixP->fx_addnumber = val & 0xffff;
389      break;
390
391    case BFD_RELOC_PJ_CODE_DIR16:
392    case BFD_RELOC_PJ_CODE_LO16:
393      *buf++ = val >> 8;
394      *buf++ = val >> 0;
395
396      max = 0xffff;
397      min = -0xffff;
398      break;
399
400    case BFD_RELOC_8:
401      max = 0xff;
402      min = -0xff;
403      *buf++ = val;
404      break;
405
406    case BFD_RELOC_PJ_CODE_DIR32:
407      *buf++ = val >> 24;
408      *buf++ = val >> 16;
409      *buf++ = val >> 8;
410      *buf++ = val >> 0;
411      break;
412
413    case BFD_RELOC_32:
414      if (target_big_endian)
415	{
416	  *buf++ = val >> 24;
417	  *buf++ = val >> 16;
418	  *buf++ = val >> 8;
419	  *buf++ = val >> 0;
420	}
421      else
422	{
423	  *buf++ = val >> 0;
424	  *buf++ = val >> 8;
425	  *buf++ = val >> 16;
426	  *buf++ = val >> 24;
427	}
428      break;
429
430    case BFD_RELOC_16:
431      if (target_big_endian)
432	{
433	  *buf++ = val >> 8;
434	  *buf++ = val >> 0;
435	}
436      else
437	{
438	  *buf++ = val >> 0;
439	  *buf++ = val >> 8;
440	}
441      break;
442
443    case BFD_RELOC_PJ_CODE_REL32:
444      fixP->fx_done = 0;
445      return;
446
447    default:
448      abort ();
449    }
450
451  if (max != 0 && (val < min || val > max))
452    as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
453
454  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
455    fixP->fx_done = 1;
456}
457
458/* Put number into target byte order.  Always put values in an
459   executable section into big endian order.  */
460
461void
462md_number_to_chars (char *ptr, valueT use, int nbytes)
463{
464  if (target_big_endian || now_seg->flags & SEC_CODE)
465    number_to_chars_bigendian (ptr, use, nbytes);
466  else
467    number_to_chars_littleendian (ptr, use, nbytes);
468}
469
470/* Translate internal representation of relocation info to BFD target
471   format.  */
472
473arelent *
474tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
475{
476  arelent *rel;
477  bfd_reloc_code_real_type r_type;
478
479  rel = XNEW (arelent);
480  rel->sym_ptr_ptr = XNEW (asymbol *);
481  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
482  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
483
484  r_type = fixp->fx_r_type;
485  rel->addend = fixp->fx_addnumber;
486  rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
487
488  if (rel->howto == NULL)
489    {
490      as_bad_where (fixp->fx_file, fixp->fx_line,
491		    _("Cannot represent relocation type %s"),
492		    bfd_get_reloc_code_name (r_type));
493      /* Set howto to a garbage value so that we can keep going.  */
494      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
495      gas_assert (rel->howto != NULL);
496    }
497
498  return rel;
499}
500