Switch to GPLv3
[deliverable/binutils-gdb.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 /* Turn a string in input_line_pointer into a floating point constant
317 of type type, and store the appropriate bytes in *LITP. The number
318 of LITTLENUMS emitted is stored in *SIZEP . An error message is
319 returned, or NULL on OK. */
320
321 char *
322 md_atof (int type, char *litP, int *sizeP)
323 {
324 int prec;
325 LITTLENUM_TYPE words[4];
326 char *t;
327 int i;
328
329 switch (type)
330 {
331 case 'f':
332 prec = 2;
333 break;
334
335 case 'd':
336 prec = 4;
337 break;
338
339 default:
340 *sizeP = 0;
341 return _("bad call to md_atof");
342 }
343
344 t = atof_ieee (input_line_pointer, type, words);
345 if (t)
346 input_line_pointer = t;
347
348 *sizeP = prec * 2;
349
350 if (!target_big_endian)
351 {
352 for (i = prec - 1; i >= 0; i--)
353 {
354 md_number_to_chars (litP, (valueT) words[i], 2);
355 litP += 2;
356 }
357 }
358 else
359 {
360 for (i = 0; i < prec; i++)
361 {
362 md_number_to_chars (litP, (valueT) words[i], 2);
363 litP += 2;
364 }
365 }
366
367 return NULL;
368 }
369 \f
370 const char *md_shortopts = "";
371
372 struct option md_longopts[] =
373 {
374 #define OPTION_LITTLE (OPTION_MD_BASE)
375 #define OPTION_BIG (OPTION_LITTLE + 1)
376
377 {"little", no_argument, NULL, OPTION_LITTLE},
378 {"big", no_argument, NULL, OPTION_BIG},
379 {NULL, no_argument, NULL, 0}
380 };
381 size_t md_longopts_size = sizeof (md_longopts);
382
383 int
384 md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
385 {
386 switch (c)
387 {
388 case OPTION_LITTLE:
389 little (0);
390 break;
391 case OPTION_BIG:
392 big (0);
393 break;
394 default:
395 return 0;
396 }
397 return 1;
398 }
399
400 void
401 md_show_usage (FILE *stream)
402 {
403 fprintf (stream, _("\
404 PJ options:\n\
405 -little generate little endian code\n\
406 -big generate big endian code\n"));
407 }
408
409 /* Apply a fixup to the object file. */
410
411 void
412 md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
413 {
414 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
415 long val = *valP;
416 long max, min;
417 int shift;
418
419 max = min = 0;
420 shift = 0;
421 switch (fixP->fx_r_type)
422 {
423 case BFD_RELOC_VTABLE_INHERIT:
424 case BFD_RELOC_VTABLE_ENTRY:
425 fixP->fx_done = 0;
426 return;
427
428 case BFD_RELOC_PJ_CODE_REL16:
429 if (val < -0x8000 || val >= 0x7fff)
430 as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
431 buf[0] |= (val >> 8) & 0xff;
432 buf[1] = val & 0xff;
433 break;
434
435 case BFD_RELOC_PJ_CODE_HI16:
436 *buf++ = val >> 24;
437 *buf++ = val >> 16;
438 fixP->fx_addnumber = val & 0xffff;
439 break;
440
441 case BFD_RELOC_PJ_CODE_DIR16:
442 case BFD_RELOC_PJ_CODE_LO16:
443 *buf++ = val >> 8;
444 *buf++ = val >> 0;
445
446 max = 0xffff;
447 min = -0xffff;
448 break;
449
450 case BFD_RELOC_8:
451 max = 0xff;
452 min = -0xff;
453 *buf++ = val;
454 break;
455
456 case BFD_RELOC_PJ_CODE_DIR32:
457 *buf++ = val >> 24;
458 *buf++ = val >> 16;
459 *buf++ = val >> 8;
460 *buf++ = val >> 0;
461 break;
462
463 case BFD_RELOC_32:
464 if (target_big_endian)
465 {
466 *buf++ = val >> 24;
467 *buf++ = val >> 16;
468 *buf++ = val >> 8;
469 *buf++ = val >> 0;
470 }
471 else
472 {
473 *buf++ = val >> 0;
474 *buf++ = val >> 8;
475 *buf++ = val >> 16;
476 *buf++ = val >> 24;
477 }
478 break;
479
480 case BFD_RELOC_16:
481 if (target_big_endian)
482 {
483 *buf++ = val >> 8;
484 *buf++ = val >> 0;
485 }
486 else
487 {
488 *buf++ = val >> 0;
489 *buf++ = val >> 8;
490 }
491 break;
492
493 default:
494 abort ();
495 }
496
497 if (max != 0 && (val < min || val > max))
498 as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
499
500 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
501 fixP->fx_done = 1;
502 }
503
504 /* Put number into target byte order. Always put values in an
505 executable section into big endian order. */
506
507 void
508 md_number_to_chars (char *ptr, valueT use, int nbytes)
509 {
510 if (target_big_endian || now_seg->flags & SEC_CODE)
511 number_to_chars_bigendian (ptr, use, nbytes);
512 else
513 number_to_chars_littleendian (ptr, use, nbytes);
514 }
515
516 /* Translate internal representation of relocation info to BFD target
517 format. */
518
519 arelent *
520 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
521 {
522 arelent *rel;
523 bfd_reloc_code_real_type r_type;
524
525 rel = xmalloc (sizeof (arelent));
526 rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
527 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
528 rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
529
530 r_type = fixp->fx_r_type;
531 rel->addend = fixp->fx_addnumber;
532 rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
533
534 if (rel->howto == NULL)
535 {
536 as_bad_where (fixp->fx_file, fixp->fx_line,
537 _("Cannot represent relocation type %s"),
538 bfd_get_reloc_code_name (r_type));
539 /* Set howto to a garbage value so that we can keep going. */
540 rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
541 assert (rel->howto != NULL);
542 }
543
544 return rel;
545 }
This page took 0.040218 seconds and 4 git commands to generate.