1/*-
2   tc-pj.c -- Assemble code for Pico Java
3   Copyright 1999, 2000, 2001, 2002, 2003, 2005
4   Free Software Foundation, Inc.
5
6   This file is part of GAS, the GNU Assembler.
7
8   GAS is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   GAS is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with GAS; see the file COPYING.  If not, write to
20   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
21   Boston, MA 02110-1301, USA.  */
22
23/* Contributed by Steve Chamberlain of Transmeta <sac@pobox.com>.  */
24
25#include "as.h"
26#include "safe-ctype.h"
27#include "opcode/pj.h"
28
29extern const pj_opc_info_t pj_opc_info[512];
30
31const char comment_chars[]        = "!/";
32const char line_separator_chars[] = ";";
33const char line_comment_chars[]   = "/!#";
34
35static int pending_reloc;
36static struct hash_control *opcode_hash_control;
37
38static void
39little (int ignore ATTRIBUTE_UNUSED)
40{
41  target_big_endian = 0;
42}
43
44static void
45big (int ignore ATTRIBUTE_UNUSED)
46{
47  target_big_endian = 1;
48}
49
50const pseudo_typeS md_pseudo_table[] =
51{
52  {"ml",    little, 0},
53  {"mb",    big,    0},
54  {0, 0, 0}
55};
56
57const char FLT_CHARS[] = "rRsSfFdDxXpP";
58const char EXP_CHARS[] = "eE";
59
60void
61md_operand (expressionS *op)
62{
63  if (strncmp (input_line_pointer, "%hi16", 5) == 0)
64    {
65      if (pending_reloc)
66	as_bad (_("confusing relocation expressions"));
67      pending_reloc = BFD_RELOC_PJ_CODE_HI16;
68      input_line_pointer += 5;
69      expression (op);
70    }
71
72  if (strncmp (input_line_pointer, "%lo16", 5) == 0)
73    {
74      if (pending_reloc)
75	as_bad (_("confusing relocation expressions"));
76      pending_reloc = BFD_RELOC_PJ_CODE_LO16;
77      input_line_pointer += 5;
78      expression (op);
79    }
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
96/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
97   reloc for a cons.  We could use the definition there, except that
98   we want to handle magic pending reloc expressions specially.  */
99
100void
101pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp)
102{
103  static int rv[5][2] =
104  { { 0, 0 },
105    { BFD_RELOC_8, BFD_RELOC_8 },
106    { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
107    { 0, 0 },
108    { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
109
110  fix_new_exp (frag, where, nbytes, exp, 0,
111	       pending_reloc ? pending_reloc
112	       : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
113
114  pending_reloc = 0;
115}
116
117/* Turn a reloc description character from the pj-opc.h table into
118   code which BFD can handle.  */
119
120static int
121c_to_r (int x)
122{
123  switch (x)
124    {
125    case O_R8:
126      return BFD_RELOC_8_PCREL;
127    case O_U8:
128    case O_8:
129      return BFD_RELOC_8;
130    case O_R16:
131      return BFD_RELOC_PJ_CODE_REL16;
132    case O_U16:
133    case O_16:
134      return BFD_RELOC_PJ_CODE_DIR16;
135    case O_R32:
136      return BFD_RELOC_PJ_CODE_REL32;
137    case O_32:
138      return BFD_RELOC_PJ_CODE_DIR32;
139    }
140  abort ();
141  return 0;
142}
143
144/* Handler for the ipush fake opcode,
145   turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>.  */
146
147static void
148ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str)
149{
150  char *b = frag_more (6);
151  expressionS arg;
152
153  b[0] = 0x11;
154  b[3] = 0xed;
155  parse_exp_save_ilp (str + 1, &arg);
156  if (pending_reloc)
157    {
158      as_bad (_("can't have relocation for ipush"));
159      pending_reloc = 0;
160    }
161
162  fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
163	       &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
164  fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
165	       &arg, 0, BFD_RELOC_PJ_CODE_HI16);
166}
167
168/* Insert names into the opcode table which are really mini macros,
169   not opcodes.  The fakeness is indicated with an opcode of -1.  */
170
171static void
172fake_opcode (const char *name,
173	     void (*func) (struct pj_opc_info_t *, char *))
174{
175  pj_opc_info_t * fake = xmalloc (sizeof (pj_opc_info_t));
176
177  fake->opcode = -1;
178  fake->opcode_next = -1;
179  fake->u.func = func;
180  hash_insert (opcode_hash_control, name, (char *) fake);
181}
182
183/* Enter another entry into the opcode hash table so the same opcode
184   can have another name.  */
185
186static void
187alias (const char *new, const char *old)
188{
189  hash_insert (opcode_hash_control, new,
190	       (char *) hash_find (opcode_hash_control, old));
191}
192
193/* This function is called once, at assembler startup time.  It sets
194   up the hash table with all the opcodes in it, and also initializes
195   some aliases for compatibility with other assemblers.  */
196
197void
198md_begin (void)
199{
200  const pj_opc_info_t *opcode;
201  opcode_hash_control = hash_new ();
202
203  /* Insert names into hash table.  */
204  for (opcode = pj_opc_info; opcode->u.name; opcode++)
205    hash_insert (opcode_hash_control, opcode->u.name, (char *) opcode);
206
207  /* Insert the only fake opcode.  */
208  fake_opcode ("ipush", ipush_code);
209
210  /* Add some aliases for opcode names.  */
211  alias ("ifeq_s", "ifeq");
212  alias ("ifne_s", "ifne");
213  alias ("if_icmpge_s", "if_icmpge");
214  alias ("if_icmpne_s", "if_icmpne");
215  alias ("if_icmpeq_s", "if_icmpeq");
216  alias ("if_icmpgt_s", "if_icmpgt");
217  alias ("goto_s", "goto");
218
219  bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
220}
221
222/* This is the guts of the machine-dependent assembler.  STR points to
223   a machine dependent instruction.  This function is supposed to emit
224   the frags/bytes it assembles to.  */
225
226void
227md_assemble (char *str)
228{
229  char *op_start;
230  char *op_end;
231
232  pj_opc_info_t *opcode;
233  char *output;
234  int idx = 0;
235  char pend;
236
237  int nlen = 0;
238
239  /* Drop leading whitespace.  */
240  while (*str == ' ')
241    str++;
242
243  /* Find the op code end.  */
244  op_start = str;
245  for (op_end = str;
246       *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
247       op_end++)
248    nlen++;
249
250  pend = *op_end;
251  *op_end = 0;
252
253  if (nlen == 0)
254    as_bad (_("can't find opcode "));
255
256  opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
257  *op_end = pend;
258
259  if (opcode == NULL)
260    {
261      as_bad (_("unknown opcode %s"), op_start);
262      return;
263    }
264
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 expresssion");
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}
316
317/* Turn a string in input_line_pointer into a floating point constant
318   of type type, and store the appropriate bytes in *LITP.  The number
319   of LITTLENUMS emitted is stored in *SIZEP .  An error message is
320   returned, or NULL on OK.  */
321
322char *
323md_atof (int type, char *litP, int *sizeP)
324{
325  int prec;
326  LITTLENUM_TYPE words[4];
327  char *t;
328  int i;
329
330  switch (type)
331    {
332    case 'f':
333      prec = 2;
334      break;
335
336    case 'd':
337      prec = 4;
338      break;
339
340    default:
341      *sizeP = 0;
342      return _("bad call to md_atof");
343    }
344
345  t = atof_ieee (input_line_pointer, type, words);
346  if (t)
347    input_line_pointer = t;
348
349  *sizeP = prec * 2;
350
351  if (!target_big_endian)
352    {
353      for (i = prec - 1; i >= 0; i--)
354	{
355	  md_number_to_chars (litP, (valueT) words[i], 2);
356	  litP += 2;
357	}
358    }
359  else
360    {
361      for (i = 0; i < prec; i++)
362	{
363	  md_number_to_chars (litP, (valueT) words[i], 2);
364	  litP += 2;
365	}
366    }
367
368  return NULL;
369}
370
371const char *md_shortopts = "";
372
373struct option md_longopts[] =
374{
375#define OPTION_LITTLE (OPTION_MD_BASE)
376#define OPTION_BIG    (OPTION_LITTLE + 1)
377
378  {"little", no_argument, NULL, OPTION_LITTLE},
379  {"big", no_argument, NULL, OPTION_BIG},
380  {NULL, no_argument, NULL, 0}
381};
382size_t md_longopts_size = sizeof (md_longopts);
383
384int
385md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
386{
387  switch (c)
388    {
389    case OPTION_LITTLE:
390      little (0);
391      break;
392    case OPTION_BIG:
393      big (0);
394      break;
395    default:
396      return 0;
397    }
398  return 1;
399}
400
401void
402md_show_usage (FILE *stream)
403{
404  fprintf (stream, _("\
405PJ options:\n\
406-little			generate little endian code\n\
407-big			generate big endian code\n"));
408}
409
410/* Apply a fixup to the object file.  */
411
412void
413md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
414{
415  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
416  long val = *valP;
417  long max, min;
418  int shift;
419
420  max = min = 0;
421  shift = 0;
422  switch (fixP->fx_r_type)
423    {
424    case BFD_RELOC_VTABLE_INHERIT:
425    case BFD_RELOC_VTABLE_ENTRY:
426      fixP->fx_done = 0;
427      return;
428
429    case BFD_RELOC_PJ_CODE_REL16:
430      if (val < -0x8000 || val >= 0x7fff)
431	as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
432      buf[0] |= (val >> 8) & 0xff;
433      buf[1] = val & 0xff;
434      break;
435
436    case BFD_RELOC_PJ_CODE_HI16:
437      *buf++ = val >> 24;
438      *buf++ = val >> 16;
439      fixP->fx_addnumber = val & 0xffff;
440      break;
441
442    case BFD_RELOC_PJ_CODE_DIR16:
443    case BFD_RELOC_PJ_CODE_LO16:
444      *buf++ = val >> 8;
445      *buf++ = val >> 0;
446
447      max = 0xffff;
448      min = -0xffff;
449      break;
450
451    case BFD_RELOC_8:
452      max = 0xff;
453      min = -0xff;
454      *buf++ = val;
455      break;
456
457    case BFD_RELOC_PJ_CODE_DIR32:
458      *buf++ = val >> 24;
459      *buf++ = val >> 16;
460      *buf++ = val >> 8;
461      *buf++ = val >> 0;
462      break;
463
464    case BFD_RELOC_32:
465      if (target_big_endian)
466	{
467	  *buf++ = val >> 24;
468	  *buf++ = val >> 16;
469	  *buf++ = val >> 8;
470	  *buf++ = val >> 0;
471	}
472      else
473	{
474	  *buf++ = val >> 0;
475	  *buf++ = val >> 8;
476	  *buf++ = val >> 16;
477	  *buf++ = val >> 24;
478	}
479      break;
480
481    case BFD_RELOC_16:
482      if (target_big_endian)
483	{
484	  *buf++ = val >> 8;
485	  *buf++ = val >> 0;
486	}
487      else
488	{
489	  *buf++ = val >> 0;
490	  *buf++ = val >> 8;
491	}
492      break;
493
494    default:
495      abort ();
496    }
497
498  if (max != 0 && (val < min || val > max))
499    as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
500
501  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
502    fixP->fx_done = 1;
503}
504
505/* Put number into target byte order.  Always put values in an
506   executable section into big endian order.  */
507
508void
509md_number_to_chars (char *ptr, valueT use, int nbytes)
510{
511  if (target_big_endian || now_seg->flags & SEC_CODE)
512    number_to_chars_bigendian (ptr, use, nbytes);
513  else
514    number_to_chars_littleendian (ptr, use, nbytes);
515}
516
517/* Translate internal representation of relocation info to BFD target
518   format.  */
519
520arelent *
521tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
522{
523  arelent *rel;
524  bfd_reloc_code_real_type r_type;
525
526  rel = xmalloc (sizeof (arelent));
527  rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
528  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
529  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
530
531  r_type = fixp->fx_r_type;
532  rel->addend = fixp->fx_addnumber;
533  rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
534
535  if (rel->howto == NULL)
536    {
537      as_bad_where (fixp->fx_file, fixp->fx_line,
538		    _("Cannot represent relocation type %s"),
539		    bfd_get_reloc_code_name (r_type));
540      /* Set howto to a garbage value so that we can keep going.  */
541      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
542      assert (rel->howto != NULL);
543    }
544
545  return rel;
546}
547