Commit | Line | Data |
---|---|---|
3b16e843 | 1 | /* Assembly backend for the OpenRISC 1000. |
aef6203b | 2 | Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. |
3b16e843 NC |
3 | Contributed by Damjan Lampret <lampret@opencores.org>. |
4 | Modified bu Johan Rydberg, <johan.rydberg@netinsight.se>. | |
5 | Based upon a29k port. | |
6 | ||
7 | This file is part of GAS, the GNU Assembler. | |
8 | ||
9 | GAS is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GAS is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GAS; see the file COPYING. If not, write to | |
4b4da160 NC |
21 | the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
22 | Boston, MA 02110-1301, USA. */ | |
3b16e843 NC |
23 | |
24 | /* tc-a29k.c used as a template. */ | |
25 | ||
26 | #include "safe-ctype.h" | |
27 | #include "as.h" | |
28 | #include "opcode/or32.h" | |
5d6255fe | 29 | #include "elf/or32.h" |
3b16e843 NC |
30 | |
31 | #define DEBUG 0 | |
32 | ||
33 | #ifndef REGISTER_PREFIX | |
34 | #define REGISTER_PREFIX '%' | |
35 | #endif | |
36 | ||
37 | /* Make it easier to clone this machine desc into another one. */ | |
38 | #define machine_opcode or32_opcode | |
39 | #define machine_opcodes or32_opcodes | |
40 | #define machine_ip or32_ip | |
41 | #define machine_it or32_it | |
42 | ||
43 | /* Handle of the OPCODE hash table. */ | |
44 | static struct hash_control *op_hash = NULL; | |
45 | ||
46 | struct machine_it | |
ea1562b3 NC |
47 | { |
48 | char * error; | |
49 | unsigned long opcode; | |
50 | struct nlist * nlistp; | |
51 | expressionS exp; | |
52 | int pcrel; | |
53 | int reloc_offset; /* Offset of reloc within insn. */ | |
54 | int reloc; | |
55 | } | |
3b16e843 NC |
56 | the_insn; |
57 | ||
3b16e843 | 58 | const pseudo_typeS md_pseudo_table[] = |
ea1562b3 NC |
59 | { |
60 | {"align", s_align_bytes, 4 }, | |
61 | {"space", s_space, 0 }, | |
62 | {"cputype", s_ignore, 0 }, | |
63 | {"reg", s_lsym, 0 }, /* Register equate, same as equ. */ | |
64 | {"sect", s_ignore, 0 }, /* Creation of coff sections. */ | |
65 | {"proc", s_ignore, 0 }, /* Start of a function. */ | |
66 | {"endproc", s_ignore, 0 }, /* Function end. */ | |
67 | {"word", cons, 4 }, | |
68 | {NULL, 0, 0 }, | |
69 | }; | |
3b16e843 NC |
70 | |
71 | int md_short_jump_size = 4; | |
72 | int md_long_jump_size = 4; | |
73 | ||
3b16e843 NC |
74 | /* This array holds the chars that always start a comment. |
75 | If the pre-processor is disabled, these aren't very useful. */ | |
76 | const char comment_chars[] = "#"; | |
77 | ||
78 | /* This array holds the chars that only start a comment at the beginning of | |
79 | a line. If the line seems to have the form '# 123 filename' | |
80 | .line and .file directives will appear in the pre-processed output. */ | |
81 | /* Note that input_file.c hand checks for '#' at the beginning of the | |
82 | first line of the input file. This is because the compiler outputs | |
83 | #NO_APP at the beginning of its output. */ | |
84 | /* Also note that comments like this one will always work. */ | |
85 | const char line_comment_chars[] = "#"; | |
86 | ||
87 | /* We needed an unused char for line separation to work around the | |
88 | lack of macros, using sed and such. */ | |
89 | const char line_separator_chars[] = ";"; | |
90 | ||
91 | /* Chars that can be used to separate mant from exp in floating point nums. */ | |
92 | const char EXP_CHARS[] = "eE"; | |
93 | ||
94 | /* Chars that mean this number is a floating point constant. | |
95 | As in 0f12.456 | |
96 | or 0d1.2345e12. */ | |
97 | const char FLT_CHARS[] = "rRsSfFdDxXpP"; | |
98 | ||
99 | /* "l.jalr r9" precalculated opcode. */ | |
100 | static unsigned long jalr_r9_opcode; | |
101 | ||
ea1562b3 | 102 | static void machine_ip (char *); |
3b16e843 | 103 | |
3b16e843 NC |
104 | |
105 | /* Set bits in machine opcode according to insn->encoding | |
5d6255fe | 106 | description and passed operand. */ |
3b16e843 | 107 | |
5d6255fe | 108 | static void |
ea1562b3 NC |
109 | encode (const struct machine_opcode *insn, |
110 | unsigned long *opcode, | |
111 | signed long param_val, | |
112 | char param_ch) | |
3b16e843 NC |
113 | { |
114 | int opc_pos = 0; | |
115 | int param_pos = 0; | |
116 | char *enc; | |
117 | ||
118 | #if DEBUG | |
119 | printf (" encode: opcode=%.8lx param_val=%.8lx abs=%.8lx param_ch=%c\n", | |
120 | *opcode, param_val, abs (param_val), param_ch); | |
121 | #endif | |
122 | for (enc = insn->encoding; *enc != '\0'; enc++) | |
123 | if (*enc == param_ch) | |
124 | { | |
125 | if (enc - 2 >= insn->encoding && (*(enc - 2) == '0') && (*(enc - 1) == 'x')) | |
126 | continue; | |
127 | else | |
128 | param_pos ++; | |
129 | } | |
130 | ||
131 | opc_pos = 32; | |
132 | ||
133 | for (enc = insn->encoding; *enc != '\0';) | |
134 | { | |
5d6255fe | 135 | if ((*enc == '0') && (*(enc + 1) == 'x')) |
3b16e843 NC |
136 | { |
137 | int tmp = strtol (enc, NULL, 16); | |
138 | ||
139 | opc_pos -= 4; | |
140 | *opcode |= tmp << opc_pos; | |
141 | enc += 3; | |
142 | } | |
5d6255fe | 143 | else if ((*enc == '0') || (*enc == '-')) |
3b16e843 NC |
144 | { |
145 | opc_pos--; | |
146 | enc++; | |
147 | } | |
5d6255fe | 148 | else if (*enc == '1') |
3b16e843 NC |
149 | { |
150 | opc_pos--; | |
151 | *opcode |= 1 << opc_pos; | |
152 | enc++; | |
153 | } | |
5d6255fe | 154 | else if (*enc == param_ch) |
3b16e843 NC |
155 | { |
156 | opc_pos--; | |
157 | param_pos--; | |
158 | *opcode |= ((param_val >> param_pos) & 0x1) << opc_pos; | |
159 | enc++; | |
160 | } | |
5d6255fe | 161 | else if (ISALPHA (*enc)) |
3b16e843 NC |
162 | { |
163 | opc_pos--; | |
164 | enc++; | |
165 | } | |
166 | else | |
167 | enc++; | |
168 | } | |
5d6255fe | 169 | |
3b16e843 NC |
170 | #if DEBUG |
171 | printf (" opcode=%.8lx\n", *opcode); | |
172 | #endif | |
173 | } | |
174 | ||
175 | /* This function is called once, at assembler startup time. It should | |
176 | set up all the tables, etc., that the MD part of the assembler will | |
177 | need. */ | |
178 | ||
179 | void | |
ea1562b3 | 180 | md_begin (void) |
3b16e843 NC |
181 | { |
182 | const char *retval = NULL; | |
183 | int lose = 0; | |
184 | int skipnext = 0; | |
185 | unsigned int i; | |
186 | ||
187 | /* Hash up all the opcodes for fast use later. */ | |
188 | op_hash = hash_new (); | |
189 | ||
190 | for (i = 0; i < or32_num_opcodes; i++) | |
191 | { | |
192 | const char *name = machine_opcodes[i].name; | |
193 | ||
194 | if (skipnext) | |
195 | { | |
196 | skipnext = 0; | |
197 | continue; | |
198 | } | |
199 | ||
ea1562b3 | 200 | retval = hash_insert (op_hash, name, (void *) &machine_opcodes[i]); |
3b16e843 NC |
201 | if (retval != NULL) |
202 | { | |
203 | fprintf (stderr, "internal error: can't hash `%s': %s\n", | |
204 | machine_opcodes[i].name, retval); | |
205 | lose = 1; | |
206 | } | |
207 | } | |
208 | ||
209 | if (lose) | |
210 | as_fatal (_("Broken assembler. No assembly attempted.")); | |
211 | ||
212 | encode (&machine_opcodes[insn_index ("l.jalr")], &jalr_r9_opcode, 9, 'B'); | |
213 | } | |
214 | ||
67c1ffbe | 215 | /* Returns non zero if instruction is to be used. */ |
3b16e843 NC |
216 | |
217 | static int | |
ea1562b3 | 218 | check_invalid_opcode (unsigned long opcode) |
3b16e843 NC |
219 | { |
220 | return opcode == jalr_r9_opcode; | |
221 | } | |
222 | ||
223 | /* Assemble a single instruction. Its label has already been handled | |
224 | by the generic front end. We just parse opcode and operands, and | |
225 | produce the bytes of data and relocation. */ | |
226 | ||
227 | void | |
ea1562b3 | 228 | md_assemble (char *str) |
3b16e843 NC |
229 | { |
230 | char *toP; | |
231 | ||
232 | #if DEBUG | |
233 | printf ("NEW INSTRUCTION\n"); | |
234 | #endif | |
235 | ||
236 | know (str); | |
237 | machine_ip (str); | |
238 | toP = frag_more (4); | |
239 | ||
240 | /* Put out the opcode. */ | |
241 | md_number_to_chars (toP, the_insn.opcode, 4); | |
242 | ||
243 | /* Put out the symbol-dependent stuff. */ | |
3b16e843 | 244 | if (the_insn.reloc != BFD_RELOC_NONE) |
3b16e843 NC |
245 | { |
246 | fix_new_exp (frag_now, | |
247 | (toP - frag_now->fr_literal + the_insn.reloc_offset), | |
248 | 4, /* size */ | |
249 | &the_insn.exp, | |
250 | the_insn.pcrel, | |
251 | the_insn.reloc); | |
252 | } | |
253 | } | |
254 | ||
255 | /* This is true of the we have issued a "lo(" or "hi"(. */ | |
256 | static int waiting_for_shift = 0; | |
257 | ||
258 | static int mask_or_shift = 0; | |
259 | ||
3b16e843 | 260 | static char * |
ea1562b3 | 261 | parse_operand (char *s, expressionS *operandp, int opt) |
3b16e843 NC |
262 | { |
263 | char *save = input_line_pointer; | |
264 | char *new; | |
265 | ||
266 | #if DEBUG | |
267 | printf (" PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt); | |
268 | #endif | |
269 | ||
270 | input_line_pointer = s; | |
271 | ||
272 | if (strncasecmp (s, "HI(", 3) == 0) | |
273 | { | |
274 | waiting_for_shift = 1; | |
275 | mask_or_shift = BFD_RELOC_HI16; | |
276 | ||
277 | input_line_pointer += 3; | |
278 | } | |
279 | else if (strncasecmp (s, "LO(", 3) == 0) | |
280 | { | |
281 | mask_or_shift = BFD_RELOC_LO16; | |
282 | ||
283 | input_line_pointer += 3; | |
284 | } | |
285 | else | |
286 | mask_or_shift = 0; | |
287 | ||
288 | if ((*s == '(') && (*(s+1) == 'r')) | |
289 | s++; | |
290 | ||
5d6255fe | 291 | if ((*s == 'r') && ISDIGIT (*(s + 1))) |
3b16e843 NC |
292 | { |
293 | operandp->X_add_number = strtol (s + 1, NULL, 10); | |
294 | operandp->X_op = O_register; | |
295 | for (; (*s != ',') && (*s != '\0');) | |
5d6255fe | 296 | s++; |
3b16e843 | 297 | input_line_pointer = save; |
5d6255fe | 298 | return s; |
3b16e843 NC |
299 | } |
300 | ||
301 | expression (operandp); | |
302 | ||
303 | if (operandp->X_op == O_absent) | |
304 | { | |
305 | if (! opt) | |
306 | as_bad (_("missing operand")); | |
307 | else | |
308 | { | |
309 | operandp->X_add_number = 0; | |
310 | operandp->X_op = O_constant; | |
311 | } | |
312 | } | |
5d6255fe | 313 | |
3b16e843 NC |
314 | new = input_line_pointer; |
315 | input_line_pointer = save; | |
5d6255fe | 316 | |
3b16e843 NC |
317 | #if DEBUG |
318 | printf (" %s=parse_operand(%s): operandp->X_op = %u\n", new, s, operandp->X_op); | |
319 | #endif | |
320 | ||
321 | return new; | |
322 | } | |
3b16e843 NC |
323 | |
324 | /* Instruction parsing. Takes a string containing the opcode. | |
325 | Operands are at input_line_pointer. Output is in the_insn. | |
326 | Warnings or errors are generated. */ | |
327 | ||
3b16e843 | 328 | static void |
ea1562b3 | 329 | machine_ip (char *str) |
3b16e843 NC |
330 | { |
331 | char *s; | |
332 | const char *args; | |
333 | const struct machine_opcode *insn; | |
334 | char *argsStart; | |
335 | unsigned long opcode; | |
336 | expressionS the_operand; | |
337 | expressionS *operand = &the_operand; | |
338 | unsigned int regno; | |
339 | int reloc = BFD_RELOC_NONE; | |
340 | ||
341 | #if DEBUG | |
342 | printf ("machine_ip(%s)\n", str); | |
343 | #endif | |
344 | ||
345 | s = str; | |
346 | for (; ISALNUM (*s) || *s == '.'; ++s) | |
347 | if (ISUPPER (*s)) | |
348 | *s = TOLOWER (*s); | |
349 | ||
350 | switch (*s) | |
351 | { | |
352 | case '\0': | |
353 | break; | |
354 | ||
355 | case ' ': /* FIXME-SOMEDAY more whitespace. */ | |
356 | *s++ = '\0'; | |
357 | break; | |
358 | ||
359 | default: | |
360 | as_bad (_("unknown opcode1: `%s'"), str); | |
361 | return; | |
362 | } | |
363 | ||
364 | if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL) | |
365 | { | |
366 | as_bad (_("unknown opcode2 `%s'."), str); | |
367 | return; | |
368 | } | |
369 | ||
370 | argsStart = s; | |
371 | opcode = 0; | |
372 | memset (&the_insn, '\0', sizeof (the_insn)); | |
373 | the_insn.reloc = BFD_RELOC_NONE; | |
374 | ||
375 | reloc = BFD_RELOC_NONE; | |
376 | ||
377 | /* Build the opcode, checking as we go to make sure that the | |
378 | operands match. | |
5d6255fe | 379 | |
3b16e843 NC |
380 | If an operand matches, we modify the_insn or opcode appropriately, |
381 | and do a "continue". If an operand fails to match, we "break". */ | |
382 | if (insn->args[0] != '\0') | |
ea1562b3 NC |
383 | /* Prime the pump. */ |
384 | s = parse_operand (s, operand, insn->args[0] == 'I'); | |
3b16e843 NC |
385 | |
386 | for (args = insn->args;; ++args) | |
387 | { | |
388 | #if DEBUG | |
389 | printf (" args = %s\n", args); | |
390 | #endif | |
391 | switch (*args) | |
392 | { | |
393 | case '\0': /* End of args. */ | |
394 | /* We have have 0 args, do the bazoooka! */ | |
395 | if (args == insn->args) | |
396 | encode (insn, &opcode, 0, 0); | |
397 | ||
398 | if (*s == '\0') | |
399 | { | |
400 | /* We are truly done. */ | |
401 | the_insn.opcode = opcode; | |
402 | if (check_invalid_opcode (opcode)) | |
5d6255fe | 403 | as_bad (_("instruction not allowed: %s"), str); |
3b16e843 NC |
404 | return; |
405 | } | |
406 | as_bad (_("too many operands: %s"), s); | |
407 | break; | |
408 | ||
409 | case ',': /* Must match a comma. */ | |
410 | if (*s++ == ',') | |
411 | { | |
412 | reloc = BFD_RELOC_NONE; | |
413 | ||
414 | /* Parse next operand. */ | |
415 | s = parse_operand (s, operand, args[1] == 'I'); | |
416 | #if DEBUG | |
417 | printf (" ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n", | |
418 | operand->X_add_number, args, s); | |
5d6255fe | 419 | #endif |
3b16e843 NC |
420 | continue; |
421 | } | |
422 | break; | |
423 | ||
424 | case '(': /* Must match a (. */ | |
425 | s = parse_operand (s, operand, args[1] == 'I'); | |
426 | continue; | |
5d6255fe | 427 | |
3b16e843 NC |
428 | case ')': /* Must match a ). */ |
429 | continue; | |
430 | ||
431 | case 'r': /* A general register. */ | |
432 | args++; | |
433 | ||
434 | if (operand->X_op != O_register) | |
435 | break; /* Only registers. */ | |
5d6255fe | 436 | |
3b16e843 NC |
437 | know (operand->X_add_symbol == 0); |
438 | know (operand->X_op_symbol == 0); | |
439 | regno = operand->X_add_number; | |
440 | encode (insn, &opcode, regno, *args); | |
441 | #if DEBUG | |
442 | printf (" r: operand->X_op = %d\n", operand->X_op); | |
443 | #endif | |
444 | continue; | |
445 | ||
446 | default: | |
447 | /* if (! ISALPHA (*args)) | |
448 | break; */ /* Only immediate values. */ | |
5d6255fe | 449 | |
3b16e843 NC |
450 | if (mask_or_shift) |
451 | { | |
452 | #if DEBUG | |
453 | printf ("mask_or_shift = %d\n", mask_or_shift); | |
454 | #endif | |
455 | reloc = mask_or_shift; | |
456 | } | |
457 | mask_or_shift = 0; | |
5d6255fe KH |
458 | |
459 | if (strncasecmp (args, "LO(", 3) == 0) | |
3b16e843 NC |
460 | { |
461 | #if DEBUG | |
462 | printf ("reloc_const\n"); | |
463 | #endif | |
464 | reloc = BFD_RELOC_LO16; | |
465 | } | |
5d6255fe | 466 | else if (strncasecmp (args, "HI(", 3) == 0) |
3b16e843 NC |
467 | { |
468 | #if DEBUG | |
469 | printf ("reloc_consth\n"); | |
470 | #endif | |
471 | reloc = BFD_RELOC_HI16; | |
472 | } | |
5d6255fe KH |
473 | |
474 | if (*s == '(') | |
ea1562b3 | 475 | operand->X_op = O_constant; |
3b16e843 NC |
476 | else if (*s == ')') |
477 | s += 1; | |
478 | #if DEBUG | |
479 | printf (" default case: operand->X_add_number = %d, *args = %s, *s = %s\n", operand->X_add_number, args, s); | |
480 | #endif | |
481 | if (operand->X_op == O_constant) | |
482 | { | |
483 | if (reloc == BFD_RELOC_NONE) | |
484 | { | |
485 | bfd_vma v, mask; | |
486 | ||
487 | mask = 0x3ffffff; | |
488 | v = abs (operand->X_add_number) & ~ mask; | |
489 | if (v) | |
490 | as_bad (_("call/jmp target out of range (1)")); | |
491 | } | |
492 | ||
493 | if (reloc == BFD_RELOC_HI16) | |
494 | operand->X_add_number = ((operand->X_add_number >> 16) & 0xffff); | |
495 | ||
496 | the_insn.pcrel = 0; | |
497 | encode (insn, &opcode, operand->X_add_number, *args); | |
498 | /* the_insn.reloc = BFD_RELOC_NONE; */ | |
5d6255fe | 499 | continue; |
3b16e843 NC |
500 | } |
501 | ||
502 | if (reloc == BFD_RELOC_NONE) | |
503 | the_insn.reloc = BFD_RELOC_32_GOT_PCREL; | |
504 | else | |
505 | the_insn.reloc = reloc; | |
506 | ||
507 | /* the_insn.reloc = insn->reloc; */ | |
508 | #if DEBUG | |
509 | printf (" reloc sym=%d\n", the_insn.reloc); | |
510 | printf (" BFD_RELOC_NONE=%d\n", BFD_RELOC_NONE); | |
511 | #endif | |
512 | the_insn.exp = *operand; | |
5d6255fe | 513 | |
3b16e843 NC |
514 | /* the_insn.reloc_offset = 1; */ |
515 | the_insn.pcrel = 1; /* Assume PC-relative jump. */ | |
516 | ||
517 | /* FIXME-SOON, Do we figure out whether abs later, after | |
518 | know sym val? */ | |
519 | if (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_HI16) | |
520 | the_insn.pcrel = 0; | |
521 | ||
522 | encode (insn, &opcode, operand->X_add_number, *args); | |
523 | continue; | |
524 | } | |
5d6255fe | 525 | |
3b16e843 NC |
526 | /* Types or values of args don't match. */ |
527 | as_bad (_("invalid operands")); | |
528 | return; | |
529 | } | |
530 | } | |
531 | ||
3b16e843 NC |
532 | /* This is identical to the md_atof in m68k.c. I think this is right, |
533 | but I'm not sure. | |
534 | ||
535 | Turn a string in input_line_pointer into a floating point constant | |
536 | of type type, and store the appropriate bytes in *litP. The number | |
537 | of LITTLENUMS emitted is stored in *sizeP . An error message is | |
538 | returned, or NULL on OK. */ | |
539 | ||
540 | /* Equal to MAX_PRECISION in atof-ieee.c. */ | |
541 | #define MAX_LITTLENUMS 6 | |
542 | ||
543 | char * | |
ea1562b3 | 544 | md_atof (int type, char * litP, int * sizeP) |
3b16e843 NC |
545 | { |
546 | int prec; | |
547 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
548 | LITTLENUM_TYPE *wordP; | |
549 | char *t; | |
550 | ||
551 | switch (type) | |
552 | { | |
553 | case 'f': | |
554 | case 'F': | |
555 | case 's': | |
556 | case 'S': | |
557 | prec = 2; | |
558 | break; | |
559 | ||
560 | case 'd': | |
561 | case 'D': | |
562 | case 'r': | |
563 | case 'R': | |
564 | prec = 4; | |
565 | break; | |
566 | ||
567 | case 'x': | |
568 | case 'X': | |
569 | prec = 6; | |
570 | break; | |
571 | ||
572 | case 'p': | |
573 | case 'P': | |
574 | prec = 6; | |
575 | break; | |
576 | ||
577 | default: | |
578 | *sizeP = 0; | |
579 | return _("Bad call to MD_ATOF()"); | |
580 | } | |
581 | ||
582 | t = atof_ieee (input_line_pointer, type, words); | |
583 | if (t) | |
584 | input_line_pointer = t; | |
585 | ||
586 | *sizeP = prec * sizeof (LITTLENUM_TYPE); | |
587 | ||
588 | for (wordP = words; prec--;) | |
589 | { | |
590 | md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); | |
591 | litP += sizeof (LITTLENUM_TYPE); | |
592 | } | |
593 | ||
594 | return NULL; | |
595 | } | |
596 | ||
597 | /* Write out big-endian. */ | |
598 | ||
599 | void | |
ea1562b3 | 600 | md_number_to_chars (char *buf, valueT val, int n) |
3b16e843 NC |
601 | { |
602 | number_to_chars_bigendian (buf, val, n); | |
603 | } | |
604 | ||
3b16e843 | 605 | void |
55cf6793 | 606 | md_apply_fix (fixS * fixP, valueT * val, segT seg ATTRIBUTE_UNUSED) |
3b16e843 NC |
607 | { |
608 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; | |
609 | long t_val; | |
610 | ||
611 | t_val = (long) *val; | |
612 | ||
613 | #if DEBUG | |
614 | printf ("md_apply_fix val:%x\n", t_val); | |
615 | #endif | |
616 | ||
617 | fixP->fx_addnumber = t_val; /* Remember value for emit_reloc. */ | |
618 | ||
619 | know (fixP->fx_size == 4); | |
620 | know (fixP->fx_r_type < BFD_RELOC_NONE); | |
621 | ||
622 | switch (fixP->fx_r_type) | |
623 | { | |
624 | case BFD_RELOC_32: /* XXXXXXXX pattern in a word. */ | |
625 | #if DEBUG | |
626 | printf ("reloc_const: val=%x\n", t_val); | |
627 | #endif | |
628 | buf[0] = t_val >> 24; | |
629 | buf[1] = t_val >> 16; | |
630 | buf[2] = t_val >> 8; | |
631 | buf[3] = t_val; | |
632 | break; | |
633 | ||
634 | case BFD_RELOC_16: /* XXXX0000 pattern in a word. */ | |
635 | #if DEBUG | |
636 | printf ("reloc_const: val=%x\n", t_val); | |
637 | #endif | |
638 | buf[0] = t_val >> 8; | |
639 | buf[1] = t_val; | |
640 | break; | |
641 | ||
642 | case BFD_RELOC_8: /* XX000000 pattern in a word. */ | |
643 | #if DEBUG | |
644 | printf ("reloc_const: val=%x\n", t_val); | |
645 | #endif | |
646 | buf[0] = t_val; | |
647 | break; | |
648 | ||
649 | case BFD_RELOC_LO16: /* 0000XXXX pattern in a word. */ | |
650 | #if DEBUG | |
651 | printf ("reloc_const: val=%x\n", t_val); | |
652 | #endif | |
653 | buf[2] = t_val >> 8; /* Holds bits 0000XXXX. */ | |
654 | buf[3] = t_val; | |
655 | break; | |
656 | ||
657 | case BFD_RELOC_HI16: /* 0000XXXX pattern in a word. */ | |
658 | #if DEBUG | |
659 | printf ("reloc_consth: val=%x\n", t_val); | |
660 | #endif | |
661 | buf[2] = t_val >> 24; /* Holds bits XXXX0000. */ | |
662 | buf[3] = t_val >> 16; | |
663 | break; | |
664 | ||
665 | case BFD_RELOC_32_GOT_PCREL: /* 0000XXXX pattern in a word. */ | |
666 | if (!fixP->fx_done) | |
65ec77d2 | 667 | ; |
3b16e843 NC |
668 | else if (fixP->fx_pcrel) |
669 | { | |
670 | long v = t_val >> 28; | |
671 | ||
672 | if (v != 0 && v != -1) | |
673 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
674 | _("call/jmp target out of range (2)")); | |
675 | } | |
676 | else | |
677 | /* This case was supposed to be handled in machine_ip. */ | |
678 | abort (); | |
679 | ||
680 | buf[0] |= (t_val >> 26) & 0x03; /* Holds bits 0FFFFFFC of address. */ | |
681 | buf[1] = t_val >> 18; | |
682 | buf[2] = t_val >> 10; | |
683 | buf[3] = t_val >> 2; | |
684 | break; | |
685 | ||
686 | case BFD_RELOC_VTABLE_INHERIT: | |
687 | case BFD_RELOC_VTABLE_ENTRY: | |
688 | fixP->fx_done = 0; | |
689 | break; | |
690 | ||
691 | case BFD_RELOC_NONE: | |
692 | default: | |
693 | as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type); | |
694 | break; | |
695 | } | |
696 | ||
697 | if (fixP->fx_addsy == (symbolS *) NULL) | |
698 | fixP->fx_done = 1; | |
699 | } | |
3b16e843 NC |
700 | |
701 | /* Should never be called for or32. */ | |
702 | ||
703 | void | |
ea1562b3 NC |
704 | md_create_short_jump (char * ptr ATTRIBUTE_UNUSED, |
705 | addressT from_addr ATTRIBUTE_UNUSED, | |
706 | addressT to_addr ATTRIBUTE_UNUSED, | |
707 | fragS * frag ATTRIBUTE_UNUSED, | |
708 | symbolS * to_symbol ATTRIBUTE_UNUSED) | |
3b16e843 NC |
709 | { |
710 | as_fatal ("or32_create_short_jmp\n"); | |
711 | } | |
712 | ||
713 | /* Should never be called for or32. */ | |
714 | ||
3b16e843 | 715 | void |
ea1562b3 NC |
716 | md_convert_frag (bfd * headers ATTRIBUTE_UNUSED, |
717 | segT seg ATTRIBUTE_UNUSED, | |
718 | fragS * fragP ATTRIBUTE_UNUSED) | |
3b16e843 NC |
719 | { |
720 | as_fatal ("or32_convert_frag\n"); | |
5d6255fe | 721 | } |
3b16e843 NC |
722 | |
723 | /* Should never be called for or32. */ | |
724 | ||
725 | void | |
ea1562b3 NC |
726 | md_create_long_jump (char * ptr ATTRIBUTE_UNUSED, |
727 | addressT from_addr ATTRIBUTE_UNUSED, | |
728 | addressT to_addr ATTRIBUTE_UNUSED, | |
729 | fragS * frag ATTRIBUTE_UNUSED, | |
730 | symbolS * to_symbol ATTRIBUTE_UNUSED) | |
3b16e843 NC |
731 | { |
732 | as_fatal ("or32_create_long_jump\n"); | |
733 | } | |
734 | ||
735 | /* Should never be called for or32. */ | |
736 | ||
737 | int | |
ea1562b3 NC |
738 | md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, |
739 | segT segtype ATTRIBUTE_UNUSED) | |
3b16e843 NC |
740 | { |
741 | as_fatal ("or32_estimate_size_before_relax\n"); | |
742 | return 0; | |
743 | } | |
744 | ||
745 | /* Translate internal representation of relocation info to target format. | |
746 | ||
747 | On sparc/29k: first 4 bytes are normal unsigned long address, next three | |
748 | bytes are index, most sig. byte first. Byte 7 is broken up with | |
749 | bit 7 as external, bits 6 & 5 unused, and the lower | |
750 | five bits as relocation type. Next 4 bytes are long addend. */ | |
751 | /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com. */ | |
752 | ||
753 | #ifdef OBJ_AOUT | |
754 | void | |
ea1562b3 NC |
755 | tc_aout_fix_to_chars (char *where, |
756 | fixS *fixP, | |
757 | relax_addressT segment_address_in_file) | |
3b16e843 NC |
758 | { |
759 | long r_symbolnum; | |
760 | ||
761 | #if DEBUG | |
762 | printf ("tc_aout_fix_to_chars\n"); | |
5d6255fe | 763 | #endif |
3b16e843 NC |
764 | |
765 | know (fixP->fx_r_type < BFD_RELOC_NONE); | |
766 | know (fixP->fx_addsy != NULL); | |
767 | ||
768 | md_number_to_chars | |
769 | (where, | |
770 | fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, | |
771 | 4); | |
772 | ||
773 | r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) | |
774 | ? S_GET_TYPE (fixP->fx_addsy) | |
775 | : fixP->fx_addsy->sy_number); | |
776 | ||
777 | where[4] = (r_symbolnum >> 16) & 0x0ff; | |
778 | where[5] = (r_symbolnum >> 8) & 0x0ff; | |
779 | where[6] = r_symbolnum & 0x0ff; | |
780 | where[7] = (((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F); | |
781 | ||
782 | /* Also easy. */ | |
783 | md_number_to_chars (&where[8], fixP->fx_addnumber, 4); | |
784 | } | |
785 | ||
786 | #endif /* OBJ_AOUT */ | |
787 | \f | |
788 | const char *md_shortopts = ""; | |
789 | ||
790 | struct option md_longopts[] = | |
ea1562b3 NC |
791 | { |
792 | { NULL, no_argument, NULL, 0 } | |
793 | }; | |
3b16e843 NC |
794 | size_t md_longopts_size = sizeof (md_longopts); |
795 | ||
796 | int | |
ea1562b3 | 797 | md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED) |
3b16e843 NC |
798 | { |
799 | return 0; | |
800 | } | |
801 | ||
802 | void | |
ea1562b3 | 803 | md_show_usage (FILE * stream ATTRIBUTE_UNUSED) |
3b16e843 NC |
804 | { |
805 | } | |
806 | \f | |
807 | /* This is called when a line is unrecognized. This is used to handle | |
808 | definitions of or32 style local labels. */ | |
809 | ||
810 | int | |
ea1562b3 | 811 | or32_unrecognized_line (int c) |
3b16e843 NC |
812 | { |
813 | int lab; | |
814 | char *s; | |
815 | ||
816 | if (c != '$' | |
817 | || ! ISDIGIT ((unsigned char) input_line_pointer[0])) | |
818 | return 0; | |
819 | ||
820 | s = input_line_pointer; | |
821 | ||
822 | lab = 0; | |
823 | while (ISDIGIT ((unsigned char) *s)) | |
824 | { | |
825 | lab = lab * 10 + *s - '0'; | |
826 | ++s; | |
827 | } | |
828 | ||
829 | if (*s != ':') | |
830 | /* Not a label definition. */ | |
831 | return 0; | |
832 | ||
833 | if (dollar_label_defined (lab)) | |
834 | { | |
835 | as_bad (_("label \"$%d\" redefined"), lab); | |
836 | return 0; | |
837 | } | |
838 | ||
839 | define_dollar_label (lab); | |
840 | colon (dollar_label_name (lab, 0)); | |
841 | input_line_pointer = s + 1; | |
842 | ||
843 | return 1; | |
844 | } | |
845 | ||
3b16e843 NC |
846 | /* Default the values of symbols known that should be "predefined". We |
847 | don't bother to predefine them unless you actually use one, since there | |
848 | are a lot of them. */ | |
849 | ||
850 | symbolS * | |
ea1562b3 | 851 | md_undefined_symbol (char *name ATTRIBUTE_UNUSED) |
3b16e843 | 852 | { |
3b16e843 NC |
853 | return NULL; |
854 | } | |
855 | ||
856 | /* Parse an operand that is machine-specific. */ | |
857 | ||
858 | void | |
ea1562b3 | 859 | md_operand (expressionS *expressionP) |
3b16e843 NC |
860 | { |
861 | #if DEBUG | |
862 | printf (" md_operand(input_line_pointer = %s)\n", input_line_pointer); | |
863 | #endif | |
864 | ||
865 | if (input_line_pointer[0] == REGISTER_PREFIX && input_line_pointer[1] == 'r') | |
866 | { | |
867 | /* We have a numeric register expression. No biggy. */ | |
868 | input_line_pointer += 2; /* Skip %r */ | |
869 | (void) expression (expressionP); | |
870 | ||
871 | if (expressionP->X_op != O_constant | |
872 | || expressionP->X_add_number > 255) | |
873 | as_bad (_("Invalid expression after %%%%\n")); | |
874 | expressionP->X_op = O_register; | |
875 | } | |
876 | else if (input_line_pointer[0] == '&') | |
877 | { | |
878 | /* We are taking the 'address' of a register...this one is not | |
879 | in the manual, but it *is* in traps/fpsymbol.h! What they | |
880 | seem to want is the register number, as an absolute number. */ | |
881 | input_line_pointer++; /* Skip & */ | |
882 | (void) expression (expressionP); | |
883 | ||
884 | if (expressionP->X_op != O_register) | |
885 | as_bad (_("invalid register in & expression")); | |
886 | else | |
887 | expressionP->X_op = O_constant; | |
888 | } | |
889 | else if (input_line_pointer[0] == '$' | |
890 | && ISDIGIT ((unsigned char) input_line_pointer[1])) | |
891 | { | |
892 | long lab; | |
893 | char *name; | |
894 | symbolS *sym; | |
5d6255fe | 895 | |
3b16e843 NC |
896 | /* This is a local label. */ |
897 | ++input_line_pointer; | |
898 | lab = (long) get_absolute_expression (); | |
899 | ||
900 | if (dollar_label_defined (lab)) | |
901 | { | |
902 | name = dollar_label_name (lab, 0); | |
903 | sym = symbol_find (name); | |
904 | } | |
905 | else | |
906 | { | |
907 | name = dollar_label_name (lab, 1); | |
908 | sym = symbol_find_or_make (name); | |
909 | } | |
910 | ||
911 | expressionP->X_op = O_symbol; | |
912 | expressionP->X_add_symbol = sym; | |
913 | expressionP->X_add_number = 0; | |
914 | } | |
915 | else if (input_line_pointer[0] == '$') | |
916 | { | |
917 | char *s; | |
918 | char type; | |
919 | int fieldnum, fieldlimit; | |
920 | LITTLENUM_TYPE floatbuf[8]; | |
921 | ||
922 | /* $float(), $doubleN(), or $extendN() convert floating values | |
923 | to integers. */ | |
924 | s = input_line_pointer; | |
925 | ||
926 | ++s; | |
927 | ||
928 | fieldnum = 0; | |
929 | if (strncmp (s, "double", sizeof "double" - 1) == 0) | |
930 | { | |
931 | s += sizeof "double" - 1; | |
932 | type = 'd'; | |
933 | fieldlimit = 2; | |
934 | } | |
935 | else if (strncmp (s, "float", sizeof "float" - 1) == 0) | |
936 | { | |
937 | s += sizeof "float" - 1; | |
938 | type = 'f'; | |
939 | fieldlimit = 1; | |
940 | } | |
941 | else if (strncmp (s, "extend", sizeof "extend" - 1) == 0) | |
942 | { | |
943 | s += sizeof "extend" - 1; | |
944 | type = 'x'; | |
945 | fieldlimit = 4; | |
946 | } | |
5d6255fe | 947 | else |
3b16e843 NC |
948 | return; |
949 | ||
950 | if (ISDIGIT (*s)) | |
951 | { | |
952 | fieldnum = *s - '0'; | |
953 | ++s; | |
954 | } | |
955 | if (fieldnum >= fieldlimit) | |
956 | return; | |
957 | ||
958 | SKIP_WHITESPACE (); | |
959 | if (*s != '(') | |
960 | return; | |
961 | ++s; | |
962 | SKIP_WHITESPACE (); | |
963 | ||
964 | s = atof_ieee (s, type, floatbuf); | |
965 | if (s == NULL) | |
966 | return; | |
967 | s = s; | |
968 | ||
969 | SKIP_WHITESPACE (); | |
970 | if (*s != ')') | |
971 | return; | |
972 | ++s; | |
973 | SKIP_WHITESPACE (); | |
974 | ||
975 | input_line_pointer = s; | |
5d6255fe | 976 | expressionP->X_op = O_constant; |
3b16e843 NC |
977 | expressionP->X_unsigned = 1; |
978 | expressionP->X_add_number = ((floatbuf[fieldnum * 2] | |
979 | << LITTLENUM_NUMBER_OF_BITS) | |
980 | + floatbuf[fieldnum * 2 + 1]); | |
981 | } | |
982 | } | |
983 | ||
984 | /* Round up a section size to the appropriate boundary. */ | |
985 | ||
986 | valueT | |
ea1562b3 | 987 | md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size ATTRIBUTE_UNUSED) |
3b16e843 NC |
988 | { |
989 | return size; /* Byte alignment is fine. */ | |
990 | } | |
991 | ||
992 | /* Exactly what point is a PC-relative offset relative TO? | |
993 | On the 29000, they're relative to the address of the instruction, | |
994 | which we have set up as the address of the fixup too. */ | |
995 | ||
996 | long | |
ea1562b3 | 997 | md_pcrel_from (fixS *fixP) |
3b16e843 NC |
998 | { |
999 | return fixP->fx_where + fixP->fx_frag->fr_address; | |
1000 | } | |
1001 | ||
1002 | /* Generate a reloc for a fixup. */ | |
1003 | ||
3b16e843 | 1004 | arelent * |
ea1562b3 | 1005 | tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) |
3b16e843 NC |
1006 | { |
1007 | arelent *reloc; | |
1008 | ||
ea1562b3 NC |
1009 | reloc = xmalloc (sizeof (arelent)); |
1010 | reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); | |
3b16e843 NC |
1011 | *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); |
1012 | reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; | |
1013 | /* reloc->address = fixp->fx_frag->fr_address + fixp->fx_where + fixp->fx_addnumber;*/ | |
1014 | reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); | |
1015 | ||
1016 | if (reloc->howto == (reloc_howto_type *) NULL) | |
1017 | { | |
1018 | as_bad_where (fixp->fx_file, fixp->fx_line, | |
1019 | _("reloc %d not supported by object file format"), | |
1020 | (int) fixp->fx_r_type); | |
1021 | return NULL; | |
1022 | } | |
1023 | ||
a161fe53 AM |
1024 | if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) |
1025 | reloc->address = fixp->fx_offset; | |
3b16e843 | 1026 | |
a161fe53 | 1027 | reloc->addend = fixp->fx_addnumber; |
3b16e843 NC |
1028 | return reloc; |
1029 | } |