2001-07-25 Chris Demetriou <cgd@broadcom.com>
[deliverable/binutils-gdb.git] / gas / config / tc-pj.c
CommitLineData
041dd5a9
ILT
1/*-
2 tc-pj.c -- Assemble code for Pico Java
f7e42eb4 3 Copyright 1999, 2000 Free Software Foundation, Inc.
041dd5a9
ILT
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 2, 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, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
a2429eb5 22/* Contributed by Steve Chamberlain of Transmeta <sac@pobox.com>. */
041dd5a9
ILT
23
24#include "as.h"
25#include "opcode/pj.h"
26
041dd5a9
ILT
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;
041dd5a9
ILT
35
36static void
37little (ignore)
38 int ignore ATTRIBUTE_UNUSED;
39{
40 target_big_endian = 0;
41}
42
43static void
44big (ignore)
45 int ignore ATTRIBUTE_UNUSED;
46{
47 target_big_endian = 1;
48}
49
041dd5a9
ILT
50const pseudo_typeS md_pseudo_table[] = {
51 {"ml", little, 0},
52 {"mb", big, 0},
53 {0, 0, 0}
54};
55
041dd5a9
ILT
56const char FLT_CHARS[] = "rRsSfFdDxXpP";
57const char EXP_CHARS[] = "eE";
58
59void
60md_operand (op)
61 expressionS *op;
62{
63 if (strncmp (input_line_pointer, "%hi16", 5) == 0)
64 {
65 if (pending_reloc)
a2429eb5 66 as_bad (_("confusing relocation expressions"));
041dd5a9
ILT
67 pending_reloc = BFD_RELOC_PJ_CODE_HI16;
68 input_line_pointer += 5;
69 expression (op);
70 }
71 if (strncmp (input_line_pointer, "%lo16", 5) == 0)
72 {
73 if (pending_reloc)
a2429eb5 74 as_bad (_("confusing relocation expressions"));
041dd5a9
ILT
75 pending_reloc = BFD_RELOC_PJ_CODE_LO16;
76 input_line_pointer += 5;
77 expression (op);
78 }
79}
80
a2429eb5 81/* Parse an expression and then restore the input line pointer. */
041dd5a9
ILT
82
83static char *
84parse_exp_save_ilp (s, op)
85 char *s;
86 expressionS *op;
87{
88 char *save = input_line_pointer;
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 (frag, where, nbytes, exp)
102 fragS *frag;
103 int where;
104 int nbytes;
105 expressionS *exp;
106{
a2429eb5 107 static int rv[5][2] =
041dd5a9
ILT
108 { { 0, 0 },
109 { BFD_RELOC_8, BFD_RELOC_8 },
110 { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
111 { 0, 0 },
112 { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
113
a2429eb5 114 fix_new_exp (frag, where, nbytes, exp, 0,
041dd5a9 115 pending_reloc ? pending_reloc
a2429eb5 116 : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
041dd5a9
ILT
117
118 pending_reloc = 0;
119}
120
041dd5a9 121/* Turn a reloc description character from the pj-opc.h table into
a2429eb5 122 code which BFD can handle. */
041dd5a9
ILT
123
124static int
125c_to_r (x)
126 char x;
127{
128 switch (x)
129 {
130 case O_R8:
131 return BFD_RELOC_8_PCREL;
132 case O_U8:
133 case O_8:
134 return BFD_RELOC_8;
135 case O_R16:
136 return BFD_RELOC_PJ_CODE_REL16;
137 case O_U16:
138 case O_16:
139 return BFD_RELOC_PJ_CODE_DIR16;
140 case O_R32:
141 return BFD_RELOC_PJ_CODE_REL32;
142 case O_32:
143 return BFD_RELOC_PJ_CODE_DIR32;
144 }
145 abort ();
146 return 0;
147}
148
041dd5a9 149/* Handler for the ipush fake opcode,
a2429eb5 150 turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>. */
041dd5a9
ILT
151
152static void
153ipush_code (opcode, str)
a2429eb5 154 pj_opc_info_t *opcode ATTRIBUTE_UNUSED;
041dd5a9
ILT
155 char *str;
156{
157 int mod = 0;
158 char *b = frag_more (6);
159 expressionS arg;
a2429eb5 160
041dd5a9
ILT
161 b[0] = 0x11;
162 b[3] = 0xed;
163 parse_exp_save_ilp (str + 1, &arg, &mod);
164 if (mod)
a2429eb5 165 as_bad (_("can't have relocation for ipush"));
041dd5a9 166
a2429eb5
NC
167 fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
168 &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
041dd5a9 169 fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
a2429eb5 170 &arg, 0, BFD_RELOC_PJ_CODE_HI16);
041dd5a9
ILT
171}
172
173/* Insert names into the opcode table which are really mini macros,
a2429eb5 174 not opcodes. The fakeness is inidicated with an opcode of -1. */
041dd5a9
ILT
175
176static void
a2429eb5
NC
177fake_opcode (name, func)
178 const char *name;
041dd5a9
ILT
179 void (*func) ();
180{
181 pj_opc_info_t *fake = (pj_opc_info_t *) xmalloc (sizeof (pj_opc_info_t));
182
183 fake->opcode = -1;
184 fake->opcode_next = -1;
185 fake->name = (const char *) func;
186 hash_insert (opcode_hash_control, name, (char *) fake);
187}
188
041dd5a9 189/* Enter another entry into the opcode hash table so the same opcode
a2429eb5
NC
190 can have another name. */
191
041dd5a9 192static void
a2429eb5
NC
193alias (new, old)
194 const char *new;
041dd5a9
ILT
195 const char *old;
196{
197 hash_insert (opcode_hash_control, new,
198 (char *) hash_find (opcode_hash_control, old));
199}
200
041dd5a9
ILT
201/* This function is called once, at assembler startup time. It sets
202 up the hash table with all the opcodes in it, and also initializes
a2429eb5 203 some aliases for compatibility with other assemblers. */
041dd5a9
ILT
204
205void
206md_begin ()
207{
208 const pj_opc_info_t *opcode;
209 opcode_hash_control = hash_new ();
210
a2429eb5 211 /* Insert names into hash table. */
041dd5a9
ILT
212 for (opcode = pj_opc_info; opcode->name; opcode++)
213 hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
214
a2429eb5 215 /* Insert the only fake opcode. */
041dd5a9
ILT
216 fake_opcode ("ipush", ipush_code);
217
a2429eb5 218 /* Add some aliases for opcode names. */
041dd5a9
ILT
219 alias ("ifeq_s", "ifeq");
220 alias ("ifne_s", "ifne");
221 alias ("if_icmpge_s", "if_icmpge");
222 alias ("if_icmpne_s", "if_icmpne");
223 alias ("if_icmpeq_s", "if_icmpeq");
224 alias ("if_icmpgt_s", "if_icmpgt");
225 alias ("goto_s", "goto");
226
227 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
228}
229
a2429eb5
NC
230/* This is the guts of the machine-dependent assembler. STR points to
231 a machine dependent instruction. This function is supposed to emit
232 the frags/bytes it assembles to. */
041dd5a9
ILT
233
234void
235md_assemble (str)
236 char *str;
237{
238 unsigned char *op_start;
239 unsigned char *op_end;
240
a2429eb5
NC
241#if 0
242 pj_operan_info operand[3];
243#endif
041dd5a9
ILT
244 pj_opc_info_t *opcode;
245 char *output;
246 int idx = 0;
247 char pend;
248
249 int nlen = 0;
250
a2429eb5 251 /* Drop leading whitespace. */
041dd5a9
ILT
252 while (*str == ' ')
253 str++;
254
a2429eb5 255 /* Find the op code end. */
041dd5a9
ILT
256 for (op_start = op_end = (unsigned char *) (str);
257 *op_end && !is_end_of_line[*op_end] && *op_end != ' ';
a2429eb5 258 op_end++)
041dd5a9
ILT
259 nlen++;
260
261 pend = *op_end;
262 *op_end = 0;
263
264 if (nlen == 0)
a2429eb5 265 as_bad (_("can't find opcode "));
041dd5a9
ILT
266
267 opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
268 *op_end = pend;
269
270 if (opcode == NULL)
271 {
a2429eb5 272 as_bad (_("unknown opcode %s"), op_start);
041dd5a9
ILT
273 return;
274 }
275
276 if (opcode->opcode == -1)
277 {
a2429eb5
NC
278 /* It's a fake opcode. Dig out the args and pretend that was
279 what we were passed. */
bc805888 280 ((void (*) ()) opcode->name) (opcode, op_end);
041dd5a9
ILT
281 }
282 else
283 {
284 int an;
285
286 output = frag_more (opcode->len);
287 output[idx++] = opcode->opcode;
288
289 if (opcode->opcode_next != -1)
290 output[idx++] = opcode->opcode_next;
291
292 for (an = 0; opcode->arg[an]; an++)
293 {
294 expressionS arg;
295
296 if (*op_end == ',' && an != 0)
297 op_end++;
298
299 if (*op_end == 0)
300 as_bad ("expected expresssion");
301
302 op_end = parse_exp_save_ilp (op_end, &arg);
303
a2429eb5 304 fix_new_exp (frag_now,
041dd5a9
ILT
305 output - frag_now->fr_literal + idx,
306 ASIZE (opcode->arg[an]),
307 &arg,
a2429eb5 308 PCREL (opcode->arg[an]),
041dd5a9
ILT
309 pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
310
311 idx += ASIZE (opcode->arg[an]);
312 pending_reloc = 0;
313 }
314
315 while (isspace (*op_end))
316 op_end++;
317
318 if (*op_end != 0)
319 as_warn ("extra stuff on line ignored");
320
321 }
322
323 if (pending_reloc)
324 as_bad ("Something forgot to clean up\n");
325
326}
327
a2429eb5
NC
328/* Turn a string in input_line_pointer into a floating point constant
329 of type type, and store the appropriate bytes in *LITP. The number
330 of LITTLENUMS emitted is stored in *SIZEP . An error message is
331 returned, or NULL on OK. */
332
041dd5a9
ILT
333char *
334md_atof (type, litP, sizeP)
335 int type;
336 char *litP;
337 int *sizeP;
338{
339 int prec;
340 LITTLENUM_TYPE words[4];
341 char *t;
342 int i;
343
344 switch (type)
345 {
346 case 'f':
347 prec = 2;
348 break;
349
350 case 'd':
351 prec = 4;
352 break;
353
354 default:
355 *sizeP = 0;
a2429eb5 356 return _("bad call to md_atof");
041dd5a9
ILT
357 }
358
359 t = atof_ieee (input_line_pointer, type, words);
360 if (t)
361 input_line_pointer = t;
362
363 *sizeP = prec * 2;
364
365 if (!target_big_endian)
366 {
367 for (i = prec - 1; i >= 0; i--)
368 {
369 md_number_to_chars (litP, (valueT) words[i], 2);
370 litP += 2;
371 }
372 }
373 else
374 {
375 for (i = 0; i < prec; i++)
376 {
377 md_number_to_chars (litP, (valueT) words[i], 2);
378 litP += 2;
379 }
380 }
381
382 return NULL;
383}
384\f
041dd5a9
ILT
385CONST char *md_shortopts = "";
386
387struct option md_longopts[] = {
388
389#define OPTION_LITTLE (OPTION_MD_BASE)
390#define OPTION_BIG (OPTION_LITTLE + 1)
391
392 {"little", no_argument, NULL, OPTION_LITTLE},
393 {"big", no_argument, NULL, OPTION_BIG},
394 {NULL, no_argument, NULL, 0}
395};
396size_t md_longopts_size = sizeof (md_longopts);
397
398int
399md_parse_option (c, arg)
400 int c;
a2429eb5 401 char *arg ATTRIBUTE_UNUSED;
041dd5a9
ILT
402{
403 switch (c)
404 {
405 case OPTION_LITTLE:
406 little ();
407 break;
408 case OPTION_BIG:
409 big ();
410 break;
411 default:
412 return 0;
413 }
414 return 1;
415}
416
417void
418md_show_usage (stream)
419 FILE *stream;
420{
a2429eb5 421 fprintf (stream, _("\
041dd5a9
ILT
422PJ options:\n\
423-little generate little endian code\n\
424-big generate big endian code\n"));
425}
426
041dd5a9
ILT
427/* Apply a fixup to the object file. */
428
041dd5a9
ILT
429int
430md_apply_fix (fixP, valp)
431 fixS *fixP;
432 valueT *valp;
433{
434 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
435 long val = *valp;
436 long max, min;
437 int shift;
438
041dd5a9
ILT
439 /* adjust_reloc_syms won't convert a reloc against a weak symbol
440 into a reloc against a section, but bfd_install_relocation will
441 screw up if the symbol is defined, so we have to adjust val here
442 to avoid the screw up later. */
443
444 if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
445 val -= S_GET_VALUE (fixP->fx_addsy);
446
447 max = min = 0;
448 shift = 0;
449 switch (fixP->fx_r_type)
450 {
451 case BFD_RELOC_VTABLE_INHERIT:
452 case BFD_RELOC_VTABLE_ENTRY:
453 fixP->fx_done = 0;
454 return 0;
455
456 case BFD_RELOC_PJ_CODE_REL16:
457 if (val < -0x8000 || val >= 0x7fff)
a2429eb5 458 as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
041dd5a9
ILT
459 buf[0] |= (val >> 8) & 0xff;
460 buf[1] = val & 0xff;
461 break;
462
463 case BFD_RELOC_PJ_CODE_HI16:
464 *buf++ = val >> 24;
465 *buf++ = val >> 16;
466 fixP->fx_addnumber = val & 0xffff;
467 break;
468
469 case BFD_RELOC_PJ_CODE_DIR16:
470 case BFD_RELOC_PJ_CODE_LO16:
471 *buf++ = val >> 8;
472 *buf++ = val >> 0;
473
474 max = 0xffff;
475 min = -0xffff;
476 break;
477
478 case BFD_RELOC_8:
479 max = 0xff;
480 min = -0xff;
481 *buf++ = val;
482 break;
483
484 case BFD_RELOC_PJ_CODE_DIR32:
485 *buf++ = val >> 24;
486 *buf++ = val >> 16;
487 *buf++ = val >> 8;
488 *buf++ = val >> 0;
489 break;
490
491 case BFD_RELOC_32:
492 if (target_big_endian)
493 {
494 *buf++ = val >> 24;
495 *buf++ = val >> 16;
496 *buf++ = val >> 8;
497 *buf++ = val >> 0;
498 }
a2429eb5 499 else
041dd5a9
ILT
500 {
501 *buf++ = val >> 0;
502 *buf++ = val >> 8;
503 *buf++ = val >> 16;
504 *buf++ = val >> 24;
505 }
506 break;
507
508 case BFD_RELOC_16:
509 if (target_big_endian)
510 {
511 *buf++ = val >> 8;
512 *buf++ = val >> 0;
513 }
514 else
515 {
516 *buf++ = val >> 0;
517 *buf++ = val >> 8;
518 }
519 break;
520
041dd5a9
ILT
521 default:
522 abort ();
523 }
524
525 if (max != 0 && (val < min || val > max))
a2429eb5 526 as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
041dd5a9
ILT
527
528 return 0;
529}
530
531/* Put number into target byte order. Always put values in an
a2429eb5 532 executable section into big endian order. */
041dd5a9
ILT
533
534void
535md_number_to_chars (ptr, use, nbytes)
536 char *ptr;
537 valueT use;
538 int nbytes;
539{
540 if (target_big_endian || now_seg->flags & SEC_CODE)
541 number_to_chars_bigendian (ptr, use, nbytes);
542 else
543 number_to_chars_littleendian (ptr, use, nbytes);
544}
545
041dd5a9 546/* Translate internal representation of relocation info to BFD target
a2429eb5 547 format. */
041dd5a9
ILT
548
549arelent *
550tc_gen_reloc (section, fixp)
551 asection *section ATTRIBUTE_UNUSED;
552 fixS *fixp;
553{
554 arelent *rel;
555 bfd_reloc_code_real_type r_type;
556
557 rel = (arelent *) xmalloc (sizeof (arelent));
558 rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
559 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
560 rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
561
562 r_type = fixp->fx_r_type;
563 rel->addend = fixp->fx_addnumber;
564 rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
565
566 if (rel->howto == NULL)
567 {
568 as_bad_where (fixp->fx_file, fixp->fx_line,
a2429eb5 569 _("Cannot represent relocation type %s"),
041dd5a9
ILT
570 bfd_get_reloc_code_name (r_type));
571 /* Set howto to a garbage value so that we can keep going. */
572 rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
573 assert (rel->howto != NULL);
574 }
575
576 return rel;
577}
This page took 0.102003 seconds and 4 git commands to generate.