]> Git Repo - binutils.git/blob - gas/config/tc-pj.c
This commit was generated by cvs2svn to track changes on a CVS vendor
[binutils.git] / gas / config / tc-pj.c
1 /*-
2    tc-pj.c -- Assemble code for Pico Java
3    Copyright (C) 1999 Free Software Foundation.
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
22 /* Contributed by Steve Chamberlain of Transmeta, [email protected] */
23
24 #include "as.h"
25 #include "opcode/pj.h"
26
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
38 static void
39 little (ignore)
40      int ignore ATTRIBUTE_UNUSED;
41 {
42   target_big_endian = 0;
43 }
44
45 static void
46 big (ignore)
47      int ignore ATTRIBUTE_UNUSED;
48 {
49   target_big_endian = 1;
50 }
51
52
53 const pseudo_typeS md_pseudo_table[] = {
54   {"ml",    little, 0},
55   {"mb",    big,    0},
56   {0, 0, 0}
57 };
58
59
60 const char FLT_CHARS[] = "rRsSfFdDxXpP";
61 const char EXP_CHARS[] = "eE";
62
63 void
64 md_operand (op)
65      expressionS *op;
66 {
67   if (strncmp (input_line_pointer, "%hi16", 5) == 0)
68     {
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);
74     }
75   if (strncmp (input_line_pointer, "%lo16", 5) == 0)
76     {
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);
82     }
83 }
84
85 /* Parse an expression and then restore the input line pointer. */
86
87 static char *
88 parse_exp_save_ilp (s, op)
89      char *s;
90      expressionS *op;
91 {
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;
98 }
99
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.  */
103
104 void
105 pj_cons_fix_new_pj (frag, where, nbytes, exp)
106      fragS *frag;
107      int where;
108      int nbytes;
109      expressionS *exp;
110 {
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 }};
117
118   fix_new_exp (frag, where, nbytes, exp, 0, 
119                pending_reloc ? pending_reloc
120                : rv [nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
121
122   pending_reloc = 0;
123 }
124
125
126 /* Turn a reloc description character from the pj-opc.h table into
127    code which BFD can handle. */
128
129 static int
130 c_to_r (x)
131      char x;
132 {
133   switch (x)
134     {
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;
149     }
150   abort ();
151   return 0;
152 }
153
154
155
156
157 /* Handler for the ipush fake opcode,
158    turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>. */
159
160 static void
161 ipush_code (opcode, str)
162      pj_opc_info_t *opcode ATTRIBUTE_UNUSED; 
163      char *str;
164 {
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"));
173
174
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);
179 }
180
181 /* Insert names into the opcode table which are really mini macros,
182    not opcodes.  The fakeness is inidicated with an opcode of -1. */
183
184 static void
185      fake_opcode (name, func) const char *
186        name;
187      void (*func) ();
188 {
189   pj_opc_info_t *fake = (pj_opc_info_t *) xmalloc (sizeof (pj_opc_info_t));
190
191   fake->opcode = -1;
192   fake->opcode_next = -1;
193   fake->name = (const char *) func;
194   hash_insert (opcode_hash_control, name, (char *) fake);
195 }
196
197
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;
204 {
205   hash_insert (opcode_hash_control, new,
206                (char *) hash_find (opcode_hash_control, old));
207 }
208
209
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. */
213
214 void
215 md_begin ()
216 {
217   const pj_opc_info_t *opcode;
218   opcode_hash_control = hash_new ();
219
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);
223
224   /* Insert the only fake opcode. */
225   fake_opcode ("ipush", ipush_code);
226
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");
235
236   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
237 }
238
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.
242  */
243
244 void
245 md_assemble (str)
246      char *str;
247 {
248   unsigned char *op_start;
249   unsigned char *op_end;
250
251   //  pj_operan_info operand[3];
252   pj_opc_info_t *opcode;
253   char *output;
254   int idx = 0;
255   char pend;
256
257   int nlen = 0;
258
259   /* Drop leading whitespace */
260   while (*str == ' ')
261     str++;
262
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++;
268
269   pend = *op_end;
270   *op_end = 0;
271
272   if (nlen == 0)
273     {
274       as_bad (_ ("can't find opcode "));
275     }
276
277   opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
278   *op_end = pend;
279
280   if (opcode == NULL)
281     {
282       as_bad (_ ("unknown opcode %s"), op_start);
283       return;
284     }
285
286   if (opcode->opcode == -1)
287     {
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);
291     }
292   else
293     {
294       int an;
295
296       output = frag_more (opcode->len);
297       output[idx++] = opcode->opcode;
298
299       if (opcode->opcode_next != -1)
300         output[idx++] = opcode->opcode_next;
301
302       for (an = 0; opcode->arg[an]; an++)
303         {
304           expressionS arg;
305
306           if (*op_end == ',' && an != 0)
307             op_end++;
308
309           if (*op_end == 0)
310             as_bad ("expected expresssion");
311
312           op_end = parse_exp_save_ilp (op_end, &arg);
313
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]));
320
321           idx += ASIZE (opcode->arg[an]);
322           pending_reloc = 0;
323         }
324
325       while (isspace (*op_end))
326         op_end++;
327
328       if (*op_end != 0)
329         as_warn ("extra stuff on line ignored");
330
331     }
332
333   if (pending_reloc)
334     as_bad ("Something forgot to clean up\n");
335
336 }
337
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.
341  */
342 char *
343 md_atof (type, litP, sizeP)
344      int type;
345      char *litP;
346      int *sizeP;
347 {
348   int prec;
349   LITTLENUM_TYPE words[4];
350   char *t;
351   int i;
352
353   switch (type)
354     {
355     case 'f':
356       prec = 2;
357       break;
358
359     case 'd':
360       prec = 4;
361       break;
362
363     default:
364       *sizeP = 0;
365       return _ ("bad call to md_atof");
366     }
367
368   t = atof_ieee (input_line_pointer, type, words);
369   if (t)
370     input_line_pointer = t;
371
372   *sizeP = prec * 2;
373
374   if (!target_big_endian)
375     {
376       for (i = prec - 1; i >= 0; i--)
377         {
378           md_number_to_chars (litP, (valueT) words[i], 2);
379           litP += 2;
380         }
381     }
382   else
383     {
384       for (i = 0; i < prec; i++)
385         {
386           md_number_to_chars (litP, (valueT) words[i], 2);
387           litP += 2;
388         }
389     }
390
391   return NULL;
392 }
393 \f
394
395 CONST char *md_shortopts = "";
396
397 struct option md_longopts[] = {
398
399 #define OPTION_LITTLE (OPTION_MD_BASE)
400 #define OPTION_BIG    (OPTION_LITTLE + 1)
401
402   {"little", no_argument, NULL, OPTION_LITTLE},
403   {"big", no_argument, NULL, OPTION_BIG},
404   {NULL, no_argument, NULL, 0}
405 };
406 size_t md_longopts_size = sizeof (md_longopts);
407
408 int
409 md_parse_option (c, arg)
410      int c;
411      char *arg ATTRIBUTE_UNUSED; 
412 {
413   switch (c)
414     {
415     case OPTION_LITTLE:
416       little ();
417       break;
418     case OPTION_BIG:
419       big ();
420       break;
421     default:
422       return 0;
423     }
424   return 1;
425 }
426
427 void
428 md_show_usage (stream)
429      FILE *stream;
430 {
431   fprintf (stream, _ ("\
432 PJ options:\n\
433 -little                 generate little endian code\n\
434 -big                    generate big endian code\n"));
435 }
436
437
438
439 /* Apply a fixup to the object file.  */
440
441
442 int
443 md_apply_fix (fixP, valp)
444      fixS *fixP;
445      valueT *valp;
446 {
447   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
448   long val = *valp;
449   long max, min;
450   int shift;
451
452
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.  */
457
458   if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
459     val -= S_GET_VALUE (fixP->fx_addsy);
460
461   max = min = 0;
462   shift = 0;
463   switch (fixP->fx_r_type)
464     {
465     case BFD_RELOC_VTABLE_INHERIT:
466     case BFD_RELOC_VTABLE_ENTRY:
467       fixP->fx_done = 0;
468       return 0;
469
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;
476
477     case BFD_RELOC_PJ_CODE_HI16:
478       *buf++ = val >> 24;
479       *buf++ = val >> 16;
480       fixP->fx_addnumber = val & 0xffff;
481       break;
482
483     case BFD_RELOC_PJ_CODE_DIR16:
484     case BFD_RELOC_PJ_CODE_LO16:
485       *buf++ = val >> 8;
486       *buf++ = val >> 0;
487
488       max = 0xffff;
489       min = -0xffff;
490       break;
491
492     case BFD_RELOC_8:
493       max = 0xff;
494       min = -0xff;
495       *buf++ = val;
496       break;
497
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;
504
505     case BFD_RELOC_32:
506       if (target_big_endian)
507         {
508           *buf++ = val >> 24;
509           *buf++ = val >> 16;
510           *buf++ = val >> 8;
511           *buf++ = val >> 0;
512         }
513       else 
514         {
515           *buf++ = val >> 0;
516           *buf++ = val >> 8;
517           *buf++ = val >> 16;
518           *buf++ = val >> 24;
519         }
520       break;
521
522     case BFD_RELOC_16:
523       if (target_big_endian)
524         {
525           *buf++ = val >> 8;
526           *buf++ = val >> 0;
527         }
528       else
529         {
530           *buf++ = val >> 0;
531           *buf++ = val >> 8;
532         }
533       break;
534
535
536     default:
537       abort ();
538     }
539
540   if (max != 0 && (val < min || val > max))
541     as_bad_where (fixP->fx_file, fixP->fx_line, _ ("offset out of range"));
542
543   return 0;
544 }
545
546 /* Put number into target byte order.  Always put values in an
547    executable section into big endian order. */
548
549 void
550 md_number_to_chars (ptr, use, nbytes)
551      char *ptr;
552      valueT use;
553      int nbytes;
554 {
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);
559 }
560
561
562
563 /* Translate internal representation of relocation info to BFD target
564    format. */
565
566 arelent *
567 tc_gen_reloc (section, fixp)
568      asection *section ATTRIBUTE_UNUSED;
569      fixS *fixp;
570 {
571   arelent *rel;
572   bfd_reloc_code_real_type r_type;
573
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;
578
579   r_type = fixp->fx_r_type;
580   rel->addend = fixp->fx_addnumber;
581   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
582
583   if (rel->howto == NULL)
584     {
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);
591     }
592
593   return rel;
594 }
This page took 0.056336 seconds and 4 git commands to generate.