Remove duplicate definitions of the md_atof() function
[platform/upstream/binutils.git] / gas / config / tc-pj.c
1 /* tc-pj.c -- Assemble code for Pico Java
2    Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2007
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 Steve Chamberlain of Transmeta <sac@pobox.com>.  */
23
24 #include "as.h"
25 #include "safe-ctype.h"
26 #include "opcode/pj.h"
27
28 extern const pj_opc_info_t pj_opc_info[512];
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 struct hash_control *opcode_hash_control;
36
37 static void
38 little (int ignore ATTRIBUTE_UNUSED)
39 {
40   target_big_endian = 0;
41 }
42
43 static void
44 big (int ignore ATTRIBUTE_UNUSED)
45 {
46   target_big_endian = 1;
47 }
48
49 const pseudo_typeS md_pseudo_table[] =
50 {
51   {"ml",    little, 0},
52   {"mb",    big,    0},
53   {0, 0, 0}
54 };
55
56 const char FLT_CHARS[] = "rRsSfFdDxXpP";
57 const char EXP_CHARS[] = "eE";
58
59 void
60 md_operand (expressionS *op)
61 {
62   if (strncmp (input_line_pointer, "%hi16", 5) == 0)
63     {
64       if (pending_reloc)
65         as_bad (_("confusing relocation expressions"));
66       pending_reloc = BFD_RELOC_PJ_CODE_HI16;
67       input_line_pointer += 5;
68       expression (op);
69     }
70
71   if (strncmp (input_line_pointer, "%lo16", 5) == 0)
72     {
73       if (pending_reloc)
74         as_bad (_("confusing relocation expressions"));
75       pending_reloc = BFD_RELOC_PJ_CODE_LO16;
76       input_line_pointer += 5;
77       expression (op);
78     }
79 }
80
81 /* Parse an expression and then restore the input line pointer.  */
82
83 static char *
84 parse_exp_save_ilp (char *s, expressionS *op)
85 {
86   char *save = input_line_pointer;
87
88   input_line_pointer = s;
89   expression (op);
90   s = input_line_pointer;
91   input_line_pointer = save;
92   return s;
93 }
94
95 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
96    reloc for a cons.  We could use the definition there, except that
97    we want to handle magic pending reloc expressions specially.  */
98
99 void
100 pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp)
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
119 static int
120 c_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
146 static void
147 ipush_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
170 static void
171 fake_opcode (const char *name,
172              void (*func) (struct pj_opc_info_t *, char *))
173 {
174   pj_opc_info_t * fake = xmalloc (sizeof (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
185 static void
186 alias (const char *new, const char *old)
187 {
188   hash_insert (opcode_hash_control, new,
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
196 void
197 md_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
225 void
226 md_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   if (opcode->opcode == -1)
265     {
266       /* It's a fake opcode.  Dig out the args and pretend that was
267          what we were passed.  */
268       (*opcode->u.func) (opcode, op_end);
269     }
270   else
271     {
272       int an;
273
274       output = frag_more (opcode->len);
275       output[idx++] = opcode->opcode;
276
277       if (opcode->opcode_next != -1)
278         output[idx++] = opcode->opcode_next;
279
280       for (an = 0; opcode->arg[an]; an++)
281         {
282           expressionS arg;
283
284           if (*op_end == ',' && an != 0)
285             op_end++;
286
287           if (*op_end == 0)
288             as_bad ("expected expresssion");
289
290           op_end = parse_exp_save_ilp (op_end, &arg);
291
292           fix_new_exp (frag_now,
293                        output - frag_now->fr_literal + idx,
294                        ASIZE (opcode->arg[an]),
295                        &arg,
296                        PCREL (opcode->arg[an]),
297                        pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
298
299           idx += ASIZE (opcode->arg[an]);
300           pending_reloc = 0;
301         }
302
303       while (ISSPACE (*op_end))
304         op_end++;
305
306       if (*op_end != 0)
307         as_warn ("extra stuff on line ignored");
308
309     }
310
311   if (pending_reloc)
312     as_bad ("Something forgot to clean up\n");
313
314 }
315
316 char *
317 md_atof (int type, char *litP, int *sizeP)
318 {
319   return ieee_md_atof (type, litP, sizeP, target_big_endian);
320 }
321 \f
322 const char *md_shortopts = "";
323
324 struct 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 };
333 size_t md_longopts_size = sizeof (md_longopts);
334
335 int
336 md_parse_option (int c, 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
352 void
353 md_show_usage (FILE *stream)
354 {
355   fprintf (stream, _("\
356 PJ 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
363 void
364 md_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   int shift;
370
371   max = min = 0;
372   shift = 0;
373   switch (fixP->fx_r_type)
374     {
375     case BFD_RELOC_VTABLE_INHERIT:
376     case BFD_RELOC_VTABLE_ENTRY:
377       fixP->fx_done = 0;
378       return;
379
380     case BFD_RELOC_PJ_CODE_REL16:
381       if (val < -0x8000 || val >= 0x7fff)
382         as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
383       buf[0] |= (val >> 8) & 0xff;
384       buf[1] = val & 0xff;
385       break;
386
387     case BFD_RELOC_PJ_CODE_HI16:
388       *buf++ = val >> 24;
389       *buf++ = val >> 16;
390       fixP->fx_addnumber = val & 0xffff;
391       break;
392
393     case BFD_RELOC_PJ_CODE_DIR16:
394     case BFD_RELOC_PJ_CODE_LO16:
395       *buf++ = val >> 8;
396       *buf++ = val >> 0;
397
398       max = 0xffff;
399       min = -0xffff;
400       break;
401
402     case BFD_RELOC_8:
403       max = 0xff;
404       min = -0xff;
405       *buf++ = val;
406       break;
407
408     case BFD_RELOC_PJ_CODE_DIR32:
409       *buf++ = val >> 24;
410       *buf++ = val >> 16;
411       *buf++ = val >> 8;
412       *buf++ = val >> 0;
413       break;
414
415     case BFD_RELOC_32:
416       if (target_big_endian)
417         {
418           *buf++ = val >> 24;
419           *buf++ = val >> 16;
420           *buf++ = val >> 8;
421           *buf++ = val >> 0;
422         }
423       else
424         {
425           *buf++ = val >> 0;
426           *buf++ = val >> 8;
427           *buf++ = val >> 16;
428           *buf++ = val >> 24;
429         }
430       break;
431
432     case BFD_RELOC_16:
433       if (target_big_endian)
434         {
435           *buf++ = val >> 8;
436           *buf++ = val >> 0;
437         }
438       else
439         {
440           *buf++ = val >> 0;
441           *buf++ = val >> 8;
442         }
443       break;
444
445     default:
446       abort ();
447     }
448
449   if (max != 0 && (val < min || val > max))
450     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
451
452   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
453     fixP->fx_done = 1;
454 }
455
456 /* Put number into target byte order.  Always put values in an
457    executable section into big endian order.  */
458
459 void
460 md_number_to_chars (char *ptr, valueT use, int nbytes)
461 {
462   if (target_big_endian || now_seg->flags & SEC_CODE)
463     number_to_chars_bigendian (ptr, use, nbytes);
464   else
465     number_to_chars_littleendian (ptr, use, nbytes);
466 }
467
468 /* Translate internal representation of relocation info to BFD target
469    format.  */
470
471 arelent *
472 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
473 {
474   arelent *rel;
475   bfd_reloc_code_real_type r_type;
476
477   rel = xmalloc (sizeof (arelent));
478   rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
479   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
480   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
481
482   r_type = fixp->fx_r_type;
483   rel->addend = fixp->fx_addnumber;
484   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
485
486   if (rel->howto == NULL)
487     {
488       as_bad_where (fixp->fx_file, fixp->fx_line,
489                     _("Cannot represent relocation type %s"),
490                     bfd_get_reloc_code_name (r_type));
491       /* Set howto to a garbage value so that we can keep going.  */
492       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
493       assert (rel->howto != NULL);
494     }
495
496   return rel;
497 }