3a69b3ac |
1 | /* tc-sparc.c -- Assemble for the SPARC |
2 | Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GAS, the GNU Assembler. |
5 | |
6 | GAS is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 1, or (at your option) |
9 | any later version. |
10 | |
11 | GAS is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GAS; see the file COPYING. If not, write to |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
19 | |
20 | /* static const char rcsid[] = "$Id$"; */ |
21 | |
22 | #include <stdio.h> |
23 | #include <ctype.h> |
24 | |
25 | #include "as.h" |
26 | |
27 | /* careful, this file includes data *declarations* */ |
28 | #include "sparc-opcode.h" |
29 | |
30 | void md_begin(); |
31 | void md_end(); |
32 | void md_number_to_chars(); |
33 | void md_assemble(); |
34 | char *md_atof(); |
35 | void md_convert_frag(); |
36 | void md_create_short_jump(); |
37 | void md_create_long_jump(); |
38 | int md_estimate_size_before_relax(); |
39 | void md_ri_to_chars(); |
40 | symbolS *md_undefined_symbol(); |
41 | static void sparc_ip(); |
42 | |
43 | const relax_typeS md_relax_table[] = { |
44 | 0 }; |
45 | |
46 | /* handle of the OPCODE hash table */ |
47 | static struct hash_control *op_hash = NULL; |
48 | |
49 | static void s_seg(), s_proc(), s_data1(), s_reserve(), s_common(); |
50 | extern void s_globl(), s_long(), s_short(), s_space(), cons(); |
51 | extern void s_align_bytes(), s_ignore(); |
52 | |
53 | const pseudo_typeS md_pseudo_table[] = { |
54 | { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0) */ |
55 | { "common", s_common, 0 }, |
56 | { "global", s_globl, 0 }, |
57 | { "half", cons, 2 }, |
58 | { "optim", s_ignore, 0 }, |
59 | { "proc", s_proc, 0 }, |
60 | { "reserve", s_reserve, 0 }, |
61 | { "seg", s_seg, 0 }, |
62 | { "skip", s_space, 0 }, |
63 | { "word", cons, 4 }, |
64 | { NULL, 0, 0 }, |
65 | }; |
66 | |
67 | int md_short_jump_size = 4; |
68 | int md_long_jump_size = 4; |
69 | int md_reloc_size = 12; /* Size of relocation record */ |
70 | |
71 | /* This array holds the chars that always start a comment. If the |
72 | pre-processor is disabled, these aren't very useful */ |
73 | char comment_chars[] = "!"; /* JF removed '|' from comment_chars */ |
74 | |
75 | /* This array holds the chars that only start a comment at the beginning of |
76 | a line. If the line seems to have the form '# 123 filename' |
77 | .line and .file directives will appear in the pre-processed output */ |
78 | /* Note that input_file.c hand checks for '#' at the beginning of the |
79 | first line of the input file. This is because the compiler outputs |
80 | #NO_APP at the beginning of its output. */ |
81 | /* Also note that comments started like this one will always work */ |
82 | char line_comment_chars[] = "#"; |
83 | |
84 | /* Chars that can be used to separate mant from exp in floating point nums */ |
85 | char EXP_CHARS[] = "eE"; |
86 | |
87 | /* Chars that mean this number is a floating point constant */ |
88 | /* As in 0f12.456 */ |
89 | /* or 0d1.2345e12 */ |
90 | char FLT_CHARS[] = "rRsSfFdDxXpP"; |
91 | |
92 | /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be |
93 | changed in read.c . Ideally it shouldn't have to know about it at all, |
94 | but nothing is ideal around here. |
95 | */ |
96 | |
97 | static unsigned char octal[256]; |
98 | #define isoctal(c) octal[c] |
99 | static unsigned char toHex[256]; |
100 | |
101 | /* |
102 | * anull bit - causes the branch delay slot instructions to not be executed |
103 | */ |
104 | #define ANNUL (1 << 29) |
105 | |
106 | struct sparc_it { |
107 | char *error; |
108 | unsigned long opcode; |
109 | struct nlist *nlistp; |
110 | expressionS exp; |
111 | int pcrel; |
112 | enum reloc_type reloc; |
113 | } the_insn, set_insn; |
114 | |
115 | #ifdef __STDC__ |
116 | #if 0 |
117 | static void print_insn(struct sparc_it *insn); |
118 | #endif |
119 | static int getExpression(char *str); |
120 | #else |
121 | #if 0 |
122 | static void print_insn(); |
123 | #endif |
124 | static int getExpression(); |
125 | #endif |
126 | static char *expr_end; |
127 | static int special_case; |
128 | |
129 | /* |
130 | * Instructions that require wierd handling because they're longer than |
131 | * 4 bytes. |
132 | */ |
133 | #define SPECIAL_CASE_SET 1 |
134 | #define SPECIAL_CASE_FDIV 2 |
135 | |
136 | /* |
137 | * sort of like s_lcomm |
138 | * |
139 | */ |
140 | static void s_reserve() { |
141 | char *name; |
142 | char c; |
143 | char *p; |
144 | int temp; |
145 | symbolS *symbolP; |
146 | |
147 | name = input_line_pointer; |
148 | c = get_symbol_end(); |
149 | p = input_line_pointer; |
150 | *p = c; |
151 | SKIP_WHITESPACE(); |
152 | if (* input_line_pointer != ',') { |
153 | as_bad("Expected comma after name"); |
154 | ignore_rest_of_line(); |
155 | return; |
156 | } |
157 | input_line_pointer ++; |
158 | if ((temp = get_absolute_expression()) < 0) { |
159 | as_bad("BSS length (%d.) <0! Ignored.", temp); |
160 | ignore_rest_of_line(); |
161 | return; |
162 | } |
163 | *p = 0; |
164 | symbolP = symbol_find_or_make(name); |
165 | *p = c; |
166 | if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) { |
167 | as_bad("bad .reserve segment: `%s'", input_line_pointer); |
168 | return; |
169 | } |
170 | input_line_pointer += 6; |
171 | if (S_GET_OTHER(symbolP) == 0 |
172 | && S_GET_DESC(symbolP) == 0 |
173 | && ((S_GET_TYPE(symbolP) == N_BSS |
174 | && S_GET_VALUE(symbolP) == local_bss_counter) |
175 | || !S_IS_DEFINED(symbolP))) { |
176 | S_SET_VALUE(symbolP, local_bss_counter); |
177 | S_SET_SEGMENT(symbolP, SEG_BSS); |
178 | symbolP->sy_frag = & bss_address_frag; |
179 | local_bss_counter += temp; |
180 | } else { |
181 | as_warn("Ignoring attempt to re-define symbol from %d. to %d.", |
182 | S_GET_VALUE(symbolP), local_bss_counter); |
183 | } |
184 | demand_empty_rest_of_line(); |
185 | return; |
186 | } /* s_reserve() */ |
187 | |
188 | static void s_common() { |
189 | register char *name; |
190 | register char c; |
191 | register char *p; |
192 | register int temp; |
193 | register symbolS * symbolP; |
194 | |
195 | name = input_line_pointer; |
196 | c = get_symbol_end(); |
197 | /* just after name is now '\0' */ |
198 | p = input_line_pointer; |
199 | *p = c; |
200 | SKIP_WHITESPACE(); |
201 | if (* input_line_pointer != ',') { |
202 | as_bad("Expected comma after symbol-name"); |
203 | ignore_rest_of_line(); |
204 | return; |
205 | } |
206 | input_line_pointer ++; /* skip ',' */ |
207 | if ((temp = get_absolute_expression ()) < 0) { |
208 | as_bad(".COMMon length (%d.) <0! Ignored.", temp); |
209 | ignore_rest_of_line(); |
210 | return; |
211 | } |
212 | *p = 0; |
213 | symbolP = symbol_find_or_make(name); |
214 | *p = c; |
215 | if (S_IS_DEFINED(symbolP)) { |
216 | as_bad("Ignoring attempt to re-define symbol"); |
217 | ignore_rest_of_line(); |
218 | return; |
219 | } |
220 | if (S_GET_VALUE(symbolP) != 0) { |
221 | if (S_GET_VALUE(symbolP) != temp) { |
222 | as_warn("Length of .comm \"%s\" is already %d. Not changed to %d.", |
223 | S_GET_NAME(symbolP), S_GET_VALUE(symbolP), temp); |
224 | } |
225 | } else { |
226 | S_SET_VALUE(symbolP, temp); |
227 | S_SET_EXTERNAL(symbolP); |
228 | } |
229 | know(symbolP->sy_frag == &zero_address_frag); |
230 | if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0 |
231 | && strncmp(input_line_pointer, ",\"data\"", 7) != 0) { |
232 | p=input_line_pointer; |
233 | while(*p && *p!='\n') |
234 | p++; |
235 | c= *p; |
236 | *p='\0'; |
237 | as_bad("bad .common segment: `%s'", input_line_pointer); |
238 | *p=c; |
239 | return; |
240 | } |
241 | input_line_pointer += 6 + (input_line_pointer[2] == 'd'); /* Skip either */ |
242 | demand_empty_rest_of_line(); |
243 | return; |
244 | } /* s_common() */ |
245 | |
246 | static void s_seg() { |
247 | |
248 | if (strncmp(input_line_pointer, "\"text\"", 6) == 0) { |
249 | input_line_pointer += 6; |
250 | s_text(); |
251 | return; |
252 | } |
253 | if (strncmp(input_line_pointer, "\"data\"", 6) == 0) { |
254 | input_line_pointer += 6; |
255 | s_data(); |
256 | return; |
257 | } |
258 | if (strncmp(input_line_pointer, "\"data1\"", 7) == 0) { |
259 | input_line_pointer += 7; |
260 | s_data1(); |
261 | return; |
262 | } |
263 | if (strncmp(input_line_pointer, "\"bss\"", 5) == 0) { |
264 | input_line_pointer += 5; |
265 | /* We only support 2 segments -- text and data -- for now, so |
266 | things in the "bss segment" will have to go into data for now. |
267 | You can still allocate SEG_BSS stuff with .lcomm or .reserve. */ |
268 | subseg_new(SEG_DATA, 255); /* FIXME-SOMEDAY */ |
269 | return; |
270 | } |
271 | as_bad("Unknown segment type"); |
272 | demand_empty_rest_of_line(); |
273 | return; |
274 | } /* s_seg() */ |
275 | |
276 | static void s_data1() { |
277 | subseg_new(SEG_DATA, 1); |
278 | demand_empty_rest_of_line(); |
279 | return; |
280 | } /* s_data1() */ |
281 | |
282 | static void s_proc() { |
283 | extern char is_end_of_line[]; |
284 | |
285 | while (!is_end_of_line[*input_line_pointer]) { |
286 | ++input_line_pointer; |
287 | } |
288 | ++input_line_pointer; |
289 | return; |
290 | } /* s_proc() */ |
291 | |
292 | /* This function is called once, at assembler startup time. It should |
293 | set up all the tables, etc. that the MD part of the assembler will need. */ |
294 | void md_begin() { |
295 | register char *retval = NULL; |
296 | int lose = 0; |
297 | register unsigned int i = 0; |
298 | |
299 | op_hash = hash_new(); |
300 | if (op_hash == NULL) |
301 | as_fatal("Virtual memory exhausted"); |
302 | |
303 | while (i < NUMOPCODES) { |
304 | const char *name = sparc_opcodes[i].name; |
305 | retval = hash_insert(op_hash, name, &sparc_opcodes[i]); |
306 | if(retval != NULL && *retval != '\0') { |
307 | fprintf (stderr, "internal error: can't hash `%s': %s\n", |
308 | sparc_opcodes[i].name, retval); |
309 | lose = 1; |
310 | } |
311 | do |
312 | { |
313 | if (sparc_opcodes[i].match & sparc_opcodes[i].lose) { |
314 | fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", |
315 | sparc_opcodes[i].name, sparc_opcodes[i].args); |
316 | lose = 1; |
317 | } |
318 | ++i; |
319 | } while (i < NUMOPCODES |
320 | && !strcmp(sparc_opcodes[i].name, name)); |
321 | } |
322 | |
323 | if (lose) |
324 | as_fatal("Broken assembler. No assembly attempted."); |
325 | |
326 | for (i = '0'; i < '8'; ++i) |
327 | octal[i] = 1; |
328 | for (i = '0'; i <= '9'; ++i) |
329 | toHex[i] = i - '0'; |
330 | for (i = 'a'; i <= 'f'; ++i) |
331 | toHex[i] = i + 10 - 'a'; |
332 | for (i = 'A'; i <= 'F'; ++i) |
333 | toHex[i] = i + 10 - 'A'; |
334 | } /* md_begin() */ |
335 | |
336 | void md_end() { |
337 | return; |
338 | } /* md_end() */ |
339 | |
340 | void md_assemble(str) |
341 | char *str; |
342 | { |
343 | char *toP; |
344 | int rsd; |
345 | |
346 | know(str); |
347 | sparc_ip(str); |
348 | |
349 | /* See if "set" operand is absolute and small; skip sethi if so. */ |
350 | if (special_case == SPECIAL_CASE_SET && the_insn.exp.X_seg == SEG_ABSOLUTE) { |
351 | if (the_insn.exp.X_add_number >= -(1<<12) |
352 | && the_insn.exp.X_add_number < (1<<12)) { |
353 | the_insn.opcode = 0x80102000 /* or %g0,imm,... */ |
354 | | (the_insn.opcode & 0x3E000000) /* dest reg */ |
355 | | (the_insn.exp.X_add_number & 0x1FFF); /* imm */ |
356 | special_case = 0; /* No longer special */ |
357 | the_insn.reloc = NO_RELOC; /* No longer relocated */ |
358 | } |
359 | } |
360 | |
361 | toP = frag_more(4); |
362 | /* put out the opcode */ |
363 | md_number_to_chars(toP, the_insn.opcode, 4); |
364 | |
365 | /* put out the symbol-dependent stuff */ |
366 | if (the_insn.reloc != NO_RELOC) { |
367 | fix_new(frag_now, /* which frag */ |
368 | (toP - frag_now->fr_literal), /* where */ |
369 | 4, /* size */ |
370 | the_insn.exp.X_add_symbol, |
371 | the_insn.exp.X_subtract_symbol, |
372 | the_insn.exp.X_add_number, |
373 | the_insn.pcrel, |
374 | the_insn.reloc); |
375 | } |
376 | switch (special_case) { |
377 | |
378 | case SPECIAL_CASE_SET: |
379 | special_case = 0; |
380 | assert(the_insn.reloc == RELOC_HI22); |
381 | /* See if "set" operand has no low-order bits; skip OR if so. */ |
382 | if (the_insn.exp.X_seg == SEG_ABSOLUTE |
383 | && ((the_insn.exp.X_add_number & 0x3FF) == 0)) |
384 | return; |
385 | toP = frag_more(4); |
386 | rsd = (the_insn.opcode >> 25) & 0x1f; |
387 | the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14); |
388 | md_number_to_chars(toP, the_insn.opcode, 4); |
389 | fix_new(frag_now, /* which frag */ |
390 | (toP - frag_now->fr_literal), /* where */ |
391 | 4, /* size */ |
392 | the_insn.exp.X_add_symbol, |
393 | the_insn.exp.X_subtract_symbol, |
394 | the_insn.exp.X_add_number, |
395 | the_insn.pcrel, |
396 | RELOC_LO10); |
397 | return; |
398 | |
399 | case SPECIAL_CASE_FDIV: |
400 | /* According to information leaked from Sun, the "fdiv" instructions |
401 | on early SPARC machines would produce incorrect results sometimes. |
402 | The workaround is to add an fmovs of the destination register to |
403 | itself just after the instruction. This was true on machines |
404 | with Weitek 1165 float chips, such as the Sun-4/260 and /280. */ |
405 | special_case = 0; |
406 | assert(the_insn.reloc == NO_RELOC); |
407 | toP = frag_more(4); |
408 | rsd = (the_insn.opcode >> 25) & 0x1f; |
409 | the_insn.opcode = 0x81A00020 | (rsd << 25) | rsd; /* fmovs dest,dest */ |
410 | md_number_to_chars(toP, the_insn.opcode, 4); |
411 | return; |
412 | |
413 | case 0: |
414 | return; |
415 | |
416 | default: |
417 | abort(); |
418 | } |
419 | } /* md_assemble() */ |
420 | |
421 | static void sparc_ip(str) |
422 | char *str; |
423 | { |
424 | char *s; |
425 | const char *args; |
426 | char c; |
427 | struct sparc_opcode *insn; |
428 | char *argsStart; |
429 | unsigned long opcode; |
430 | unsigned int mask; |
431 | int match = 0; |
432 | int comma = 0; |
433 | |
434 | for (s = str; islower(*s) || (*s >= '0' && *s <= '3'); ++s) |
435 | ; |
436 | switch (*s) { |
437 | |
438 | case '\0': |
439 | break; |
440 | |
441 | case ',': |
442 | comma = 1; |
443 | |
444 | /*FALLTHROUGH */ |
445 | |
446 | case ' ': |
447 | *s++ = '\0'; |
448 | break; |
449 | |
450 | default: |
451 | as_bad("Unknown opcode: `%s'", str); |
452 | exit(1); |
453 | } |
454 | if ((insn = (struct sparc_opcode *) hash_find(op_hash, str)) == NULL) { |
455 | as_bad("Unknown opcode: `%s'", str); |
456 | return; |
457 | } |
458 | if (comma) { |
459 | *--s = ','; |
460 | } |
461 | argsStart = s; |
462 | for (;;) { |
463 | opcode = insn->match; |
464 | bzero(&the_insn, sizeof(the_insn)); |
465 | the_insn.reloc = NO_RELOC; |
466 | |
467 | /* |
468 | * Build the opcode, checking as we go to make |
469 | * sure that the operands match |
470 | */ |
471 | for (args = insn->args; ; ++args) { |
472 | switch (*args) { |
473 | |
474 | case '\0': /* end of args */ |
475 | if (*s == '\0') { |
476 | match = 1; |
477 | } |
478 | break; |
479 | |
480 | case '+': |
481 | if (*s == '+') { |
482 | ++s; |
483 | continue; |
484 | } |
485 | if (*s == '-') { |
486 | continue; |
487 | } |
488 | break; |
489 | |
490 | case '[': /* these must match exactly */ |
491 | case ']': |
492 | case ',': |
493 | case ' ': |
494 | if (*s++ == *args) |
495 | continue; |
496 | break; |
497 | |
498 | case '#': /* must be at least one digit */ |
499 | if (isdigit(*s++)) { |
500 | while (isdigit(*s)) { |
501 | ++s; |
502 | } |
503 | continue; |
504 | } |
505 | break; |
506 | |
507 | case 'C': /* coprocessor state register */ |
508 | if (strncmp(s, "%csr", 4) == 0) { |
509 | s += 4; |
510 | continue; |
511 | } |
512 | break; |
513 | |
514 | case 'b': /* next operand is a coprocessor register */ |
515 | case 'c': |
516 | case 'D': |
517 | if (*s++ == '%' && *s++ == 'c' && isdigit(*s)) { |
518 | mask = *s++; |
519 | if (isdigit(*s)) { |
520 | mask = 10 * (mask - '0') + (*s++ - '0'); |
521 | if (mask >= 32) { |
522 | break; |
523 | } |
524 | } else { |
525 | mask -= '0'; |
526 | } |
527 | switch (*args) { |
528 | |
529 | case 'b': |
530 | opcode |= mask << 14; |
531 | continue; |
532 | |
533 | case 'c': |
534 | opcode |= mask; |
535 | continue; |
536 | |
537 | case 'D': |
538 | opcode |= mask << 25; |
539 | continue; |
540 | } |
541 | } |
542 | break; |
543 | |
544 | case 'r': /* next operand must be a register */ |
545 | case '1': |
546 | case '2': |
547 | case 'd': |
548 | if (*s++ == '%') { |
549 | switch (c = *s++) { |
550 | |
551 | case 'f': /* frame pointer */ |
552 | if (*s++ == 'p') { |
553 | mask = 0x1e; |
554 | break; |
555 | } |
556 | goto error; |
557 | |
558 | case 'g': /* global register */ |
559 | if (isoctal(c = *s++)) { |
560 | mask = c - '0'; |
561 | break; |
562 | } |
563 | goto error; |
564 | |
565 | case 'i': /* in register */ |
566 | if (isoctal(c = *s++)) { |
567 | mask = c - '0' + 24; |
568 | break; |
569 | } |
570 | goto error; |
571 | |
572 | case 'l': /* local register */ |
573 | if (isoctal(c = *s++)) { |
574 | mask= (c - '0' + 16) ; |
575 | break; |
576 | } |
577 | goto error; |
578 | |
579 | case 'o': /* out register */ |
580 | if (isoctal(c = *s++)) { |
581 | mask= (c - '0' + 8) ; |
582 | break; |
583 | } |
584 | goto error; |
585 | |
586 | case 's': /* stack pointer */ |
587 | if (*s++ == 'p') { |
588 | mask= 0xe; |
589 | break; |
590 | } |
591 | goto error; |
592 | |
593 | case 'r': /* any register */ |
594 | if (!isdigit(c = *s++)) { |
595 | goto error; |
596 | } |
597 | /* FALLTHROUGH */ |
598 | case '0': case '1': case '2': case '3': case '4': |
599 | case '5': case '6': case '7': case '8': case '9': |
600 | if (isdigit(*s)) { |
601 | if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) { |
602 | goto error; |
603 | } |
604 | } else { |
605 | c -= '0'; |
606 | } |
607 | mask= c; |
608 | break; |
609 | |
610 | default: |
611 | goto error; |
612 | } |
613 | /* |
614 | * Got the register, now figure out where |
615 | * it goes in the opcode. |
616 | */ |
617 | switch (*args) { |
618 | |
619 | case '1': |
620 | opcode |= mask << 14; |
621 | continue; |
622 | |
623 | case '2': |
624 | opcode |= mask; |
625 | continue; |
626 | |
627 | case 'd': |
628 | opcode |= mask << 25; |
629 | continue; |
630 | |
631 | case 'r': |
632 | opcode |= (mask << 25) | (mask << 14); |
633 | continue; |
634 | } |
635 | } |
636 | break; |
637 | |
638 | case 'e': /* next operand is a floating point register */ |
639 | case 'f': |
640 | case 'g': |
641 | if (*s++ == '%' && *s++ == 'f' && isdigit(*s)) { |
642 | mask = *s++; |
643 | if (isdigit(*s)) { |
644 | mask = 10 * (mask - '0') + (*s++ - '0'); |
645 | if (mask >= 32) { |
646 | break; |
647 | } |
648 | } else { |
649 | mask -= '0'; |
650 | } |
651 | switch (*args) { |
652 | |
653 | case 'e': |
654 | opcode |= mask << 14; |
655 | continue; |
656 | |
657 | case 'f': |
658 | opcode |= mask; |
659 | continue; |
660 | |
661 | case 'g': |
662 | opcode |= mask << 25; |
663 | continue; |
664 | } |
665 | } |
666 | break; |
667 | |
668 | case 'F': |
669 | if (strncmp(s, "%fsr", 4) == 0) { |
670 | s += 4; |
671 | continue; |
672 | } |
673 | break; |
674 | |
675 | case 'h': /* high 22 bits */ |
676 | the_insn.reloc = RELOC_HI22; |
677 | goto immediate; |
678 | |
679 | case 'l': /* 22 bit PC relative immediate */ |
680 | the_insn.reloc = RELOC_WDISP22; |
681 | the_insn.pcrel = 1; |
682 | goto immediate; |
683 | |
684 | case 'L': /* 30 bit immediate */ |
685 | the_insn.reloc = RELOC_WDISP30; |
686 | the_insn.pcrel = 1; |
687 | goto immediate; |
688 | |
689 | case 'i': /* 13 bit immediate */ |
690 | the_insn.reloc = RELOC_BASE13; |
691 | |
692 | /*FALLTHROUGH */ |
693 | |
694 | immediate: |
695 | if(*s==' ') |
696 | s++; |
697 | if (*s == '%') { |
698 | if ((c = s[1]) == 'h' && s[2] == 'i') { |
699 | the_insn.reloc = RELOC_HI22; |
700 | s+=3; |
701 | } else if (c == 'l' && s[2] == 'o') { |
702 | the_insn.reloc = RELOC_LO10; |
703 | s+=3; |
704 | } else |
705 | break; |
706 | } |
707 | /* Note that if the getExpression() fails, we will still have |
708 | created U entries in the symbol table for the 'symbols' |
709 | in the input string. Try not to create U symbols for |
710 | registers, etc. */ |
711 | { |
712 | /* This stuff checks to see if the expression ends |
713 | in +%reg If it does, it removes the register from |
714 | the expression, and re-sets 's' to point to the |
715 | right place */ |
716 | |
717 | char *s1; |
718 | |
719 | for(s1=s;*s1 && *s1!=','&& *s1!=']';s1++) |
720 | ; |
721 | |
722 | if(s1!=s && isdigit(s1[-1])) { |
723 | if(s1[-2]=='%' && s1[-3]=='+') { |
724 | s1-=3; |
725 | *s1='\0'; |
726 | (void)getExpression(s); |
727 | *s1='+'; |
728 | s=s1; |
729 | continue; |
730 | } else if(strchr("goli0123456789",s1[-2]) && s1[-3]=='%' && s1[-4]=='+') { |
731 | s1-=4; |
732 | *s1='\0'; |
733 | (void)getExpression(s); |
734 | *s1='+'; |
735 | s=s1; |
736 | continue; |
737 | } |
738 | } |
739 | } |
740 | (void)getExpression(s); |
741 | s = expr_end; |
742 | continue; |
743 | |
744 | case 'a': |
745 | if (*s++ == 'a') { |
746 | opcode |= ANNUL; |
747 | continue; |
748 | } |
749 | break; |
750 | |
751 | case 'A': /* alternate space */ |
752 | if (isdigit(*s)) { |
753 | long num; |
754 | |
755 | num=0; |
756 | while (isdigit(*s)) { |
757 | num= num*10 + *s-'0'; |
758 | ++s; |
759 | } |
760 | opcode |= num<<5; |
761 | continue; |
762 | } |
763 | break; |
764 | /* abort(); */ |
765 | |
766 | case 'p': |
767 | if (strncmp(s, "%psr", 4) == 0) { |
768 | s += 4; |
769 | continue; |
770 | } |
771 | break; |
772 | |
773 | case 'q': /* floating point queue */ |
774 | if (strncmp(s, "%fq", 3) == 0) { |
775 | s += 3; |
776 | continue; |
777 | } |
778 | break; |
779 | |
780 | case 'Q': /* coprocessor queue */ |
781 | if (strncmp(s, "%cq", 3) == 0) { |
782 | s += 3; |
783 | continue; |
784 | } |
785 | break; |
786 | |
787 | case 'S': |
788 | if (strcmp(str, "set") == 0) { |
789 | special_case = SPECIAL_CASE_SET; |
790 | continue; |
791 | } else if (strncmp(str, "fdiv", 4) == 0) { |
792 | special_case = SPECIAL_CASE_FDIV; |
793 | continue; |
794 | } |
795 | break; |
796 | |
797 | case 't': |
798 | if (strncmp(s, "%tbr", 4) != 0) |
799 | break; |
800 | s += 4; |
801 | continue; |
802 | |
803 | case 'w': |
804 | if (strncmp(s, "%wim", 4) != 0) |
805 | break; |
806 | s += 4; |
807 | continue; |
808 | |
809 | case 'y': |
810 | if (strncmp(s, "%y", 2) != 0) |
811 | break; |
812 | s += 2; |
813 | continue; |
814 | |
815 | default: |
816 | abort(); |
817 | } |
818 | break; |
819 | } |
820 | error: |
821 | if (match == 0) { |
822 | /* Args don't match. */ |
823 | if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES |
824 | && !strcmp(insn->name, insn[1].name)) { |
825 | ++insn; |
826 | s = argsStart; |
827 | continue; |
828 | } |
829 | else |
830 | { |
831 | as_bad("Illegal operands"); |
832 | return; |
833 | } |
834 | } |
835 | break; |
836 | } |
837 | |
838 | the_insn.opcode = opcode; |
839 | return; |
840 | } /* sparc_ip() */ |
841 | |
842 | static int getExpression(str) |
843 | char *str; |
844 | { |
845 | char *save_in; |
846 | segT seg; |
847 | |
848 | save_in = input_line_pointer; |
849 | input_line_pointer = str; |
850 | switch (seg = expression(&the_insn.exp)) { |
851 | |
852 | case SEG_ABSOLUTE: |
853 | case SEG_TEXT: |
854 | case SEG_DATA: |
855 | case SEG_BSS: |
856 | case SEG_UNKNOWN: |
857 | case SEG_DIFFERENCE: |
858 | case SEG_BIG: |
859 | case SEG_ABSENT: |
860 | break; |
861 | |
862 | default: |
863 | the_insn.error = "bad segment"; |
864 | expr_end = input_line_pointer; |
865 | input_line_pointer=save_in; |
866 | return 1; |
867 | } |
868 | expr_end = input_line_pointer; |
869 | input_line_pointer = save_in; |
870 | return 0; |
871 | } /* getExpression() */ |
872 | |
873 | |
874 | /* |
875 | This is identical to the md_atof in m68k.c. I think this is right, |
876 | but I'm not sure. |
877 | |
878 | Turn a string in input_line_pointer into a floating point constant of type |
879 | type, and store the appropriate bytes in *litP. The number of LITTLENUMS |
880 | emitted is stored in *sizeP . An error message is returned, or NULL on OK. |
881 | */ |
882 | |
883 | /* Equal to MAX_PRECISION in atof-ieee.c */ |
884 | #define MAX_LITTLENUMS 6 |
885 | |
886 | char *md_atof(type,litP,sizeP) |
887 | char type; |
888 | char *litP; |
889 | int *sizeP; |
890 | { |
891 | int prec; |
892 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; |
893 | LITTLENUM_TYPE *wordP; |
894 | char *t; |
895 | char *atof_ieee(); |
896 | |
897 | switch(type) { |
898 | |
899 | case 'f': |
900 | case 'F': |
901 | case 's': |
902 | case 'S': |
903 | prec = 2; |
904 | break; |
905 | |
906 | case 'd': |
907 | case 'D': |
908 | case 'r': |
909 | case 'R': |
910 | prec = 4; |
911 | break; |
912 | |
913 | case 'x': |
914 | case 'X': |
915 | prec = 6; |
916 | break; |
917 | |
918 | case 'p': |
919 | case 'P': |
920 | prec = 6; |
921 | break; |
922 | |
923 | default: |
924 | *sizeP=0; |
925 | return "Bad call to MD_ATOF()"; |
926 | } |
927 | t=atof_ieee(input_line_pointer,type,words); |
928 | if(t) |
929 | input_line_pointer=t; |
930 | *sizeP=prec * sizeof(LITTLENUM_TYPE); |
931 | for(wordP=words;prec--;) { |
932 | md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); |
933 | litP+=sizeof(LITTLENUM_TYPE); |
934 | } |
935 | return ""; /* Someone should teach Dean about null pointers */ |
936 | } /* md_atof() */ |
937 | |
938 | /* |
939 | * Write out big-endian. |
940 | */ |
941 | void md_number_to_chars(buf,val,n) |
942 | char *buf; |
943 | long val; |
944 | int n; |
945 | { |
946 | |
947 | switch(n) { |
948 | |
949 | case 4: |
950 | *buf++ = val >> 24; |
951 | *buf++ = val >> 16; |
952 | case 2: |
953 | *buf++ = val >> 8; |
954 | case 1: |
955 | *buf = val; |
956 | break; |
957 | |
958 | default: |
959 | abort(); |
960 | } |
961 | return; |
962 | } /* md_number_to_chars() */ |
963 | |
964 | /* Apply a fixS to the frags, now that we know the value it ought to |
965 | hold. */ |
966 | |
967 | void md_apply_fix(fixP, val) |
968 | fixS *fixP; |
969 | long val; |
970 | { |
971 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; |
972 | |
973 | assert(fixP->fx_size == 4); |
974 | assert(fixP->fx_r_type < NO_RELOC); |
975 | |
976 | fixP->fx_addnumber = val; /* Remember value for emit_reloc */ |
977 | |
978 | /* |
979 | * This is a hack. There should be a better way to |
980 | * handle this. |
981 | */ |
982 | if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) { |
983 | val += fixP->fx_where + fixP->fx_frag->fr_address; |
984 | } |
985 | |
986 | switch (fixP->fx_r_type) { |
987 | |
988 | case RELOC_32: |
989 | buf[0] = 0; /* val >> 24; */ |
990 | buf[1] = 0; /* val >> 16; */ |
991 | buf[2] = 0; /* val >> 8; */ |
992 | buf[3] = 0; /* val; */ |
993 | break; |
994 | |
995 | #if 0 |
996 | case RELOC_8: /* These don't seem to ever be needed. */ |
997 | case RELOC_16: |
998 | case RELOC_DISP8: |
999 | case RELOC_DISP16: |
1000 | case RELOC_DISP32: |
1001 | #endif |
1002 | case RELOC_WDISP30: |
1003 | val = (val >>= 2) + 1; |
1004 | buf[0] |= (val >> 24) & 0x3f; |
1005 | buf[1]= (val >> 16); |
1006 | buf[2] = val >> 8; |
1007 | buf[3] = val; |
1008 | break; |
1009 | |
1010 | case RELOC_HI22: |
1011 | if(!fixP->fx_addsy) { |
1012 | buf[1] |= (val >> 26) & 0x3f; |
1013 | buf[2] = val >> 18; |
1014 | buf[3] = val >> 10; |
1015 | } else { |
1016 | buf[2]=0; |
1017 | buf[3]=0; |
1018 | } |
1019 | break; |
1020 | #if 0 |
1021 | case RELOC_22: |
1022 | case RELOC_13: |
1023 | #endif |
1024 | case RELOC_LO10: |
1025 | if(!fixP->fx_addsy) { |
1026 | buf[2] |= (val >> 8) & 0x03; |
1027 | buf[3] = val; |
1028 | } else |
1029 | buf[3]=0; |
1030 | break; |
1031 | #if 0 |
1032 | case RELOC_SFA_BASE: |
1033 | case RELOC_SFA_OFF13: |
1034 | case RELOC_BASE10: |
1035 | #endif |
1036 | case RELOC_BASE13: |
1037 | buf[2] |= (val >> 8) & 0x1f; |
1038 | buf[3] = val; |
1039 | break; |
1040 | |
1041 | case RELOC_WDISP22: |
1042 | val = (val >>= 2) + 1; |
1043 | /* FALLTHROUGH */ |
1044 | case RELOC_BASE22: |
1045 | buf[1] |= (val >> 16) & 0x3f; |
1046 | buf[2] = val >> 8; |
1047 | buf[3] = val; |
1048 | break; |
1049 | |
1050 | #if 0 |
1051 | case RELOC_PC10: |
1052 | case RELOC_PC22: |
1053 | case RELOC_JMP_TBL: |
1054 | case RELOC_SEGOFF16: |
1055 | case RELOC_GLOB_DAT: |
1056 | case RELOC_JMP_SLOT: |
1057 | case RELOC_RELATIVE: |
1058 | #endif |
1059 | |
1060 | case NO_RELOC: |
1061 | default: |
1062 | as_bad("bad relocation type: 0x%02x", fixP->fx_r_type); |
1063 | break; |
1064 | } |
1065 | } /* md_apply_fix() */ |
1066 | |
1067 | /* should never be called for sparc */ |
1068 | void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) |
1069 | char *ptr; |
1070 | long from_addr; |
1071 | long to_addr; |
1072 | fragS *frag; |
1073 | symbolS *to_symbol; |
1074 | { |
1075 | fprintf(stderr, "sparc_create_short_jmp\n"); |
1076 | abort(); |
1077 | } /* md_create_short_jump() */ |
1078 | |
1079 | /* Translate internal representation of relocation info to target format. |
1080 | |
1081 | On sparc: first 4 bytes are normal unsigned long address, next three |
1082 | bytes are index, most sig. byte first. Byte 7 is broken up with |
1083 | bit 7 as external, bits 6 & 5 unused, and the lower |
1084 | five bits as relocation type. Next 4 bytes are long addend. */ |
1085 | /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ |
1086 | void md_ri_to_chars(the_bytes, ri) |
1087 | char *the_bytes; |
1088 | struct reloc_info_generic *ri; |
1089 | { |
1090 | /* this is easy */ |
1091 | md_number_to_chars(the_bytes, ri->r_address, 4); |
1092 | /* now the fun stuff */ |
1093 | the_bytes[4] = (ri->r_index >> 16) & 0x0ff; |
1094 | the_bytes[5] = (ri->r_index >> 8) & 0x0ff; |
1095 | the_bytes[6] = ri->r_index & 0x0ff; |
1096 | the_bytes[7] = ((ri->r_extern << 7) & 0x80) | (0 & 0x60) | (ri->r_type & 0x1F); |
1097 | /* Also easy */ |
1098 | md_number_to_chars(&the_bytes[8], ri->r_addend, 4); |
1099 | } /* md_ri_to_chars() */ |
1100 | |
1101 | /* should never be called for sparc */ |
1102 | void md_convert_frag(fragP) |
1103 | register fragS *fragP; |
1104 | { |
1105 | fprintf(stderr, "sparc_convert_frag\n"); |
1106 | abort(); |
1107 | } /* md_convert_frag() */ |
1108 | |
1109 | /* should never be called for sparc */ |
1110 | void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol) |
1111 | char *ptr; |
1112 | long from_addr, to_addr; |
1113 | fragS *frag; |
1114 | symbolS *to_symbol; |
1115 | { |
1116 | fprintf(stderr, "sparc_create_long_jump\n"); |
1117 | abort(); |
1118 | } /* md_create_long_jump() */ |
1119 | |
1120 | /* should never be called for sparc */ |
1121 | int md_estimate_size_before_relax(fragP, segtype) |
1122 | fragS *fragP; |
1123 | segT segtype; |
1124 | { |
1125 | fprintf(stderr, "sparc_estimate_size_before_relax\n"); |
1126 | abort(); |
1127 | return 0; |
1128 | } /* md_estimate_size_before_relax() */ |
1129 | |
1130 | #if 0 |
1131 | /* for debugging only */ |
1132 | static void print_insn(insn) |
1133 | struct sparc_it *insn; |
1134 | { |
1135 | char *Reloc[] = { |
1136 | "RELOC_8", |
1137 | "RELOC_16", |
1138 | "RELOC_32", |
1139 | "RELOC_DISP8", |
1140 | "RELOC_DISP16", |
1141 | "RELOC_DISP32", |
1142 | "RELOC_WDISP30", |
1143 | "RELOC_WDISP22", |
1144 | "RELOC_HI22", |
1145 | "RELOC_22", |
1146 | "RELOC_13", |
1147 | "RELOC_LO10", |
1148 | "RELOC_SFA_BASE", |
1149 | "RELOC_SFA_OFF13", |
1150 | "RELOC_BASE10", |
1151 | "RELOC_BASE13", |
1152 | "RELOC_BASE22", |
1153 | "RELOC_PC10", |
1154 | "RELOC_PC22", |
1155 | "RELOC_JMP_TBL", |
1156 | "RELOC_SEGOFF16", |
1157 | "RELOC_GLOB_DAT", |
1158 | "RELOC_JMP_SLOT", |
1159 | "RELOC_RELATIVE", |
1160 | "NO_RELOC" |
1161 | }; |
1162 | |
1163 | if (insn->error) { |
1164 | fprintf(stderr, "ERROR: %s\n"); |
1165 | } |
1166 | fprintf(stderr, "opcode=0x%08x\n", insn->opcode); |
1167 | fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]); |
1168 | fprintf(stderr, "exp = { |
1169 | \n"); |
1170 | fprintf(stderr, "\t\tX_add_symbol = %s\n", |
1171 | ((insn->exp.X_add_symbol != NULL) |
1172 | ? ((S_GET_NAME(insn->exp.X_add_symbol) != NULL) |
1173 | ? S_GET_NAME(insn->exp.X_add_symbol) |
1174 | : "???") |
1175 | : "0")); |
1176 | fprintf(stderr, "\t\tX_sub_symbol = %s\n", |
1177 | ((insn->exp.X_subtract_symbol != NULL) |
1178 | ? (S_GET_NAME(insn->exp.X_subtract_symbol) |
1179 | ? S_GET_NAME(insn->exp.X_subtract_symbol) |
1180 | : "???") |
1181 | : "0")); |
1182 | fprintf(stderr, "\t\tX_add_number = %d\n", |
1183 | insn->exp.X_add_number); |
1184 | fprintf(stderr, "}\n"); |
1185 | return; |
1186 | } /* print_insn() */ |
1187 | #endif |
1188 | |
1189 | /* Set the hook... */ |
1190 | |
1191 | void emit_sparc_reloc(); |
1192 | void (*md_emit_relocations)() = emit_sparc_reloc; |
1193 | |
1194 | /* |
1195 | * Sparc/AM29K relocations are completely different, so it needs |
1196 | * this machine dependent routine to emit them. |
1197 | */ |
1198 | #if defined(OBJ_AOUT) || defined(OBJ_BOUT) |
1199 | void emit_sparc_reloc(fixP, segment_address_in_file) |
1200 | register fixS *fixP; |
1201 | relax_addressT segment_address_in_file; |
1202 | { |
1203 | struct reloc_info_generic ri; |
1204 | register symbolS *symbolP; |
1205 | extern char *next_object_file_charP; |
1206 | /* long add_number; */ |
1207 | |
1208 | bzero((char *) &ri, sizeof(ri)); |
1209 | for (; fixP; fixP = fixP->fx_next) { |
1210 | |
1211 | if (fixP->fx_r_type >= NO_RELOC) { |
1212 | fprintf(stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type); |
1213 | abort(); |
1214 | } |
1215 | |
1216 | if ((symbolP = fixP->fx_addsy) != NULL) { |
1217 | ri.r_address = fixP->fx_frag->fr_address + |
1218 | fixP->fx_where - segment_address_in_file; |
1219 | if ((S_GET_TYPE(symbolP)) == N_UNDF) { |
1220 | ri.r_extern = 1; |
1221 | ri.r_index = symbolP->sy_number; |
1222 | } else { |
1223 | ri.r_extern = 0; |
1224 | ri.r_index = S_GET_TYPE(symbolP); |
1225 | } |
1226 | if (symbolP && symbolP->sy_frag) { |
1227 | ri.r_addend = symbolP->sy_frag->fr_address; |
1228 | } |
1229 | ri.r_type = fixP->fx_r_type; |
1230 | if (fixP->fx_pcrel) { |
1231 | /* ri.r_addend -= fixP->fx_where; */ |
1232 | ri.r_addend -= ri.r_address; |
1233 | } else { |
1234 | ri.r_addend = fixP->fx_addnumber; |
1235 | } |
1236 | |
1237 | md_ri_to_chars(next_object_file_charP, &ri); |
1238 | next_object_file_charP += md_reloc_size; |
1239 | } |
1240 | } |
1241 | return; |
1242 | } /* emit_sparc_reloc() */ |
1243 | #endif /* aout or bout */ |
1244 | |
1245 | int md_parse_option(argP,cntP,vecP) |
1246 | char **argP; |
1247 | int *cntP; |
1248 | char ***vecP; |
1249 | { |
1250 | return 1; |
1251 | } /* md_parse_option() */ |
1252 | |
1253 | /* We have no need to default values of symbols. */ |
1254 | |
1255 | /* ARGSUSED */ |
1256 | symbolS *md_undefined_symbol(name) |
1257 | char *name; |
1258 | { |
1259 | return 0; |
1260 | } /* md_undefined_symbol() */ |
1261 | |
1262 | /* Parse an operand that is machine-specific. |
1263 | We just return without modifying the expression if we have nothing |
1264 | to do. */ |
1265 | |
1266 | /* ARGSUSED */ |
1267 | void md_operand(expressionP) |
1268 | expressionS *expressionP; |
1269 | { |
1270 | } /* md_operand() */ |
1271 | |
1272 | /* Round up a section size to the appropriate boundary. */ |
1273 | long md_section_align (segment, size) |
1274 | segT segment; |
1275 | long size; |
1276 | { |
1277 | return (size + 7) & ~7; /* Round all sects to multiple of 8 */ |
1278 | } /* md_section_align() */ |
1279 | |
1280 | /* Exactly what point is a PC-relative offset relative TO? |
1281 | On the sparc, they're relative to the address of the offset, plus |
1282 | its size. This gets us to the following instruction. |
1283 | (??? Is this right? FIXME-SOON) */ |
1284 | long md_pcrel_from(fixP) |
1285 | fixS *fixP; |
1286 | { |
1287 | return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; |
1288 | } /* md_pcrel_from() */ |
1289 | |
1290 | /* |
1291 | * Local Variables: |
1292 | * comment-column: 0 |
1293 | * fill-column: 131 |
1294 | * End: |
1295 | */ |
1296 | |
1297 | /* end of tp-sparc.c */ |