Fix formatting.
[deliverable/binutils-gdb.git] / gas / config / tc-pj.c
CommitLineData
041dd5a9
ILT
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, sac@pobox.com */
23
24#include "as.h"
25#include "opcode/pj.h"
26
27
28extern const pj_opc_info_t pj_opc_info[512];
29
30const char comment_chars[] = "!/";
31const char line_separator_chars[] = ";";
32const char line_comment_chars[] = "/!#";
33
34static int pending_reloc;
35static struct hash_control *opcode_hash_control;
36
37
38static void
39little (ignore)
40 int ignore ATTRIBUTE_UNUSED;
41{
42 target_big_endian = 0;
43}
44
45static void
46big (ignore)
47 int ignore ATTRIBUTE_UNUSED;
48{
49 target_big_endian = 1;
50}
51
52
53const pseudo_typeS md_pseudo_table[] = {
54 {"ml", little, 0},
55 {"mb", big, 0},
56 {0, 0, 0}
57};
58
59
60const char FLT_CHARS[] = "rRsSfFdDxXpP";
61const char EXP_CHARS[] = "eE";
62
63void
64md_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
87static char *
88parse_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
104void
105pj_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
129static int
130c_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
160static void
161ipush_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
184static 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. */
200static 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
214void
215md_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
244void
245md_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 */
342char *
343md_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
395CONST char *md_shortopts = "";
396
397struct 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};
406size_t md_longopts_size = sizeof (md_longopts);
407
408int
409md_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
427void
428md_show_usage (stream)
429 FILE *stream;
430{
431 fprintf (stream, _ ("\
432PJ 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
442int
443md_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
549void
550md_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
566arelent *
567tc_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.062919 seconds and 4 git commands to generate.