]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gas/config/tc-sparc.c
force all files to end in "/* end of filename"
[thirdparty/binutils-gdb.git] / gas / config / tc-sparc.c
1 #define cypress 1234
2 /* tc-sparc.c -- Assemble for the SPARC
3 Copyright (C) 1989, 1990, 1991 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 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include <stdio.h>
22 #include <ctype.h>
23
24 #include "as.h"
25
26 /* careful, this file includes data *declarations* */
27 #include "opcode/sparc.h"
28
29 void md_begin();
30 void md_end();
31 void md_number_to_chars();
32 void md_assemble();
33 char *md_atof();
34 void md_convert_frag();
35 void md_create_short_jump();
36 void md_create_long_jump();
37 int md_estimate_size_before_relax();
38 void md_ri_to_chars();
39 symbolS *md_undefined_symbol();
40 static void sparc_ip();
41
42 static enum sparc_architecture current_architecture = v6;
43 static int architecture_requested = 0;
44 static int warn_on_bump = 0;
45
46 const relax_typeS md_relax_table[] = {
47 0 };
48
49 /* handle of the OPCODE hash table */
50 static struct hash_control *op_hash = NULL;
51
52 static void s_seg(), s_proc(), s_data1(), s_reserve(), s_common();
53 extern void s_globl(), s_long(), s_short(), s_space(), cons();
54 extern void s_align_bytes(), s_ignore();
55
56 const pseudo_typeS md_pseudo_table[] = {
57 { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0) */
58 { "common", s_common, 0 },
59 { "global", s_globl, 0 },
60 { "half", cons, 2 },
61 { "optim", s_ignore, 0 },
62 { "proc", s_proc, 0 },
63 { "reserve", s_reserve, 0 },
64 { "seg", s_seg, 0 },
65 { "skip", s_space, 0 },
66 { "word", cons, 4 },
67 { NULL, 0, 0 },
68 };
69
70 const int md_short_jump_size = 4;
71 const int md_long_jump_size = 4;
72 const int md_reloc_size = 12; /* Size of relocation record */
73
74 /* This array holds the chars that always start a comment. If the
75 pre-processor is disabled, these aren't very useful */
76 const char comment_chars[] = "!"; /* JF removed '|' from 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 started like this one will always
85 work if '/' isn't otherwise defined. */
86 const char line_comment_chars[] = "#";
87
88 /* Chars that can be used to separate mant from exp in floating point nums */
89 const char EXP_CHARS[] = "eE";
90
91 /* Chars that mean this number is a floating point constant */
92 /* As in 0f12.456 */
93 /* or 0d1.2345e12 */
94 const char FLT_CHARS[] = "rRsSfFdDxXpP";
95
96 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
97 changed in read.c . Ideally it shouldn't have to know about it at all,
98 but nothing is ideal around here.
99 */
100
101 static unsigned char octal[256];
102 #define isoctal(c) octal[c]
103 static unsigned char toHex[256];
104
105 struct sparc_it {
106 char *error;
107 unsigned long opcode;
108 struct nlist *nlistp;
109 expressionS exp;
110 int pcrel;
111 enum reloc_type reloc;
112 } the_insn, set_insn;
113
114 #ifdef __STDC__
115 #if 0
116 static void print_insn(struct sparc_it *insn);
117 #endif
118 static int getExpression(char *str);
119 #else
120 #if 0
121 static void print_insn();
122 #endif
123 static int getExpression();
124 #endif
125 static char *expr_end;
126 static int special_case;
127
128 /*
129 * Instructions that require wierd handling because they're longer than
130 * 4 bytes.
131 */
132 #define SPECIAL_CASE_SET 1
133 #define SPECIAL_CASE_FDIV 2
134
135 /*
136 * sort of like s_lcomm
137 *
138 */
139 static int max_alignment = 15;
140
141 static void s_reserve() {
142 char *name;
143 char *p;
144 char c;
145 int align;
146 int size;
147 int temp;
148 symbolS *symbolP;
149
150 name = input_line_pointer;
151 c = get_symbol_end();
152 p = input_line_pointer;
153 *p = c;
154 SKIP_WHITESPACE();
155
156 if (*input_line_pointer != ',') {
157 as_bad("Expected comma after name");
158 ignore_rest_of_line();
159 return;
160 }
161
162 ++input_line_pointer;
163
164 if ((size = get_absolute_expression()) < 0) {
165 as_bad("BSS length (%d.) <0! Ignored.", size);
166 ignore_rest_of_line();
167 return;
168 } /* bad length */
169
170 *p = 0;
171 symbolP = symbol_find_or_make(name);
172 *p = c;
173
174 if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) {
175 as_bad("bad .reserve segment: `%s'", input_line_pointer);
176 return;
177 } /* if not bss */
178
179 input_line_pointer += 6;
180 SKIP_WHITESPACE();
181
182 if (*input_line_pointer == ',') {
183 ++input_line_pointer;
184
185 SKIP_WHITESPACE();
186 if (*input_line_pointer == '\n') {
187 as_bad("Missing alignment");
188 return;
189 }
190
191 align = get_absolute_expression();
192 if (align > max_alignment){
193 align = max_alignment;
194 as_warn("Alignment too large: %d. assumed.", align);
195 } else if (align < 0) {
196 align = 0;
197 as_warn("Alignment negative. 0 assumed.");
198 }
199 #ifdef MANY_SEGMENTS
200 #define SEG_BSS SEG_E2
201 record_alignment(SEG_E2, align);
202 #else
203 record_alignment(SEG_BSS, align);
204 #endif
205
206 /* convert to a power of 2 alignment */
207 for (temp = 0; (align & 1) == 0; align >>= 1, ++temp) ;;
208
209 if (align != 1) {
210 as_bad("Alignment not a power of 2");
211 ignore_rest_of_line();
212 return;
213 } /* not a power of two */
214
215 align = temp;
216
217 /* Align */
218 align = ~((~0) << align); /* Convert to a mask */
219 local_bss_counter = (local_bss_counter + align) & (~align);
220 } /* if has optional alignment */
221
222 if (S_GET_OTHER(symbolP) == 0
223 && S_GET_DESC(symbolP) == 0
224 && ((S_GET_SEGMENT(symbolP) == SEG_BSS
225 && S_GET_VALUE(symbolP) == local_bss_counter)
226 || !S_IS_DEFINED(symbolP))) {
227 S_SET_VALUE(symbolP, local_bss_counter);
228 S_SET_SEGMENT(symbolP, SEG_BSS);
229 symbolP->sy_frag = &bss_address_frag;
230 local_bss_counter += size;
231 } else {
232 as_warn("Ignoring attempt to re-define symbol from %d. to %d.",
233 S_GET_VALUE(symbolP), local_bss_counter);
234 } /* if not redefining */
235
236 demand_empty_rest_of_line();
237 return;
238 } /* s_reserve() */
239
240 static void s_common() {
241 register char *name;
242 register char c;
243 register char *p;
244 register int temp;
245 register symbolS * symbolP;
246
247 name = input_line_pointer;
248 c = get_symbol_end();
249 /* just after name is now '\0' */
250 p = input_line_pointer;
251 *p = c;
252 SKIP_WHITESPACE();
253 if (* input_line_pointer != ',') {
254 as_bad("Expected comma after symbol-name");
255 ignore_rest_of_line();
256 return;
257 }
258 input_line_pointer ++; /* skip ',' */
259 if ((temp = get_absolute_expression ()) < 0) {
260 as_bad(".COMMon length (%d.) <0! Ignored.", temp);
261 ignore_rest_of_line();
262 return;
263 }
264 *p = 0;
265 symbolP = symbol_find_or_make(name);
266 *p = c;
267 if (S_IS_DEFINED(symbolP)) {
268 as_bad("Ignoring attempt to re-define symbol");
269 ignore_rest_of_line();
270 return;
271 }
272 if (S_GET_VALUE(symbolP) != 0) {
273 if (S_GET_VALUE(symbolP) != temp) {
274 as_warn("Length of .comm \"%s\" is already %d. Not changed to %d.",
275 S_GET_NAME(symbolP), S_GET_VALUE(symbolP), temp);
276 }
277 } else {
278 S_SET_VALUE(symbolP, temp);
279 S_SET_EXTERNAL(symbolP);
280 }
281 know(symbolP->sy_frag == &zero_address_frag);
282 if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0
283 && strncmp(input_line_pointer, ",\"data\"", 7) != 0) {
284 p=input_line_pointer;
285 while(*p && *p!='\n')
286 p++;
287 c= *p;
288 *p='\0';
289 as_bad("bad .common segment: `%s'", input_line_pointer);
290 *p=c;
291 return;
292 }
293 input_line_pointer += 6 + (input_line_pointer[2] == 'd'); /* Skip either */
294 demand_empty_rest_of_line();
295 return;
296 } /* s_common() */
297
298 static void s_seg() {
299
300 if (strncmp(input_line_pointer, "\"text\"", 6) == 0) {
301 input_line_pointer += 6;
302 s_text();
303 return;
304 }
305 if (strncmp(input_line_pointer, "\"data\"", 6) == 0) {
306 input_line_pointer += 6;
307 s_data();
308 return;
309 }
310 if (strncmp(input_line_pointer, "\"data1\"", 7) == 0) {
311 input_line_pointer += 7;
312 s_data1();
313 return;
314 }
315 if (strncmp(input_line_pointer, "\"bss\"", 5) == 0) {
316 input_line_pointer += 5;
317 /* We only support 2 segments -- text and data -- for now, so
318 things in the "bss segment" will have to go into data for now.
319 You can still allocate SEG_BSS stuff with .lcomm or .reserve. */
320 subseg_new(SEG_DATA, 255); /* FIXME-SOMEDAY */
321 return;
322 }
323 as_bad("Unknown segment type");
324 demand_empty_rest_of_line();
325 return;
326 } /* s_seg() */
327
328 static void s_data1() {
329 subseg_new(SEG_DATA, 1);
330 demand_empty_rest_of_line();
331 return;
332 } /* s_data1() */
333
334 static void s_proc() {
335 extern char is_end_of_line[];
336
337 while (!is_end_of_line[*input_line_pointer]) {
338 ++input_line_pointer;
339 }
340 ++input_line_pointer;
341 return;
342 } /* s_proc() */
343
344 /* This function is called once, at assembler startup time. It should
345 set up all the tables, etc. that the MD part of the assembler will need. */
346 void md_begin() {
347 register char *retval = NULL;
348 int lose = 0;
349 register unsigned int i = 0;
350
351 op_hash = hash_new();
352 if (op_hash == NULL)
353 as_fatal("Virtual memory exhausted");
354
355 while (i < NUMOPCODES) {
356 const char *name = sparc_opcodes[i].name;
357 retval = hash_insert(op_hash, name, &sparc_opcodes[i]);
358 if(retval != NULL && *retval != '\0') {
359 fprintf (stderr, "internal error: can't hash `%s': %s\n",
360 sparc_opcodes[i].name, retval);
361 lose = 1;
362 }
363 do
364 {
365 if (sparc_opcodes[i].match & sparc_opcodes[i].lose) {
366 fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
367 sparc_opcodes[i].name, sparc_opcodes[i].args);
368 lose = 1;
369 }
370 ++i;
371 } while (i < NUMOPCODES
372 && !strcmp(sparc_opcodes[i].name, name));
373 }
374
375 if (lose)
376 as_fatal("Broken assembler. No assembly attempted.");
377
378 for (i = '0'; i < '8'; ++i)
379 octal[i] = 1;
380 for (i = '0'; i <= '9'; ++i)
381 toHex[i] = i - '0';
382 for (i = 'a'; i <= 'f'; ++i)
383 toHex[i] = i + 10 - 'a';
384 for (i = 'A'; i <= 'F'; ++i)
385 toHex[i] = i + 10 - 'A';
386 } /* md_begin() */
387
388 void md_end() {
389 return;
390 } /* md_end() */
391
392 void md_assemble(str)
393 char *str;
394 {
395 char *toP;
396 int rsd;
397
398 know(str);
399 sparc_ip(str);
400
401 /* See if "set" operand is absolute and small; skip sethi if so. */
402 if (special_case == SPECIAL_CASE_SET && the_insn.exp.X_seg == SEG_ABSOLUTE) {
403 if (the_insn.exp.X_add_number >= -(1<<12)
404 && the_insn.exp.X_add_number < (1<<12)) {
405 the_insn.opcode = 0x80102000 /* or %g0,imm,... */
406 | (the_insn.opcode & 0x3E000000) /* dest reg */
407 | (the_insn.exp.X_add_number & 0x1FFF); /* imm */
408 special_case = 0; /* No longer special */
409 the_insn.reloc = NO_RELOC; /* No longer relocated */
410 }
411 }
412
413 toP = frag_more(4);
414 /* put out the opcode */
415 md_number_to_chars(toP, the_insn.opcode, 4);
416
417 /* put out the symbol-dependent stuff */
418 if (the_insn.reloc != NO_RELOC) {
419 fix_new(frag_now, /* which frag */
420 (toP - frag_now->fr_literal), /* where */
421 4, /* size */
422 the_insn.exp.X_add_symbol,
423 the_insn.exp.X_subtract_symbol,
424 the_insn.exp.X_add_number,
425 the_insn.pcrel,
426 the_insn.reloc);
427 }
428 switch (special_case) {
429
430 case SPECIAL_CASE_SET:
431 special_case = 0;
432 assert(the_insn.reloc == RELOC_HI22);
433 /* See if "set" operand has no low-order bits; skip OR if so. */
434 if (the_insn.exp.X_seg == SEG_ABSOLUTE
435 && ((the_insn.exp.X_add_number & 0x3FF) == 0))
436 return;
437 toP = frag_more(4);
438 rsd = (the_insn.opcode >> 25) & 0x1f;
439 the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);
440 md_number_to_chars(toP, the_insn.opcode, 4);
441 fix_new(frag_now, /* which frag */
442 (toP - frag_now->fr_literal), /* where */
443 4, /* size */
444 the_insn.exp.X_add_symbol,
445 the_insn.exp.X_subtract_symbol,
446 the_insn.exp.X_add_number,
447 the_insn.pcrel,
448 RELOC_LO10);
449 return;
450
451 case SPECIAL_CASE_FDIV:
452 /* According to information leaked from Sun, the "fdiv" instructions
453 on early SPARC machines would produce incorrect results sometimes.
454 The workaround is to add an fmovs of the destination register to
455 itself just after the instruction. This was true on machines
456 with Weitek 1165 float chips, such as the Sun-4/260 and /280. */
457 special_case = 0;
458 assert(the_insn.reloc == NO_RELOC);
459 toP = frag_more(4);
460 rsd = (the_insn.opcode >> 25) & 0x1f;
461 the_insn.opcode = 0x81A00020 | (rsd << 25) | rsd; /* fmovs dest,dest */
462 md_number_to_chars(toP, the_insn.opcode, 4);
463 return;
464
465 case 0:
466 return;
467
468 default:
469 as_fatal("failed sanity check.");
470 }
471 } /* md_assemble() */
472
473 static void sparc_ip(str)
474 char *str;
475 {
476 char *error_message = "";
477 char *s;
478 const char *args;
479 char c;
480 struct sparc_opcode *insn;
481 char *argsStart;
482 unsigned long opcode;
483 unsigned int mask = 0;
484 int match = 0;
485 int comma = 0;
486
487 for (s = str; islower(*s) || (*s >= '0' && *s <= '3'); ++s)
488 ;
489 switch (*s) {
490
491 case '\0':
492 break;
493
494 case ',':
495 comma = 1;
496
497 /*FALLTHROUGH */
498
499 case ' ':
500 *s++ = '\0';
501 break;
502
503 default:
504 as_bad("Unknown opcode: `%s'", str);
505 exit(1);
506 }
507 if ((insn = (struct sparc_opcode *) hash_find(op_hash, str)) == NULL) {
508 as_bad("Unknown opcode: `%s'", str);
509 return;
510 }
511 if (comma) {
512 *--s = ',';
513 }
514 argsStart = s;
515 for (;;) {
516 opcode = insn->match;
517 bzero(&the_insn, sizeof(the_insn));
518 the_insn.reloc = NO_RELOC;
519
520 /*
521 * Build the opcode, checking as we go to make
522 * sure that the operands match
523 */
524 for (args = insn->args; ; ++args) {
525 switch (*args) {
526
527 case 'M':
528 case 'm':
529 if (strncmp(s, "%asr", 4) == 0) {
530 s += 4;
531
532 if (isdigit(*s)) {
533 long num = 0;
534
535 while (isdigit(*s)) {
536 num = num*10 + *s-'0';
537 ++s;
538 }
539
540 if (num < 16 || 31 < num) {
541 error_message = ": asr number must be between 15 and 31";
542 goto error;
543 } /* out of range */
544
545 opcode |= (*args == 'M' ? RS1(num) : RD(num));
546 continue;
547 } else {
548 error_message = ": expecting %asrN";
549 goto error;
550 } /* if %asr followed by a number. */
551
552 } /* if %asr */
553 break;
554
555 /* start-sanitize-v9 */
556 #ifndef NO_V9
557 case 'I':
558 the_insn.reloc = RELOC_11;
559 goto immediate;
560
561 case 'k':
562 the_insn.reloc = RELOC_WDISP2_14;
563 the_insn.pcrel = 1;
564 goto immediate;
565
566 case 'G':
567 the_insn.reloc = RELOC_WDISP19;
568 the_insn.pcrel = 1;
569 goto immediate;
570
571 case 'N':
572 if (*s == 'p' && s[1] == 'n') {
573 s += 2;
574 continue;
575 }
576 break;
577
578 case 'T':
579 if (*s == 'p' && s[1] == 't') {
580 s += 2;
581 continue;
582 }
583 break;
584
585 case 'Y':
586 if (strncmp(s, "%amr", 4) == 0) {
587 s += 4;
588 continue;
589 }
590 break;
591
592 case 'z':
593 if (*s == ' ') {
594 ++s;
595 }
596 if (strncmp(s, "icc", 3) == 0) {
597 s += 3;
598 continue;
599 }
600 break;
601
602 case 'Z':
603 if (*s == ' ') {
604 ++s;
605 }
606 if (strncmp(s, "xcc", 3) == 0) {
607 s += 3;
608 continue;
609 }
610 break;
611
612 case '6':
613 if (*s == ' ') {
614 ++s;
615 }
616 if (strncmp(s, "fcc0", 4) == 0) {
617 s += 4;
618 continue;
619 }
620 break;
621
622 case '7':
623 if (*s == ' ') {
624 ++s;
625 }
626 if (strncmp(s, "fcc1", 4) == 0) {
627 s += 4;
628 continue;
629 }
630 break;
631
632 case '8':
633 if (*s == ' ') {
634 ++s;
635 }
636 if (strncmp(s, "fcc2", 4) == 0) {
637 s += 4;
638 continue;
639 }
640 break;
641
642 case '9':
643 if (*s == ' ') {
644 ++s;
645 }
646 if (strncmp(s, "fcc3", 4) == 0) {
647 s += 4;
648 continue;
649 }
650 break;
651
652 case 'P':
653 if (strncmp(s, "%pc", 3) == 0) {
654 s += 3;
655 continue;
656 }
657 break;
658
659 case 'E':
660 if (strncmp(s, "%modes", 6) == 0) {
661 s += 6;
662 continue;
663 }
664 break;
665
666 case 'W':
667 if (strncmp(s, "%tick", 5) == 0) {
668 s += 5;
669 continue;
670 }
671 break;
672 #endif /* NO_V9 */
673 /* end-sanitize-v9 */
674
675 case '\0': /* end of args */
676 if (*s == '\0') {
677 match = 1;
678 }
679 break;
680
681 case '+':
682 if (*s == '+') {
683 ++s;
684 continue;
685 }
686 if (*s == '-') {
687 continue;
688 }
689 break;
690
691 case '[': /* these must match exactly */
692 case ']':
693 case ',':
694 case ' ':
695 if (*s++ == *args)
696 continue;
697 break;
698
699 case '#': /* must be at least one digit */
700 if (isdigit(*s++)) {
701 while (isdigit(*s)) {
702 ++s;
703 }
704 continue;
705 }
706 break;
707
708 case 'C': /* coprocessor state register */
709 if (strncmp(s, "%csr", 4) == 0) {
710 s += 4;
711 continue;
712 }
713 break;
714
715 case 'b': /* next operand is a coprocessor register */
716 case 'c':
717 case 'D':
718 if (*s++ == '%' && *s++ == 'c' && isdigit(*s)) {
719 mask = *s++;
720 if (isdigit(*s)) {
721 mask = 10 * (mask - '0') + (*s++ - '0');
722 if (mask >= 32) {
723 break;
724 }
725 } else {
726 mask -= '0';
727 }
728 switch (*args) {
729
730 case 'b':
731 opcode |= mask << 14;
732 continue;
733
734 case 'c':
735 opcode |= mask;
736 continue;
737
738 case 'D':
739 opcode |= mask << 25;
740 continue;
741 }
742 }
743 break;
744
745 case 'r': /* next operand must be a register */
746 case '1':
747 case '2':
748 case 'd':
749 if (*s++ == '%') {
750 switch (c = *s++) {
751
752 case 'f': /* frame pointer */
753 if (*s++ == 'p') {
754 mask = 0x1e;
755 break;
756 }
757 goto error;
758
759 case 'g': /* global register */
760 if (isoctal(c = *s++)) {
761 mask = c - '0';
762 break;
763 }
764 goto error;
765
766 case 'i': /* in register */
767 if (isoctal(c = *s++)) {
768 mask = c - '0' + 24;
769 break;
770 }
771 goto error;
772
773 case 'l': /* local register */
774 if (isoctal(c = *s++)) {
775 mask= (c - '0' + 16) ;
776 break;
777 }
778 goto error;
779
780 case 'o': /* out register */
781 if (isoctal(c = *s++)) {
782 mask= (c - '0' + 8) ;
783 break;
784 }
785 goto error;
786
787 case 's': /* stack pointer */
788 if (*s++ == 'p') {
789 mask= 0xe;
790 break;
791 }
792 goto error;
793
794 case 'r': /* any register */
795 if (!isdigit(c = *s++)) {
796 goto error;
797 }
798 /* FALLTHROUGH */
799 case '0': case '1': case '2': case '3': case '4':
800 case '5': case '6': case '7': case '8': case '9':
801 if (isdigit(*s)) {
802 if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
803 goto error;
804 }
805 } else {
806 c -= '0';
807 }
808 mask= c;
809 break;
810
811 default:
812 goto error;
813 }
814 /*
815 * Got the register, now figure out where
816 * it goes in the opcode.
817 */
818 switch (*args) {
819
820 case '1':
821 opcode |= mask << 14;
822 continue;
823
824 case '2':
825 opcode |= mask;
826 continue;
827
828 case 'd':
829 opcode |= mask << 25;
830 continue;
831
832 case 'r':
833 opcode |= (mask << 25) | (mask << 14);
834 continue;
835 }
836 }
837 break;
838
839 /* start-sanitize-v9 */
840 #ifndef NO_V9
841 case 'j':
842 case 'u':
843 case 'U':
844 #endif /* NO_V9 */
845 /* end-sanitize-v9 */
846 case 'e': /* next operand is a floating point register */
847 case 'v':
848 case 'V':
849
850 case 'f':
851 case 'B':
852 case 'R':
853
854 case 'g':
855 case 'H':
856 case 'J': {
857 char format;
858
859 if (*s++ == '%'
860
861 /* start-sanitize-v9 */
862 #ifndef NO_V9
863 && ((format = *s) == 'f'
864 || *s == 'd'
865 || *s == 'q')
866 #else
867 /* end-sanitize-v9 */
868 && ((format = *s) == 'f')
869
870 /* start-sanitize-v9 */
871 #endif /* NO_V9 */
872 /* end-sanitize-v9 */
873 && isdigit(*++s)) {
874
875
876
877 for (mask = 0; isdigit(*s); ++s) {
878 mask = 10 * mask + (*s - '0');
879 } /* read the number */
880
881 if ((*args == 'u'
882 || *args == 'v'
883 || *args == 'B'
884 || *args == 'H')
885 && (mask & 1)) {
886 break;
887 } /* register must be even numbered */
888
889 if ((*args == 'U'
890 || *args == 'V'
891 || *args == 'R'
892 || *args == 'J')
893 && (mask & 3)) {
894 break;
895 } /* register must be multiple of 4 */
896
897 if (format == 'f') {
898 if (mask >= 32) {
899 error_message = ": There are only 32 f registers; [0-31]";
900 goto error;
901 } /* on error */
902 /* start-sanitize-v9 */
903 #ifndef NO_V9
904 } else {
905 if (format == 'd') {
906 if (mask >= 64) {
907 error_message = ": There are only 32 d registers [0, 2, ... 62].";
908 goto error;
909 } else if (mask & 1) {
910 error_message = ": Only even numbered d registers exist.";
911 goto error;
912 } /* on error */
913
914 } else if (format == 'q') {
915 if (mask >= 64) {
916 error_message =
917 ": There are only 16 q registers [0, 4, ... 60].";
918 goto error;
919 } else if (mask & 3) {
920 error_message =
921 ": Only q registers evenly divisible by four exist.";
922 goto error;
923 } /* on error */
924 } else {
925 know(0);
926 } /* depending on format */
927
928 if (mask >= 32) {
929 mask -= 31;
930 } /* wrap high bit */
931 #endif /* NO_V9 */
932 /* end-sanitize-v9 */
933 } /* if not an 'f' register. */
934 } /* on error */
935
936 switch (*args) {
937 /* start-sanitize-v9 */
938 #ifndef NO_V9
939 case 'j':
940 case 'u':
941 case 'U':
942 opcode |= (mask & 0x1f) << 9;
943 continue;
944 #endif /* NO_V9 */
945 /* end-sanitize-v9 */
946
947 case 'v':
948 case 'V':
949 case 'e':
950 opcode |= RS1(mask);
951 continue;
952
953
954 case 'f':
955 case 'B':
956 case 'R':
957 opcode |= RS2(mask);
958 continue;
959
960 case 'g':
961 case 'H':
962 case 'J':
963 opcode |= RD(mask);
964 continue;
965 } /* pack it in. */
966
967 know(0);
968 break;
969 } /* float arg */
970
971 case 'F':
972 if (strncmp(s, "%fsr", 4) == 0) {
973 s += 4;
974 continue;
975 }
976 break;
977
978 case 'h': /* high 22 bits */
979 the_insn.reloc = RELOC_HI22;
980 goto immediate;
981
982 case 'l': /* 22 bit PC relative immediate */
983 the_insn.reloc = RELOC_WDISP22;
984 the_insn.pcrel = 1;
985 goto immediate;
986
987 case 'L': /* 30 bit immediate */
988 the_insn.reloc = RELOC_WDISP30;
989 the_insn.pcrel = 1;
990 goto immediate;
991
992 case 'n': /* 22 bit immediate */
993 the_insn.reloc = RELOC_22;
994 goto immediate;
995
996 case 'i': /* 13 bit immediate */
997 the_insn.reloc = RELOC_BASE13;
998
999 /*FALLTHROUGH */
1000
1001 immediate:
1002 if(*s==' ')
1003 s++;
1004 if (*s == '%') {
1005 if ((c = s[1]) == 'h' && s[2] == 'i') {
1006 the_insn.reloc = RELOC_HI22;
1007 s+=3;
1008 } else if (c == 'l' && s[2] == 'o') {
1009 the_insn.reloc = RELOC_LO10;
1010 s+=3;
1011 /* start-sanitize-v9 */
1012 #ifndef NO_V9
1013 } else if (c == 'h'
1014 && s[2] == 'h'
1015 && s[3] == 'i') {
1016 the_insn.reloc = RELOC_HHI22;
1017 s += 4;
1018
1019 } else if (c == 'h'
1020 && s[2] == 'l'
1021 && s[3] == 'o') {
1022 the_insn.reloc = RELOC_HLO10;
1023 s += 4;
1024 #endif /* NO_V9 */
1025 /* end-sanitize-v9 */
1026 } else
1027 break;
1028 }
1029 /* Note that if the getExpression() fails, we
1030 will still have created U entries in the
1031 symbol table for the 'symbols' in the input
1032 string. Try not to create U symbols for
1033 registers, etc. */
1034 {
1035 /* This stuff checks to see if the
1036 expression ends in +%reg If it does,
1037 it removes the register from the
1038 expression, and re-sets 's' to point
1039 to the right place */
1040
1041 char *s1;
1042
1043 for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ;;
1044
1045 if (s1 != s && isdigit(s1[-1])) {
1046 if(s1[-2] == '%' && s1[-3] == '+') {
1047 s1 -= 3;
1048 *s1 = '\0';
1049 (void) getExpression(s);
1050 *s1 = '+';
1051 s = s1;
1052 continue;
1053 } else if (strchr("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+') {
1054 s1 -= 4;
1055 *s1 = '\0';
1056 (void) getExpression(s);
1057 *s1 = '+';
1058 s = s1;
1059 continue;
1060 }
1061 }
1062 }
1063 (void)getExpression(s);
1064 s = expr_end;
1065 continue;
1066
1067 case 'a':
1068 if (*s++ == 'a') {
1069 opcode |= ANNUL;
1070 continue;
1071 }
1072 break;
1073
1074 case 'A': {
1075 char *push = input_line_pointer;
1076 expressionS e;
1077
1078 input_line_pointer = s;
1079
1080 if (expression(&e) == SEG_ABSOLUTE) {
1081 opcode |= e.X_add_number << 5;
1082 s = input_line_pointer;
1083 input_line_pointer = push;
1084 continue;
1085 } /* if absolute */
1086
1087 break;
1088 } /* alternate space */
1089
1090 case 'p':
1091 if (strncmp(s, "%psr", 4) == 0) {
1092 s += 4;
1093 continue;
1094 }
1095 break;
1096
1097 case 'q': /* floating point queue */
1098 if (strncmp(s, "%fq", 3) == 0) {
1099 s += 3;
1100 continue;
1101 }
1102 break;
1103
1104 case 'Q': /* coprocessor queue */
1105 if (strncmp(s, "%cq", 3) == 0) {
1106 s += 3;
1107 continue;
1108 }
1109 break;
1110
1111 case 'S':
1112 if (strcmp(str, "set") == 0) {
1113 special_case = SPECIAL_CASE_SET;
1114 continue;
1115 } else if (strncmp(str, "fdiv", 4) == 0) {
1116 special_case = SPECIAL_CASE_FDIV;
1117 continue;
1118 }
1119 break;
1120
1121 case 't':
1122 if (strncmp(s, "%tbr", 4) != 0)
1123 break;
1124 s += 4;
1125 continue;
1126
1127 case 'w':
1128 if (strncmp(s, "%wim", 4) != 0)
1129 break;
1130 s += 4;
1131 continue;
1132
1133 case 'y':
1134 if (strncmp(s, "%y", 2) != 0)
1135 break;
1136 s += 2;
1137 continue;
1138
1139 default:
1140 as_fatal("failed sanity check.");
1141 } /* switch on arg code */
1142 break;
1143 } /* for each arg that we expect */
1144 error:
1145 if (match == 0) {
1146 /* Args don't match. */
1147 if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES
1148 && !strcmp(insn->name, insn[1].name)) {
1149 ++insn;
1150 s = argsStart;
1151 continue;
1152 } else {
1153 as_bad("Illegal operands%s", error_message);
1154 return;
1155 }
1156 } else {
1157 if (insn->architecture > current_architecture) {
1158 if (!architecture_requested || warn_on_bump) {
1159
1160 if (warn_on_bump) {
1161 as_warn("architecture bumped from \"%s\" to \"%s\" on \"%s\"",
1162 architecture_pname[current_architecture],
1163 architecture_pname[insn->architecture],
1164 str);
1165 } /* if warning */
1166
1167 current_architecture = insn->architecture;
1168 } else {
1169 as_bad("architecture mismatch on \"%s\" (\"%s\"). current architecture is \"%s\"",
1170 str,
1171 architecture_pname[insn->architecture],
1172 architecture_pname[current_architecture]);
1173 return;
1174 } /* if bump ok else error */
1175 } /* if architecture higher */
1176 } /* if no match */
1177
1178 break;
1179 } /* forever looking for a match */
1180
1181 the_insn.opcode = opcode;
1182 return;
1183 } /* sparc_ip() */
1184
1185 static int getExpression(str)
1186 char *str;
1187 {
1188 char *save_in;
1189 segT seg;
1190
1191 save_in = input_line_pointer;
1192 input_line_pointer = str;
1193 switch (seg = expression(&the_insn.exp)) {
1194
1195 case SEG_ABSOLUTE:
1196 case SEG_TEXT:
1197 case SEG_DATA:
1198 case SEG_BSS:
1199 case SEG_UNKNOWN:
1200 case SEG_DIFFERENCE:
1201 case SEG_BIG:
1202 case SEG_ABSENT:
1203 break;
1204
1205 default:
1206 the_insn.error = "bad segment";
1207 expr_end = input_line_pointer;
1208 input_line_pointer=save_in;
1209 return 1;
1210 }
1211 expr_end = input_line_pointer;
1212 input_line_pointer = save_in;
1213 return 0;
1214 } /* getExpression() */
1215
1216
1217 /*
1218 This is identical to the md_atof in m68k.c. I think this is right,
1219 but I'm not sure.
1220
1221 Turn a string in input_line_pointer into a floating point constant of type
1222 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1223 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1224 */
1225
1226 /* Equal to MAX_PRECISION in atof-ieee.c */
1227 #define MAX_LITTLENUMS 6
1228
1229 char *md_atof(type,litP,sizeP)
1230 char type;
1231 char *litP;
1232 int *sizeP;
1233 {
1234 int prec;
1235 LITTLENUM_TYPE words[MAX_LITTLENUMS];
1236 LITTLENUM_TYPE *wordP;
1237 char *t;
1238 char *atof_ieee();
1239
1240 switch(type) {
1241
1242 case 'f':
1243 case 'F':
1244 case 's':
1245 case 'S':
1246 prec = 2;
1247 break;
1248
1249 case 'd':
1250 case 'D':
1251 case 'r':
1252 case 'R':
1253 prec = 4;
1254 break;
1255
1256 case 'x':
1257 case 'X':
1258 prec = 6;
1259 break;
1260
1261 case 'p':
1262 case 'P':
1263 prec = 6;
1264 break;
1265
1266 default:
1267 *sizeP=0;
1268 return "Bad call to MD_ATOF()";
1269 }
1270 t=atof_ieee(input_line_pointer,type,words);
1271 if(t)
1272 input_line_pointer=t;
1273 *sizeP=prec * sizeof(LITTLENUM_TYPE);
1274 for(wordP=words;prec--;) {
1275 md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
1276 litP+=sizeof(LITTLENUM_TYPE);
1277 }
1278 return ""; /* Someone should teach Dean about null pointers */
1279 } /* md_atof() */
1280
1281 /*
1282 * Write out big-endian.
1283 */
1284 void md_number_to_chars(buf,val,n)
1285 char *buf;
1286 long val;
1287 int n;
1288 {
1289
1290 switch(n) {
1291
1292 case 4:
1293 *buf++ = val >> 24;
1294 *buf++ = val >> 16;
1295 case 2:
1296 *buf++ = val >> 8;
1297 case 1:
1298 *buf = val;
1299 break;
1300
1301 default:
1302 as_fatal("failed sanity check.");
1303 }
1304 return;
1305 } /* md_number_to_chars() */
1306
1307 /* Apply a fixS to the frags, now that we know the value it ought to
1308 hold. */
1309
1310 void md_apply_fix(fixP, val)
1311 fixS *fixP;
1312 long val;
1313 {
1314 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1315
1316 assert(fixP->fx_size == 4);
1317 assert(fixP->fx_r_type < NO_RELOC);
1318
1319 fixP->fx_addnumber = val; /* Remember value for emit_reloc */
1320
1321 /*
1322 * This is a hack. There should be a better way to
1323 * handle this.
1324 */
1325 if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) {
1326 val += fixP->fx_where + fixP->fx_frag->fr_address;
1327 }
1328
1329 switch (fixP->fx_r_type) {
1330
1331 case RELOC_32:
1332 buf[0] = 0; /* val >> 24; */
1333 buf[1] = 0; /* val >> 16; */
1334 buf[2] = 0; /* val >> 8; */
1335 buf[3] = 0; /* val; */
1336 break;
1337
1338 #if 0
1339 case RELOC_8: /* These don't seem to ever be needed. */
1340 case RELOC_16:
1341 case RELOC_DISP8:
1342 case RELOC_DISP16:
1343 case RELOC_DISP32:
1344 #endif
1345 case RELOC_WDISP30:
1346 val = (val >>= 2) + 1;
1347 buf[0] |= (val >> 24) & 0x3f;
1348 buf[1]= (val >> 16);
1349 buf[2] = val >> 8;
1350 buf[3] = val;
1351 break;
1352
1353 /* start-sanitize-v9 */
1354 #ifndef NO_V9
1355 case RELOC_11:
1356 if (((val > 0) && (val & ~0x7ff))
1357 || ((val < 0) && (~(val - 1) & ~0x7ff))) {
1358 as_bad("relocation overflow.");
1359 } /* on overflow */
1360
1361 buf[2] = (val >> 8) & 0x7;
1362 buf[3] = val & 0xff;
1363 break;
1364
1365 case RELOC_WDISP2_14:
1366 if (((val > 0) && (val & ~0x3fffc))
1367 || ((val < 0) && (~(val - 1) & ~0x3fffc))) {
1368 as_bad("relocation overflow.");
1369 } /* on overflow */
1370
1371 val = (val >>= 2) + 1;
1372 buf[1] |= ((val >> 14) & 0x3) << 3;
1373 buf[2] |= (val >> 8) & 0x3f ;
1374 buf[3] = val & 0xff;
1375 break;
1376
1377 case RELOC_WDISP19:
1378 if (((val > 0) && (val & ~0x1ffffc))
1379 || ((val < 0) && (~(val - 1) & ~0x1ffffc))) {
1380 as_bad("relocation overflow.");
1381 } /* on overflow */
1382
1383 val = (val >>= 2) + 1;
1384 buf[1] |= (val >> 16) & 0x7;
1385 buf[2] = (val >> 8) & 0xff;
1386 buf[3] = val & 0xff;
1387 break;
1388
1389 case RELOC_HHI22:
1390 val >>= 32;
1391 /* intentional fallthrough */
1392 #endif /* NO_V9 */
1393 /* end-sanitize-v9 */
1394
1395 case RELOC_HI22:
1396 if(!fixP->fx_addsy) {
1397 buf[1] |= (val >> 26) & 0x3f;
1398 buf[2] = val >> 18;
1399 buf[3] = val >> 10;
1400 } else {
1401 buf[2]=0;
1402 buf[3]=0;
1403 }
1404 break;
1405
1406 case RELOC_22:
1407 if (val & ~0x003fffff) {
1408 as_bad("relocation overflow");
1409 } /* on overflow */
1410 buf[1] |= (val >> 16) & 0x3f;
1411 buf[2] = val >> 8;
1412 buf[3] = val & 0xff;
1413 break;
1414
1415 case RELOC_13:
1416 if (val & ~0x00001fff) {
1417 as_bad("relocation overflow");
1418 } /* on overflow */
1419 buf[2] = (val >> 8) & 0x1f;
1420 buf[3] = val & 0xff;
1421 break;
1422
1423 /* start-sanitize-v9 */
1424 #ifndef NO_V9
1425 case RELOC_HLO10:
1426 val >>= 32;
1427 /* intentional fallthrough */
1428 #endif /* NO_V9 */
1429 /* end-sanitize-v9 */
1430
1431 case RELOC_LO10:
1432 if(!fixP->fx_addsy) {
1433 buf[2] |= (val >> 8) & 0x03;
1434 buf[3] = val;
1435 } else
1436 buf[3]=0;
1437 break;
1438 #if 0
1439 case RELOC_SFA_BASE:
1440 case RELOC_SFA_OFF13:
1441 case RELOC_BASE10:
1442 #endif
1443 case RELOC_BASE13:
1444 buf[2] |= (val >> 8) & 0x1f;
1445 buf[3] = val;
1446 break;
1447
1448 case RELOC_WDISP22:
1449 val = (val >>= 2) + 1;
1450 /* FALLTHROUGH */
1451 case RELOC_BASE22:
1452 buf[1] |= (val >> 16) & 0x3f;
1453 buf[2] = val >> 8;
1454 buf[3] = val;
1455 break;
1456
1457 #if 0
1458 case RELOC_PC10:
1459 case RELOC_PC22:
1460 case RELOC_JMP_TBL:
1461 case RELOC_SEGOFF16:
1462 case RELOC_GLOB_DAT:
1463 case RELOC_JMP_SLOT:
1464 case RELOC_RELATIVE:
1465 #endif
1466
1467 case NO_RELOC:
1468 default:
1469 as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
1470 break;
1471 }
1472 } /* md_apply_fix() */
1473
1474 /* should never be called for sparc */
1475 void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
1476 char *ptr;
1477 long from_addr;
1478 long to_addr;
1479 fragS *frag;
1480 symbolS *to_symbol;
1481 {
1482 as_fatal("sparc_create_short_jmp\n");
1483 } /* md_create_short_jump() */
1484
1485 /* Translate internal representation of relocation info to target format.
1486
1487 On sparc: first 4 bytes are normal unsigned long address, next three
1488 bytes are index, most sig. byte first. Byte 7 is broken up with
1489 bit 7 as external, bits 6 & 5 unused, and the lower
1490 five bits as relocation type. Next 4 bytes are long addend. */
1491 /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
1492 void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
1493 char *where;
1494 fixS *fixP;
1495 relax_addressT segment_address_in_file;
1496 {
1497 long r_index;
1498 long r_extern;
1499 long r_addend;
1500 long r_address;
1501
1502 know(fixP->fx_addsy);
1503
1504 if ((S_GET_TYPE(fixP->fx_addsy)) == N_UNDF) {
1505 r_extern = 1;
1506 r_index = fixP->fx_addsy->sy_number;
1507 } else {
1508 r_extern = 0;
1509 r_index = S_GET_TYPE(fixP->fx_addsy);
1510 }
1511
1512 /* this is easy */
1513 md_number_to_chars(where,
1514 r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
1515 4);
1516
1517 /* now the fun stuff */
1518 where[4] = (r_index >> 16) & 0x0ff;
1519 where[5] = (r_index >> 8) & 0x0ff;
1520 where[6] = r_index & 0x0ff;
1521 where[7] = ((r_extern << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F);
1522
1523 /* Also easy */
1524 if (fixP->fx_addsy->sy_frag) {
1525 r_addend = fixP->fx_addsy->sy_frag->fr_address;
1526 }
1527
1528 if (fixP->fx_pcrel) {
1529 r_addend -= r_address;
1530 } else {
1531 r_addend = fixP->fx_addnumber;
1532 }
1533
1534 md_number_to_chars(&where[8], r_addend, 4);
1535
1536 return;
1537 } /* tc_aout_fix_to_chars() */
1538
1539 /* should never be called for sparc */
1540 void md_convert_frag(headers, fragP)
1541 object_headers *headers;
1542 register fragS *fragP;
1543 {
1544 as_fatal("sparc_convert_frag\n");
1545 } /* md_convert_frag() */
1546
1547 /* should never be called for sparc */
1548 void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
1549 char *ptr;
1550 long from_addr, to_addr;
1551 fragS *frag;
1552 symbolS *to_symbol;
1553 {
1554 as_fatal("sparc_create_long_jump\n");
1555 } /* md_create_long_jump() */
1556
1557 /* should never be called for sparc */
1558 int md_estimate_size_before_relax(fragP, segtype)
1559 fragS *fragP;
1560 segT segtype;
1561 {
1562 as_fatal("sparc_estimate_size_before_relax\n");
1563 return(1);
1564 } /* md_estimate_size_before_relax() */
1565
1566 #if 0
1567 /* for debugging only */
1568 static void print_insn(insn)
1569 struct sparc_it *insn;
1570 {
1571 char *Reloc[] = {
1572 "RELOC_8",
1573 "RELOC_16",
1574 "RELOC_32",
1575 "RELOC_DISP8",
1576 "RELOC_DISP16",
1577 "RELOC_DISP32",
1578 "RELOC_WDISP30",
1579 "RELOC_WDISP22",
1580 "RELOC_HI22",
1581 "RELOC_22",
1582 "RELOC_13",
1583 "RELOC_LO10",
1584 "RELOC_SFA_BASE",
1585 "RELOC_SFA_OFF13",
1586 "RELOC_BASE10",
1587 "RELOC_BASE13",
1588 "RELOC_BASE22",
1589 "RELOC_PC10",
1590 "RELOC_PC22",
1591 "RELOC_JMP_TBL",
1592 "RELOC_SEGOFF16",
1593 "RELOC_GLOB_DAT",
1594 "RELOC_JMP_SLOT",
1595 "RELOC_RELATIVE",
1596 "NO_RELOC"
1597 };
1598
1599 if (insn->error) {
1600 fprintf(stderr, "ERROR: %s\n");
1601 }
1602 fprintf(stderr, "opcode=0x%08x\n", insn->opcode);
1603 fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]);
1604 fprintf(stderr, "exp = {
1605 \n");
1606 fprintf(stderr, "\t\tX_add_symbol = %s\n",
1607 ((insn->exp.X_add_symbol != NULL)
1608 ? ((S_GET_NAME(insn->exp.X_add_symbol) != NULL)
1609 ? S_GET_NAME(insn->exp.X_add_symbol)
1610 : "???")
1611 : "0"));
1612 fprintf(stderr, "\t\tX_sub_symbol = %s\n",
1613 ((insn->exp.X_subtract_symbol != NULL)
1614 ? (S_GET_NAME(insn->exp.X_subtract_symbol)
1615 ? S_GET_NAME(insn->exp.X_subtract_symbol)
1616 : "???")
1617 : "0"));
1618 fprintf(stderr, "\t\tX_add_number = %d\n",
1619 insn->exp.X_add_number);
1620 fprintf(stderr, "}\n");
1621 return;
1622 } /* print_insn() */
1623 #endif
1624
1625 /* Set the hook... */
1626
1627 /* void emit_sparc_reloc();
1628 void (*md_emit_relocations)() = emit_sparc_reloc; */
1629
1630 #ifdef comment
1631
1632 /*
1633 * Sparc/AM29K relocations are completely different, so it needs
1634 * this machine dependent routine to emit them.
1635 */
1636 #if defined(OBJ_AOUT) || defined(OBJ_BOUT)
1637 void emit_sparc_reloc(fixP, segment_address_in_file)
1638 register fixS *fixP;
1639 relax_addressT segment_address_in_file;
1640 {
1641 struct reloc_info_generic ri;
1642 register symbolS *symbolP;
1643 extern char *next_object_file_charP;
1644 /* long add_number; */
1645
1646 bzero((char *) &ri, sizeof(ri));
1647 for (; fixP; fixP = fixP->fx_next) {
1648
1649 if (fixP->fx_r_type >= NO_RELOC) {
1650 as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type);
1651 }
1652
1653 if ((symbolP = fixP->fx_addsy) != NULL) {
1654 ri.r_address = fixP->fx_frag->fr_address +
1655 fixP->fx_where - segment_address_in_file;
1656 if ((S_GET_TYPE(symbolP)) == N_UNDF) {
1657 ri.r_extern = 1;
1658 ri.r_index = symbolP->sy_number;
1659 } else {
1660 ri.r_extern = 0;
1661 ri.r_index = S_GET_TYPE(symbolP);
1662 }
1663 if (symbolP && symbolP->sy_frag) {
1664 ri.r_addend = symbolP->sy_frag->fr_address;
1665 }
1666 ri.r_type = fixP->fx_r_type;
1667 if (fixP->fx_pcrel) {
1668 /* ri.r_addend -= fixP->fx_where; */
1669 ri.r_addend -= ri.r_address;
1670 } else {
1671 ri.r_addend = fixP->fx_addnumber;
1672 }
1673
1674 md_ri_to_chars(next_object_file_charP, &ri);
1675 next_object_file_charP += md_reloc_size;
1676 }
1677 }
1678 return;
1679 } /* emit_sparc_reloc() */
1680 #endif /* aout or bout */
1681 #endif /* comment */
1682
1683 /*
1684 * md_parse_option
1685 * Invocation line includes a switch not recognized by the base assembler.
1686 * See if it's a processor-specific option. These are:
1687 *
1688 * -bump
1689 * Warn on architecture bumps. See also -A.
1690 *
1691 * -Av6, -Av7, -Av8
1692 * Select the architecture. Instructions or features not
1693 * supported by the selected architecture cause fatal errors.
1694 *
1695 * The default is to start at v6, and bump the architecture up
1696 * whenever an instruction is seen at a higher level.
1697 *
1698 * If -bump is specified, a warning is printing when bumping to
1699 * higher levels.
1700 *
1701 * If an architecture is specified, all instructions must match
1702 * that architecture. Any higher level instructions are flagged
1703 * as errors.
1704 *
1705 * if both an architecture and -bump are specified, the
1706 * architecture starts at the specified level, but bumps are
1707 * warnings.
1708 *
1709 */
1710 /* start-sanitize-v9 */
1711 /* There is also a -Av9 architecture option. xoxorich. */
1712 /* end-sanitize-v9 */
1713 int md_parse_option(argP, cntP, vecP)
1714 char **argP;
1715 int *cntP;
1716 char ***vecP;
1717 {
1718 char *p;
1719 const char **arch;
1720
1721 if (!strcmp(*argP,"bump")){
1722 warn_on_bump = 1;
1723
1724 } else if (**argP == 'A'){
1725 p = (*argP) + 1;
1726
1727 for (arch = architecture_pname; *arch != NULL; ++arch){
1728 if (strcmp(p, *arch) == 0){
1729 break;
1730 } /* found a match */
1731 } /* walk the pname table */
1732
1733 if (*arch == NULL){
1734 as_bad("unknown architecture: %s", p);
1735 } else {
1736 current_architecture = (enum sparc_architecture) (arch - architecture_pname);
1737 architecture_requested = 1;
1738 }
1739 } else {
1740 /* Unknown option */
1741 (*argP)++;
1742 return 0;
1743 }
1744 **argP = '\0'; /* Done parsing this switch */
1745 return 1;
1746 } /* md_parse_option() */
1747
1748 /* We have no need to default values of symbols. */
1749
1750 /* ARGSUSED */
1751 symbolS *md_undefined_symbol(name)
1752 char *name;
1753 {
1754 return 0;
1755 } /* md_undefined_symbol() */
1756
1757 /* Parse an operand that is machine-specific.
1758 We just return without modifying the expression if we have nothing
1759 to do. */
1760
1761 /* ARGSUSED */
1762 void md_operand(expressionP)
1763 expressionS *expressionP;
1764 {
1765 } /* md_operand() */
1766
1767 /* Round up a section size to the appropriate boundary. */
1768 long md_section_align (segment, size)
1769 segT segment;
1770 long size;
1771 {
1772 return (size + 7) & ~7; /* Round all sects to multiple of 8 */
1773 } /* md_section_align() */
1774
1775 /* Exactly what point is a PC-relative offset relative TO?
1776 On the sparc, they're relative to the address of the offset, plus
1777 its size. This gets us to the following instruction.
1778 (??? Is this right? FIXME-SOON) */
1779 long md_pcrel_from(fixP)
1780 fixS *fixP;
1781 {
1782 return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
1783 } /* md_pcrel_from() */
1784
1785 void tc_aout_pre_write_hook(headers)
1786 object_headers *headers;
1787 {
1788 H_SET_VERSION(headers, 1);
1789 return;
1790 } /* tc_aout_pre_write_hook() */
1791
1792 /*
1793 * Local Variables:
1794 * comment-column: 0
1795 * fill-column: 131
1796 * End:
1797 */
1798
1799 /* end of tc-sparc.c */