Add field ``name'' to floatformat.
[binutils.git] / gas / config / tc-pj.c
blob4f803095b2198a659fb5a90e434a0ba60fe6b7ca
1 /*-
2 tc-pj.c -- Assemble code for Pico Java
3 Copyright (C) 1999 Free Software Foundation.
5 This file is part of GAS, the GNU Assembler.
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 2, or (at your option)
10 any later version.
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.
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, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Contributed by Steve Chamberlain of Transmeta, sac@pobox.com */
24 #include "as.h"
25 #include "opcode/pj.h"
28 extern const pj_opc_info_t pj_opc_info[512];
30 const char comment_chars[] = "!/";
31 const char line_separator_chars[] = ";";
32 const char line_comment_chars[] = "/!#";
34 static int pending_reloc;
35 static struct hash_control *opcode_hash_control;
38 static void
39 little (ignore)
40 int ignore ATTRIBUTE_UNUSED;
42 target_big_endian = 0;
45 static void
46 big (ignore)
47 int ignore ATTRIBUTE_UNUSED;
49 target_big_endian = 1;
53 const pseudo_typeS md_pseudo_table[] = {
54 {"ml", little, 0},
55 {"mb", big, 0},
56 {0, 0, 0}
60 const char FLT_CHARS[] = "rRsSfFdDxXpP";
61 const char EXP_CHARS[] = "eE";
63 void
64 md_operand (op)
65 expressionS *op;
67 if (strncmp (input_line_pointer, "%hi16", 5) == 0)
69 if (pending_reloc)
70 as_bad (_ ("confusing relocation expressions"));
71 pending_reloc = BFD_RELOC_PJ_CODE_HI16;
72 input_line_pointer += 5;
73 expression (op);
75 if (strncmp (input_line_pointer, "%lo16", 5) == 0)
77 if (pending_reloc)
78 as_bad (_ ("confusing relocation expressions"));
79 pending_reloc = BFD_RELOC_PJ_CODE_LO16;
80 input_line_pointer += 5;
81 expression (op);
85 /* Parse an expression and then restore the input line pointer. */
87 static char *
88 parse_exp_save_ilp (s, op)
89 char *s;
90 expressionS *op;
92 char *save = input_line_pointer;
93 input_line_pointer = s;
94 expression (op);
95 s = input_line_pointer;
96 input_line_pointer = save;
97 return s;
100 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
101 reloc for a cons. We could use the definition there, except that
102 we want to handle magic pending reloc expressions specially. */
104 void
105 pj_cons_fix_new_pj (frag, where, nbytes, exp)
106 fragS *frag;
107 int where;
108 int nbytes;
109 expressionS *exp;
111 static int rv[5][2] =
112 { { 0, 0 },
113 { BFD_RELOC_8, BFD_RELOC_8 },
114 { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
115 { 0, 0 },
116 { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
118 fix_new_exp (frag, where, nbytes, exp, 0,
119 pending_reloc ? pending_reloc
120 : rv [nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
122 pending_reloc = 0;
126 /* Turn a reloc description character from the pj-opc.h table into
127 code which BFD can handle. */
129 static int
130 c_to_r (x)
131 char x;
133 switch (x)
135 case O_R8:
136 return BFD_RELOC_8_PCREL;
137 case O_U8:
138 case O_8:
139 return BFD_RELOC_8;
140 case O_R16:
141 return BFD_RELOC_PJ_CODE_REL16;
142 case O_U16:
143 case O_16:
144 return BFD_RELOC_PJ_CODE_DIR16;
145 case O_R32:
146 return BFD_RELOC_PJ_CODE_REL32;
147 case O_32:
148 return BFD_RELOC_PJ_CODE_DIR32;
150 abort ();
151 return 0;
157 /* Handler for the ipush fake opcode,
158 turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>. */
160 static void
161 ipush_code (opcode, str)
162 pj_opc_info_t *opcode ATTRIBUTE_UNUSED;
163 char *str;
165 int mod = 0;
166 char *b = frag_more (6);
167 expressionS arg;
168 b[0] = 0x11;
169 b[3] = 0xed;
170 parse_exp_save_ilp (str + 1, &arg, &mod);
171 if (mod)
172 as_bad (_ ("can't have relocation for ipush"));
175 fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
176 &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
177 fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
178 &arg, 0, BFD_RELOC_PJ_CODE_HI16);
181 /* Insert names into the opcode table which are really mini macros,
182 not opcodes. The fakeness is inidicated with an opcode of -1. */
184 static void
185 fake_opcode (name, func) const char *
186 name;
187 void (*func) ();
189 pj_opc_info_t *fake = (pj_opc_info_t *) xmalloc (sizeof (pj_opc_info_t));
191 fake->opcode = -1;
192 fake->opcode_next = -1;
193 fake->name = (const char *) func;
194 hash_insert (opcode_hash_control, name, (char *) fake);
198 /* Enter another entry into the opcode hash table so the same opcode
199 can have another name. */
200 static void
201 alias (new, old) const char *
202 new;
203 const char *old;
205 hash_insert (opcode_hash_control, new,
206 (char *) hash_find (opcode_hash_control, old));
210 /* This function is called once, at assembler startup time. It sets
211 up the hash table with all the opcodes in it, and also initializes
212 some aliases for compatibility with other assemblers. */
214 void
215 md_begin ()
217 const pj_opc_info_t *opcode;
218 opcode_hash_control = hash_new ();
220 /* Insert names into hash table */
221 for (opcode = pj_opc_info; opcode->name; opcode++)
222 hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
224 /* Insert the only fake opcode. */
225 fake_opcode ("ipush", ipush_code);
227 /* Add some aliases for opcode names. */
228 alias ("ifeq_s", "ifeq");
229 alias ("ifne_s", "ifne");
230 alias ("if_icmpge_s", "if_icmpge");
231 alias ("if_icmpne_s", "if_icmpne");
232 alias ("if_icmpeq_s", "if_icmpeq");
233 alias ("if_icmpgt_s", "if_icmpgt");
234 alias ("goto_s", "goto");
236 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
239 /* This is the guts of the machine-dependent assembler. STR points to a
240 machine dependent instruction. This function is supposed to emit
241 the frags/bytes it assembles to.
244 void
245 md_assemble (str)
246 char *str;
248 unsigned char *op_start;
249 unsigned char *op_end;
251 // pj_operan_info operand[3];
252 pj_opc_info_t *opcode;
253 char *output;
254 int idx = 0;
255 char pend;
257 int nlen = 0;
259 /* Drop leading whitespace */
260 while (*str == ' ')
261 str++;
263 /* find the op code end */
264 for (op_start = op_end = (unsigned char *) (str);
265 *op_end && !is_end_of_line[*op_end] && *op_end != ' ';
266 op_end++)
267 nlen++;
269 pend = *op_end;
270 *op_end = 0;
272 if (nlen == 0)
274 as_bad (_ ("can't find opcode "));
277 opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
278 *op_end = pend;
280 if (opcode == NULL)
282 as_bad (_ ("unknown opcode %s"), op_start);
283 return;
286 if (opcode->opcode == -1)
288 /* It's a fake opcode.. dig out the args and pretend that was
289 what we were passed */
290 ((void (*)()) opcode->name) (opcode, op_end);
292 else
294 int an;
296 output = frag_more (opcode->len);
297 output[idx++] = opcode->opcode;
299 if (opcode->opcode_next != -1)
300 output[idx++] = opcode->opcode_next;
302 for (an = 0; opcode->arg[an]; an++)
304 expressionS arg;
306 if (*op_end == ',' && an != 0)
307 op_end++;
309 if (*op_end == 0)
310 as_bad ("expected expresssion");
312 op_end = parse_exp_save_ilp (op_end, &arg);
314 fix_new_exp (frag_now,
315 output - frag_now->fr_literal + idx,
316 ASIZE (opcode->arg[an]),
317 &arg,
318 PCREL (opcode->arg[an]),
319 pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
321 idx += ASIZE (opcode->arg[an]);
322 pending_reloc = 0;
325 while (isspace (*op_end))
326 op_end++;
328 if (*op_end != 0)
329 as_warn ("extra stuff on line ignored");
333 if (pending_reloc)
334 as_bad ("Something forgot to clean up\n");
338 /* Turn a string in input_line_pointer into a floating point constant of type
339 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
340 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
342 char *
343 md_atof (type, litP, sizeP)
344 int type;
345 char *litP;
346 int *sizeP;
348 int prec;
349 LITTLENUM_TYPE words[4];
350 char *t;
351 int i;
353 switch (type)
355 case 'f':
356 prec = 2;
357 break;
359 case 'd':
360 prec = 4;
361 break;
363 default:
364 *sizeP = 0;
365 return _ ("bad call to md_atof");
368 t = atof_ieee (input_line_pointer, type, words);
369 if (t)
370 input_line_pointer = t;
372 *sizeP = prec * 2;
374 if (!target_big_endian)
376 for (i = prec - 1; i >= 0; i--)
378 md_number_to_chars (litP, (valueT) words[i], 2);
379 litP += 2;
382 else
384 for (i = 0; i < prec; i++)
386 md_number_to_chars (litP, (valueT) words[i], 2);
387 litP += 2;
391 return NULL;
395 CONST char *md_shortopts = "";
397 struct option md_longopts[] = {
399 #define OPTION_LITTLE (OPTION_MD_BASE)
400 #define OPTION_BIG (OPTION_LITTLE + 1)
402 {"little", no_argument, NULL, OPTION_LITTLE},
403 {"big", no_argument, NULL, OPTION_BIG},
404 {NULL, no_argument, NULL, 0}
406 size_t md_longopts_size = sizeof (md_longopts);
409 md_parse_option (c, arg)
410 int c;
411 char *arg ATTRIBUTE_UNUSED;
413 switch (c)
415 case OPTION_LITTLE:
416 little ();
417 break;
418 case OPTION_BIG:
419 big ();
420 break;
421 default:
422 return 0;
424 return 1;
427 void
428 md_show_usage (stream)
429 FILE *stream;
431 fprintf (stream, _ ("\
432 PJ options:\n\
433 -little generate little endian code\n\
434 -big generate big endian code\n"));
439 /* Apply a fixup to the object file. */
443 md_apply_fix (fixP, valp)
444 fixS *fixP;
445 valueT *valp;
447 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
448 long val = *valp;
449 long max, min;
450 int shift;
453 /* adjust_reloc_syms won't convert a reloc against a weak symbol
454 into a reloc against a section, but bfd_install_relocation will
455 screw up if the symbol is defined, so we have to adjust val here
456 to avoid the screw up later. */
458 if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
459 val -= S_GET_VALUE (fixP->fx_addsy);
461 max = min = 0;
462 shift = 0;
463 switch (fixP->fx_r_type)
465 case BFD_RELOC_VTABLE_INHERIT:
466 case BFD_RELOC_VTABLE_ENTRY:
467 fixP->fx_done = 0;
468 return 0;
470 case BFD_RELOC_PJ_CODE_REL16:
471 if (val < -0x8000 || val >= 0x7fff)
472 as_bad_where (fixP->fx_file, fixP->fx_line, _ ("pcrel too far"));
473 buf[0] |= (val >> 8) & 0xff;
474 buf[1] = val & 0xff;
475 break;
477 case BFD_RELOC_PJ_CODE_HI16:
478 *buf++ = val >> 24;
479 *buf++ = val >> 16;
480 fixP->fx_addnumber = val & 0xffff;
481 break;
483 case BFD_RELOC_PJ_CODE_DIR16:
484 case BFD_RELOC_PJ_CODE_LO16:
485 *buf++ = val >> 8;
486 *buf++ = val >> 0;
488 max = 0xffff;
489 min = -0xffff;
490 break;
492 case BFD_RELOC_8:
493 max = 0xff;
494 min = -0xff;
495 *buf++ = val;
496 break;
498 case BFD_RELOC_PJ_CODE_DIR32:
499 *buf++ = val >> 24;
500 *buf++ = val >> 16;
501 *buf++ = val >> 8;
502 *buf++ = val >> 0;
503 break;
505 case BFD_RELOC_32:
506 if (target_big_endian)
508 *buf++ = val >> 24;
509 *buf++ = val >> 16;
510 *buf++ = val >> 8;
511 *buf++ = val >> 0;
513 else
515 *buf++ = val >> 0;
516 *buf++ = val >> 8;
517 *buf++ = val >> 16;
518 *buf++ = val >> 24;
520 break;
522 case BFD_RELOC_16:
523 if (target_big_endian)
525 *buf++ = val >> 8;
526 *buf++ = val >> 0;
528 else
530 *buf++ = val >> 0;
531 *buf++ = val >> 8;
533 break;
536 default:
537 abort ();
540 if (max != 0 && (val < min || val > max))
541 as_bad_where (fixP->fx_file, fixP->fx_line, _ ("offset out of range"));
543 return 0;
546 /* Put number into target byte order. Always put values in an
547 executable section into big endian order. */
549 void
550 md_number_to_chars (ptr, use, nbytes)
551 char *ptr;
552 valueT use;
553 int nbytes;
555 if (target_big_endian || now_seg->flags & SEC_CODE)
556 number_to_chars_bigendian (ptr, use, nbytes);
557 else
558 number_to_chars_littleendian (ptr, use, nbytes);
563 /* Translate internal representation of relocation info to BFD target
564 format. */
566 arelent *
567 tc_gen_reloc (section, fixp)
568 asection *section ATTRIBUTE_UNUSED;
569 fixS *fixp;
571 arelent *rel;
572 bfd_reloc_code_real_type r_type;
574 rel = (arelent *) xmalloc (sizeof (arelent));
575 rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
576 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
577 rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
579 r_type = fixp->fx_r_type;
580 rel->addend = fixp->fx_addnumber;
581 rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
583 if (rel->howto == NULL)
585 as_bad_where (fixp->fx_file, fixp->fx_line,
586 _ ("Cannot represent relocation type %s"),
587 bfd_get_reloc_code_name (r_type));
588 /* Set howto to a garbage value so that we can keep going. */
589 rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
590 assert (rel->howto != NULL);
593 return rel;