|
|
1.1 ! root 1: /* tc-sparc.c -- Assemble for the SPARC ! 2: Copyright (C) 1989, 1990, 1991, 1992 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 2, 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: /* relocation type for internal assembler use only */ ! 21: #define SPARC_RELOC_13 (127) ! 22: #define SPARC_RELOC_22 (126) ! 23: ! 24: #define cypress 1234 ! 25: ! 26: #undef DEBUGINSN ! 27: ! 28: #include <stdio.h> ! 29: #include <ctype.h> ! 30: #include "as.h" ! 31: #include "libc.h" ! 32: #include "md.h" ! 33: #include "messages.h" ! 34: #include "symbols.h" ! 35: ! 36: /* careful, this file includes data *declarations* */ ! 37: #include "sparc-opcode.h" ! 38: #include <mach-o/sparc/reloc.h> ! 39: ! 40: /* From GNU ansidecl.h */ ! 41: #define PARAMS(paramlist) paramlist ! 42: ! 43: typedef long offsetT; ! 44: ! 45: /* ! 46: * These are the default cputype and cpusubtype for the Sparc architecture. ! 47: */ ! 48: const cpu_type_t md_cputype = CPU_TYPE_SPARC; ! 49: cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_SPARC_ALL; ! 50: ! 51: /* This is the byte sex for the Sparc architecture */ ! 52: const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX; ! 53: ! 54: /* These characters start a comment anywhere on the line */ ! 55: const char md_comment_chars[] = ";!"; ! 56: ! 57: /* These characters only start a comment at the beginning of a line */ ! 58: const char md_line_comment_chars[] = "#"; ! 59: ! 60: /* ! 61: * These characters can be used to separate mantissa decimal digits from ! 62: * exponent decimal digits in floating point numbers. ! 63: */ ! 64: const char md_EXP_CHARS[] = "eE"; ! 65: ! 66: /* ! 67: * The characters after a leading 0 that means this number is a floating point ! 68: * constant as in 0f123.456 or 0d1.234E-12 (see md_EXP_CHARS above). ! 69: */ ! 70: const char md_FLT_CHARS[] = "dDfF"; ! 71: ! 72: static void sparc_ip PARAMS ((char *)); ! 73: ! 74: static enum sparc_architecture current_architecture = v6; ! 75: static int architecture_requested; ! 76: static int warn_on_bump; ! 77: ! 78: const relax_typeS md_relax_table[1]; ! 79: ! 80: /* handle of the OPCODE hash table */ ! 81: static struct hash_control *op_hash = NULL; ! 82: ! 83: #ifdef NeXT ! 84: static void s_proc PARAMS ((int)); ! 85: static void s_ignore PARAMS ((int)); ! 86: extern void s_seg PARAMS ((int)); ! 87: #else NeXT ! 88: static void s_data1 PARAMS ((void)); ! 89: static void s_seg PARAMS ((int)); ! 90: static void s_proc PARAMS ((int)); ! 91: static void s_reserve PARAMS ((int)); ! 92: static void s_common PARAMS ((int)); ! 93: #endif NeXT ! 94: ! 95: const pseudo_typeS md_pseudo_table[] = ! 96: { ! 97: #ifdef NeXT ! 98: {"global", s_globl, 0}, /* Maybe we should fix compiler to use globl */ ! 99: {"proc", s_proc, 0}, /* nop??? */ ! 100: /* This are to handle SUN assembler files and point to existing handlers */ ! 101: {"empty", s_ignore, 0}, ! 102: {"ident", s_ignore, 0}, ! 103: {"optim", s_ignore, 0}, ! 104: {"skip", s_space, 0}, ! 105: {"type", s_ignore, 0}, ! 106: {"word", cons, 4}, ! 107: {"half", cons, 2}, ! 108: /* these are custom handlers for SUN SPARC assembler only */ ! 109: ! 110: #else NeXT ! 111: {"seg", s_seg, 0}, ! 112: {"align", s_align_bytes, 0}, /* Defaulting is invalid (0) */ ! 113: {"common", s_common, 0}, ! 114: {"global", s_globl, 0}, ! 115: {"half", cons, 2}, ! 116: {"optim", s_ignore, 0}, ! 117: {"proc", s_proc, 0}, ! 118: {"reserve", s_reserve, 0}, ! 119: {"seg", s_seg, 0}, ! 120: {"skip", s_space, 0}, ! 121: {"word", cons, 4}, ! 122: #endif NeXT ! 123: {NULL, 0, 0}, ! 124: }; ! 125: ! 126: const int md_short_jump_size = 4; ! 127: const int md_long_jump_size = 4; ! 128: const int md_reloc_size = 12; /* Size of relocation record */ ! 129: ! 130: /* This array holds the chars that always start a comment. If the ! 131: pre-processor is disabled, these aren't very useful */ ! 132: const char comment_chars[] = "!"; /* JF removed '|' from comment_chars */ ! 133: ! 134: /* This array holds the chars that only start a comment at the beginning of ! 135: a line. If the line seems to have the form '# 123 filename' ! 136: .line and .file directives will appear in the pre-processed output */ ! 137: /* Note that input_file.c hand checks for '#' at the beginning of the ! 138: first line of the input file. This is because the compiler outputs ! 139: #NO_APP at the beginning of its output. */ ! 140: /* Also note that comments started like this one will always ! 141: work if '/' isn't otherwise defined. */ ! 142: const char line_comment_chars[] = "#"; ! 143: ! 144: const char line_separator_chars[] = ""; ! 145: ! 146: /* Chars that can be used to separate mant from exp in floating point nums */ ! 147: const char EXP_CHARS[] = "eE"; ! 148: ! 149: /* Chars that mean this number is a floating point constant */ ! 150: /* As in 0f12.456 */ ! 151: /* or 0d1.2345e12 */ ! 152: const char FLT_CHARS[] = "rRsSfFdDxXpP"; ! 153: ! 154: /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be ! 155: changed in read.c. Ideally it shouldn't have to know about it at all, ! 156: but nothing is ideal around here. */ ! 157: ! 158: static unsigned char octal[256]; ! 159: #define isoctal(c) octal[(unsigned char) (c)] ! 160: static unsigned char toHex[256]; ! 161: ! 162: struct sparc_it ! 163: { ! 164: char *error; ! 165: unsigned long opcode; ! 166: struct nlist *nlistp; ! 167: expressionS exp; ! 168: int pcrel; ! 169: char pcrel_reloc; /* do relocation? */ ! 170: enum reloc_type_sparc reloc; ! 171: }; ! 172: ! 173: struct sparc_it the_insn; ! 174: ! 175: #ifdef DEBUGINSN ! 176: static void print_insn PARAMS ((struct sparc_it *insn)); ! 177: #endif ! 178: static int getExpression PARAMS ((char *str)); ! 179: ! 180: static char *expr_end; ! 181: ! 182: ! 183: /* ! 184: * Indicates a 'set' instruction which may require a either ! 185: * of the following instructions depending on the size of the ! 186: * value argument: ! 187: * ! 188: * sethi %hi(value),reg ! 189: * ! 190: * or %g0,value,reg ! 191: * ! 192: * sethi %hi(value),reg ! 193: * or reg,%lo(value),reg ! 194: * ! 195: */ ! 196: static int special_case_set = 0; ! 197: ! 198: /* s_proc and s_ignore are included for rudimentary ! 199: compatibility with the Sun assembler only */ ! 200: ! 201: static void ! 202: s_proc (ignore) ! 203: int ignore; ! 204: { ! 205: totally_ignore_line(); ! 206: } ! 207: ! 208: /* we simply ignore the rest of this statement */ ! 209: static void ! 210: s_ignore (ignore) ! 211: int ignore; ! 212: { ! 213: totally_ignore_line(); ! 214: } ! 215: ! 216: /* This function is called once, at assembler startup time. It should ! 217: set up all the tables, etc. that the MD part of the assembler will need. */ ! 218: void ! 219: md_begin () ! 220: { ! 221: register const char *retval = NULL; ! 222: int lose = 0; ! 223: register unsigned int i = 0; ! 224: ! 225: op_hash = hash_new (); ! 226: ! 227: while (i < NUMOPCODES) ! 228: { ! 229: const char *name = sparc_opcodes[i].name; ! 230: retval = hash_insert (op_hash, (char *)name, (char *)&sparc_opcodes[i]); ! 231: ! 232: if(retval != NULL && *retval != '\0') { ! 233: fprintf (stderr, "internal error: can't hash `%s': %s\n", ! 234: sparc_opcodes[i].name, retval); ! 235: lose = 1; ! 236: } do { ! 237: if (sparc_opcodes[i].match & sparc_opcodes[i].lose) ! 238: { ! 239: fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", ! 240: sparc_opcodes[i].name, sparc_opcodes[i].args); ! 241: lose = 1; ! 242: } ! 243: ++i; ! 244: } ! 245: while (i < NUMOPCODES ! 246: && !strcmp (sparc_opcodes[i].name, name)); ! 247: } ! 248: ! 249: if (lose) ! 250: as_fatal ("Broken assembler. No assembly attempted."); ! 251: ! 252: for (i = '0'; i < '8'; ++i) ! 253: octal[i] = 1; ! 254: for (i = '0'; i <= '9'; ++i) ! 255: toHex[i] = i - '0'; ! 256: for (i = 'a'; i <= 'f'; ++i) ! 257: toHex[i] = i + 10 - 'a'; ! 258: for (i = 'A'; i <= 'F'; ++i) ! 259: toHex[i] = i + 10 - 'A'; ! 260: } ! 261: ! 262: void ! 263: md_end( ! 264: void) ! 265: { ! 266: return; ! 267: } ! 268: ! 269: void ! 270: md_assemble (str) ! 271: char *str; ! 272: { ! 273: char *toP; ! 274: int rsd; ! 275: ! 276: know (str); ! 277: sparc_ip (str); ! 278: ! 279: #ifdef DEBUGINSN ! 280: print_insn(&the_insn); ! 281: #endif ! 282: ! 283: /* See if "set" operand is absolute and small; skip sethi if so. */ ! 284: if (special_case_set && the_insn.exp.X_seg == SEG_ABSOLUTE) ! 285: { ! 286: if (the_insn.exp.X_add_number >= -(1 << 12) ! 287: && the_insn.exp.X_add_number < (1 << 12)) ! 288: { ! 289: the_insn.opcode = 0x80102000 /* or %g0,imm,... */ ! 290: | (the_insn.opcode & 0x3E000000) /* dest reg */ ! 291: | (the_insn.exp.X_add_number & 0x1FFF); /* imm */ ! 292: special_case_set = 0; /* No longer special */ ! 293: the_insn.reloc = SPARC_RELOC_NONE; /* No longer relocated */ ! 294: } ! 295: } ! 296: ! 297: toP = frag_more (4); ! 298: /* put out the opcode */ ! 299: md_number_to_chars (toP, (valueT) the_insn.opcode, 4); ! 300: ! 301: /* put out the symbol-dependent stuff */ ! 302: if (the_insn.reloc != SPARC_RELOC_NONE) ! 303: { ! 304: fix_new(frag_now, ! 305: (toP - frag_now->fr_literal), ! 306: 4, ! 307: the_insn.exp.X_add_symbol, ! 308: the_insn.exp.X_subtract_symbol, ! 309: the_insn.exp.X_add_number, ! 310: the_insn.pcrel, ! 311: the_insn.pcrel_reloc, /* 1 for local labels due to scatter loading */ ! 312: the_insn.reloc); ! 313: } ! 314: ! 315: if (special_case_set) { ! 316: special_case_set = 0; ! 317: assert (the_insn.reloc == SPARC_RELOC_HI22); ! 318: /* See if "set" operand has no low-order bits; skip OR if so. */ ! 319: if ((the_insn.exp.X_seg == SEG_ABSOLUTE) && ! 320: ((the_insn.exp.X_add_number & 0x3FF) == 0)) ! 321: return; ! 322: ! 323: toP = frag_more (4); ! 324: rsd = (the_insn.opcode >> 25) & 0x1f; ! 325: the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14); ! 326: md_number_to_chars (toP, (valueT) the_insn.opcode, 4); ! 327: the_insn.pcrel_reloc = 0; ! 328: ! 329: fix_new(frag_now, ! 330: (toP - frag_now->fr_literal), ! 331: 4, ! 332: the_insn.exp.X_add_symbol, ! 333: the_insn.exp.X_subtract_symbol, ! 334: the_insn.exp.X_add_number, ! 335: the_insn.pcrel, ! 336: the_insn.pcrel_reloc, ! 337: SPARC_RELOC_LO10); ! 338: return; ! 339: } ! 340: } ! 341: ! 342: static void ! 343: sparc_ip (str) ! 344: char *str; ! 345: { ! 346: char *error_message = ""; ! 347: char *s; ! 348: const char *args; ! 349: char c; ! 350: struct sparc_opcode *insn; ! 351: char *argsStart; ! 352: unsigned long opcode; ! 353: unsigned int mask = 0; ! 354: int match = 0; ! 355: int comma = 0; ! 356: long immediate_max = 0; ! 357: ! 358: for (s = str; islower (*s) || (*s >= '0' && *s <= '3'); ++s) ! 359: ; ! 360: switch (*s) ! 361: { ! 362: ! 363: case '\0': ! 364: break; ! 365: ! 366: case ',': ! 367: comma = 1; ! 368: ! 369: /*FALLTHROUGH */ ! 370: ! 371: case ' ': ! 372: *s++ = '\0'; ! 373: break; ! 374: ! 375: default: ! 376: as_bad ("Unknown opcode: `%s'", str); ! 377: exit (1); ! 378: } ! 379: if ((insn = (struct sparc_opcode *) hash_find (op_hash, str)) == NULL) ! 380: { ! 381: as_bad ("Unknown opcode: `%s'", str); ! 382: return; ! 383: } ! 384: if (comma) ! 385: { ! 386: *--s = ','; ! 387: } ! 388: argsStart = s; ! 389: for (;;) ! 390: { ! 391: opcode = insn->match; ! 392: memset (&the_insn, '\0', sizeof (the_insn)); ! 393: the_insn.reloc = SPARC_RELOC_NONE; ! 394: the_insn.pcrel_reloc = 1; /* default, reloc, for scatter loading */ ! 395: ! 396: /* ! 397: * Build the opcode, checking as we go to make ! 398: * sure that the operands match ! 399: */ ! 400: for (args = insn->args;; ++args) ! 401: { ! 402: switch (*args) ! 403: { ! 404: case 'M': ! 405: case 'm': ! 406: if (strncmp (s, "%asr", 4) == 0) ! 407: { ! 408: s += 4; ! 409: ! 410: if (isdigit (*s)) ! 411: { ! 412: long num = 0; ! 413: ! 414: while (isdigit (*s)) ! 415: { ! 416: num = num * 10 + *s - '0'; ! 417: ++s; ! 418: } ! 419: ! 420: if (num < 16 || 31 < num) ! 421: { ! 422: error_message = ": asr number must be between 15 and 31"; ! 423: goto error; ! 424: } /* out of range */ ! 425: ! 426: opcode |= (*args == 'M' ? RS1 (num) : RD (num)); ! 427: continue; ! 428: } ! 429: else ! 430: { ! 431: error_message = ": expecting %asrN"; ! 432: goto error; ! 433: } /* if %asr followed by a number. */ ! 434: ! 435: } /* if %asr */ ! 436: break; ! 437: ! 438: ! 439: case '\0': /* end of args */ ! 440: if (*s == '\0') ! 441: { ! 442: match = 1; ! 443: } ! 444: break; ! 445: ! 446: case '+': ! 447: if (*s == '+') ! 448: { ! 449: ++s; ! 450: continue; ! 451: } ! 452: if (*s == '-') ! 453: { ! 454: continue; ! 455: } ! 456: break; ! 457: ! 458: case '[': /* these must match exactly */ ! 459: case ']': ! 460: case ',': ! 461: case ' ': ! 462: if (*s++ == *args) ! 463: continue; ! 464: break; ! 465: ! 466: case '#': /* must be at least one digit */ ! 467: if (isdigit (*s++)) ! 468: { ! 469: while (isdigit (*s)) ! 470: { ! 471: ++s; ! 472: } ! 473: continue; ! 474: } ! 475: break; ! 476: ! 477: case 'C': /* coprocessor state register */ ! 478: if (strncmp (s, "%csr", 4) == 0) ! 479: { ! 480: s += 4; ! 481: continue; ! 482: } ! 483: break; ! 484: ! 485: case 'b': /* next operand is a coprocessor register */ ! 486: case 'c': ! 487: case 'D': ! 488: if (*s++ == '%' && *s++ == 'c' && isdigit (*s)) ! 489: { ! 490: mask = *s++; ! 491: if (isdigit (*s)) ! 492: { ! 493: mask = 10 * (mask - '0') + (*s++ - '0'); ! 494: if (mask >= 32) ! 495: { ! 496: break; ! 497: } ! 498: } ! 499: else ! 500: { ! 501: mask -= '0'; ! 502: } ! 503: switch (*args) ! 504: { ! 505: ! 506: case 'b': ! 507: opcode |= mask << 14; ! 508: continue; ! 509: ! 510: case 'c': ! 511: opcode |= mask; ! 512: continue; ! 513: ! 514: case 'D': ! 515: opcode |= mask << 25; ! 516: continue; ! 517: } ! 518: } ! 519: break; ! 520: ! 521: case 'r': /* next operand must be a register */ ! 522: case 'u': ! 523: case '1': ! 524: case '2': ! 525: case 'd': ! 526: if (*s++ == '%') ! 527: { ! 528: switch (c = *s++) ! 529: { ! 530: ! 531: case 'f': /* frame pointer */ ! 532: if (*s++ == 'p') ! 533: { ! 534: mask = 0x1e; ! 535: break; ! 536: } ! 537: error_message = ": register not fp"; ! 538: goto error; ! 539: ! 540: case 'g': /* global register */ ! 541: if (isoctal (c = *s++)) ! 542: { ! 543: mask = c - '0'; ! 544: break; ! 545: } ! 546: error_message = ": invalid global register"; ! 547: goto error; ! 548: ! 549: case 'i': /* in register */ ! 550: if (isoctal (c = *s++)) ! 551: { ! 552: mask = c - '0' + 24; ! 553: break; ! 554: } ! 555: error_message = ": invalid in register"; ! 556: goto error; ! 557: ! 558: case 'l': /* local register */ ! 559: if (isoctal (c = *s++)) ! 560: { ! 561: mask = (c - '0' + 16); ! 562: break; ! 563: } ! 564: error_message = ": invalid local register"; ! 565: goto error; ! 566: ! 567: case 'o': /* out register */ ! 568: if (isoctal (c = *s++)) ! 569: { ! 570: mask = (c - '0' + 8); ! 571: break; ! 572: } ! 573: error_message = ": invalid out register"; ! 574: goto error; ! 575: ! 576: case 's': /* stack pointer */ ! 577: if (*s++ == 'p') ! 578: { ! 579: mask = 0xe; ! 580: break; ! 581: } ! 582: error_message = ": register is not sp"; ! 583: goto error; ! 584: ! 585: case 'r': /* any register */ ! 586: if (!isdigit (c = *s++)) ! 587: { ! 588: error_message = ": invalid register"; ! 589: goto error; ! 590: } ! 591: /* FALLTHROUGH */ ! 592: case '0': ! 593: case '1': ! 594: case '2': ! 595: case '3': ! 596: case '4': ! 597: case '5': ! 598: case '6': ! 599: case '7': ! 600: case '8': ! 601: case '9': ! 602: if (isdigit (*s)) ! 603: { ! 604: if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) ! 605: { ! 606: error_message = ": register # out of range"; ! 607: goto error; ! 608: } ! 609: } ! 610: else ! 611: { ! 612: c -= '0'; ! 613: } ! 614: mask = c; ! 615: break; ! 616: ! 617: default: ! 618: error_message = ": invalid resgiter #"; ! 619: goto error; ! 620: } ! 621: /* ! 622: * Got the register, now figure out where ! 623: * it goes in the opcode. ! 624: */ ! 625: switch (*args) ! 626: { ! 627: ! 628: case '1': ! 629: opcode |= mask << 14; ! 630: continue; ! 631: ! 632: case '2': ! 633: opcode |= mask; ! 634: continue; ! 635: ! 636: case 'd': ! 637: opcode |= mask << 25; ! 638: continue; ! 639: ! 640: case 'r': ! 641: opcode |= (mask << 25) | (mask << 14); ! 642: continue; ! 643: ! 644: case 'u': ! 645: opcode |= (mask << 25) | mask; ! 646: continue; ! 647: } ! 648: } ! 649: break; ! 650: ! 651: case 'e': /* next operand is a floating point register */ ! 652: case 'v': ! 653: case 'V': ! 654: ! 655: case 'f': ! 656: case 'B': ! 657: case 'R': ! 658: ! 659: case 'g': ! 660: case 'H': ! 661: case 'J': ! 662: { ! 663: char format; ! 664: ! 665: if (*s++ == '%' ! 666: && ((format = *s) == 'f') ! 667: && isdigit (*++s)) ! 668: { ! 669: for (mask = 0; isdigit (*s); ++s) ! 670: { ! 671: mask = 10 * mask + (*s - '0'); ! 672: } /* read the number */ ! 673: ! 674: if ((*args == 'v' ! 675: || *args == 'B' ! 676: || *args == 'H') ! 677: && (mask & 1)) ! 678: { ! 679: break; ! 680: } /* register must be even numbered */ ! 681: ! 682: if ((*args == 'V' ! 683: || *args == 'R' ! 684: || *args == 'J') ! 685: && (mask & 3)) ! 686: { ! 687: break; ! 688: } /* register must be multiple of 4 */ ! 689: ! 690: if (mask >= 32) ! 691: { ! 692: error_message = ": There are only 32 f registers; [0-31]"; ! 693: goto error; ! 694: } /* on error */ ! 695: } ! 696: else ! 697: { ! 698: break; ! 699: } /* if not an 'f' register. */ ! 700: ! 701: switch (*args) ! 702: { ! 703: ! 704: case 'v': ! 705: case 'V': ! 706: case 'e': ! 707: opcode |= RS1 (mask); ! 708: continue; ! 709: ! 710: ! 711: case 'f': ! 712: case 'B': ! 713: case 'R': ! 714: opcode |= RS2 (mask); ! 715: continue; ! 716: ! 717: case 'g': ! 718: case 'H': ! 719: case 'J': ! 720: opcode |= RD (mask); ! 721: continue; ! 722: } /* pack it in. */ ! 723: ! 724: know (0); ! 725: break; ! 726: } /* float arg */ ! 727: ! 728: case 'F': ! 729: if (strncmp (s, "%fsr", 4) == 0) ! 730: { ! 731: s += 4; ! 732: continue; ! 733: } ! 734: break; ! 735: ! 736: case 'h': /* high 22 bits */ ! 737: the_insn.reloc = SPARC_RELOC_HI22; ! 738: goto immediate; ! 739: ! 740: case 'l': /* 22 bit PC relative immediate */ ! 741: the_insn.reloc = SPARC_RELOC_WDISP22; ! 742: the_insn.pcrel = 1; ! 743: goto immediate; ! 744: ! 745: case 'L': /* 30 bit immediate for call insn */ ! 746: the_insn.reloc = SPARC_RELOC_WDISP30; ! 747: the_insn.pcrel = 1; ! 748: goto immediate; ! 749: ! 750: case 'n': /* 22 bit immediate */ ! 751: the_insn.reloc = SPARC_RELOC_22; ! 752: goto immediate; ! 753: ! 754: case 'i': /* 13 bit immediate */ ! 755: /* What's the difference between base13 and 13? ! 756: 13-bit immediate and 13-bit immediate+register */ ! 757: the_insn.reloc = SPARC_RELOC_13; ! 758: immediate_max = 0x1FFF; ! 759: ! 760: /*FALLTHROUGH */ ! 761: ! 762: immediate: ! 763: if (*s == ' ') ! 764: s++; ! 765: if (*s == '%') ! 766: { ! 767: if ((c = s[1]) == 'h' && s[2] == 'i') ! 768: { ! 769: the_insn.reloc = SPARC_RELOC_HI22; ! 770: s += 3; ! 771: } ! 772: else if (c == 'l' && s[2] == 'o') ! 773: { ! 774: the_insn.reloc = SPARC_RELOC_LO10; ! 775: s += 3; ! 776: } ! 777: else ! 778: break; ! 779: } ! 780: /* Note that if the getExpression() fails, we will still ! 781: have created U entries in the symbol table for the ! 782: 'symbols' in the input string. Try not to create U ! 783: symbols for registers, etc. */ ! 784: { ! 785: /* This stuff checks to see if the expression ends in ! 786: +%reg. If it does, it removes the register from ! 787: the expression, and re-sets 's' to point to the ! 788: right place. */ ! 789: ! 790: char *s1; ! 791: ! 792: for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++); ! 793: ! 794: if (s1 != s && isdigit (s1[-1])) ! 795: { ! 796: if (s1[-2] == '%' && s1[-3] == '+') ! 797: { ! 798: s1 -= 3; ! 799: *s1 = '\0'; ! 800: (void) getExpression (s); ! 801: *s1 = '+'; ! 802: s = s1; ! 803: continue; ! 804: } ! 805: else if (strchr ("goli0123456789", ! 806: s1[-2]) && s1[-3] == '%' && s1[-4] == '+') ! 807: { ! 808: s1 -= 4; ! 809: *s1 = '\0'; ! 810: (void) getExpression (s); ! 811: *s1 = '+'; ! 812: s = s1; ! 813: continue; ! 814: } ! 815: } ! 816: } ! 817: (void) getExpression (s); ! 818: s = expr_end; ! 819: /* The Next linker has the ability to scatter blocks of sections between ! 820: * labels. This requires that branches to labels that survive to the ! 821: * link phase be relocatable. These labels are those that are not L* ! 822: */ ! 823: if (the_insn.exp.X_add_symbol != NULL && !flagseen['L'] ! 824: && the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name[0] == 'L') { ! 825: /* local symbol which will be thrown away. Don't bother ! 826: * to reloc it. ! 827: */ ! 828: the_insn.pcrel_reloc = 0; ! 829: } ! 830: ! 831: if ((the_insn.exp.X_seg == SEG_ABSOLUTE || ! 832: the_insn.exp.X_seg == SEG_BIG) ! 833: && the_insn.exp.X_add_symbol == 0) ! 834: { ! 835: ! 836: /* Check for invalid constant values. Don't warn if ! 837: constant was inside %hi or %lo, since these ! 838: truncate the constant to fit. */ ! 839: if (immediate_max != 0 ! 840: && the_insn.reloc != SPARC_RELOC_LO10 ! 841: && the_insn.reloc != SPARC_RELOC_HI22 ! 842: && (the_insn.exp.X_add_number > immediate_max ! 843: || the_insn.exp.X_add_number < ~immediate_max)) ! 844: as_bad ("constant value must be between %ld and %ld", ! 845: ~immediate_max, immediate_max); ! 846: ! 847: if ((the_insn.reloc == SPARC_RELOC_WDISP22 || ! 848: the_insn.reloc == SPARC_RELOC_WDISP30) && ! 849: the_insn.exp.X_add_number & 3) ! 850: as_bad ("displacement is not long aligned"); ! 851: ! 852: /* plug absolutes directly into opcode */ ! 853: ! 854: switch(the_insn.reloc) { ! 855: case SPARC_RELOC_13: ! 856: if (the_insn.exp.X_seg == SEG_BIG) ! 857: opcode |= (*(int *) generic_bignum) & 0x1fff; ! 858: else ! 859: opcode |= the_insn.exp.X_add_number & 0x1fff; ! 860: the_insn.reloc = SPARC_RELOC_NONE; ! 861: break; ! 862: case SPARC_RELOC_22: ! 863: if (the_insn.exp.X_seg == SEG_BIG) ! 864: opcode |= (*(int *) generic_bignum) & 0x3fffff; ! 865: else ! 866: opcode |= the_insn.exp.X_add_number & 0x3fffff; ! 867: the_insn.reloc = SPARC_RELOC_NONE; ! 868: break; ! 869: case SPARC_RELOC_HI22: ! 870: /* extract upper 22 bits from constant */ ! 871: opcode |= (the_insn.exp.X_add_number >> 10) & 0x3fffff; ! 872: the_insn.reloc = SPARC_RELOC_NONE; ! 873: break; ! 874: case SPARC_RELOC_LO10: ! 875: opcode |= the_insn.exp.X_add_number & 0x3ff; ! 876: break; ! 877: ! 878: /* the PC relative displacements are plugged in ! 879: if the argument is absolute, but retain ! 880: relocatability */ ! 881: case SPARC_RELOC_WDISP22: ! 882: opcode |= (the_insn.exp.X_add_number >> 2) & 0x3fffff; ! 883: break; ! 884: case SPARC_RELOC_WDISP30: ! 885: opcode |= (the_insn.exp.X_add_number >> 2) & 0x3fffffff; ! 886: break; ! 887: default: ! 888: printf("Unknown reloc entry\n"); ! 889: } ! 890: } ! 891: ! 892: /* Reset to prevent extraneous range check. */ ! 893: immediate_max = 0; ! 894: ! 895: continue; ! 896: ! 897: case 'a': ! 898: if (*s++ == 'a') ! 899: { ! 900: opcode |= ANNUL; ! 901: continue; ! 902: } ! 903: break; ! 904: ! 905: case 'A': ! 906: { ! 907: char *push = input_line_pointer; ! 908: expressionS e; ! 909: ! 910: input_line_pointer = s; ! 911: ! 912: expression (&e); ! 913: ! 914: if (e.X_seg == SEG_ABSOLUTE) ! 915: { ! 916: opcode |= e.X_add_number << 5; ! 917: s = input_line_pointer; ! 918: input_line_pointer = push; ! 919: continue; ! 920: } /* if absolute */ ! 921: ! 922: break; ! 923: } /* alternate space */ ! 924: ! 925: case 'p': ! 926: if (strncmp (s, "%psr", 4) == 0) ! 927: { ! 928: s += 4; ! 929: continue; ! 930: } ! 931: break; ! 932: ! 933: case 'q': /* floating point queue */ ! 934: if (strncmp (s, "%fq", 3) == 0) ! 935: { ! 936: s += 3; ! 937: continue; ! 938: } ! 939: break; ! 940: ! 941: case 'Q': /* coprocessor queue */ ! 942: if (strncmp (s, "%cq", 3) == 0) ! 943: { ! 944: s += 3; ! 945: continue; ! 946: } ! 947: break; ! 948: ! 949: case 'S': ! 950: if (strcmp (str, "set") == 0) ! 951: { ! 952: special_case_set = 1; ! 953: continue; ! 954: } ! 955: break; ! 956: ! 957: ! 958: case 't': ! 959: if (strncmp (s, "%tbr", 4) != 0) ! 960: break; ! 961: s += 4; ! 962: continue; ! 963: ! 964: case 'w': ! 965: if (strncmp (s, "%wim", 4) != 0) ! 966: break; ! 967: s += 4; ! 968: continue; ! 969: ! 970: case 'y': ! 971: if (strncmp (s, "%y", 2) != 0) ! 972: break; ! 973: s += 2; ! 974: continue; ! 975: ! 976: default: ! 977: as_fatal ("failed sanity check."); ! 978: } /* switch on arg code */ ! 979: break; ! 980: } /* for each arg that we expect */ ! 981: error: ! 982: if (match == 0) ! 983: { ! 984: /* Args don't match. */ ! 985: if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES ! 986: && !strcmp (insn->name, insn[1].name)) ! 987: { ! 988: ++insn; ! 989: s = argsStart; ! 990: continue; ! 991: } ! 992: else ! 993: { ! 994: as_bad ("Illegal operands%s", error_message); ! 995: return; ! 996: } ! 997: } ! 998: else ! 999: { ! 1000: if (insn->architecture > current_architecture) ! 1001: { ! 1002: if ((!architecture_requested || warn_on_bump) ! 1003: && ! 1004: 1 ! 1005: ) ! 1006: { ! 1007: if (warn_on_bump) ! 1008: { ! 1009: as_warn ("architecture bumped from \"%s\" to \"%s\" on \"%s\"", ! 1010: architecture_pname[current_architecture], ! 1011: architecture_pname[insn->architecture], ! 1012: str); ! 1013: } /* if warning */ ! 1014: ! 1015: current_architecture = insn->architecture; ! 1016: } ! 1017: else ! 1018: { ! 1019: as_bad ("architecture mismatch on \"%s\" (\"%s\"). current architecture is \"%s\"", ! 1020: str, ! 1021: architecture_pname[insn->architecture], ! 1022: architecture_pname[current_architecture]); ! 1023: return; ! 1024: } /* if bump ok else error */ ! 1025: } /* if architecture higher */ ! 1026: } /* if no match */ ! 1027: ! 1028: break; ! 1029: } /* forever looking for a match */ ! 1030: ! 1031: the_insn.opcode = opcode; ! 1032: } ! 1033: ! 1034: static int ! 1035: getExpression (str) ! 1036: char *str; ! 1037: { ! 1038: char *save_in; ! 1039: segT seg; ! 1040: ! 1041: save_in = input_line_pointer; ! 1042: input_line_pointer = str; ! 1043: seg = expression (&the_insn.exp); ! 1044: ! 1045: if (seg != SEG_ABSOLUTE ! 1046: && seg != SEG_SECT ! 1047: && seg != SEG_DIFFSECT ! 1048: && seg != SEG_UNKNOWN ! 1049: && seg != SEG_NONE ! 1050: && seg != SEG_BIG) { ! 1051: the_insn.error = "bad segment"; ! 1052: expr_end = input_line_pointer; ! 1053: input_line_pointer = save_in; ! 1054: return 1; ! 1055: } ! 1056: expr_end = input_line_pointer; ! 1057: input_line_pointer = save_in; ! 1058: return 0; ! 1059: } /* getExpression() */ ! 1060: ! 1061: ! 1062: /* ! 1063: This is identical to the md_atof in m68k.c. I think this is right, ! 1064: but I'm not sure. ! 1065: ! 1066: Turn a string in input_line_pointer into a floating point constant of type ! 1067: type, and store the appropriate bytes in *litP. The number of LITTLENUMS ! 1068: emitted is stored in *sizeP . An error message is returned, or NULL on OK. ! 1069: */ ! 1070: ! 1071: /* Equal to MAX_PRECISION in atof-ieee.c */ ! 1072: #define MAX_LITTLENUMS 6 ! 1073: ! 1074: char * ! 1075: md_atof (type, litP, sizeP) ! 1076: char type; ! 1077: char *litP; ! 1078: int *sizeP; ! 1079: { ! 1080: int prec; ! 1081: LITTLENUM_TYPE words[MAX_LITTLENUMS]; ! 1082: LITTLENUM_TYPE *wordP; ! 1083: char *t; ! 1084: char *atof_ieee (); ! 1085: ! 1086: switch (type) ! 1087: { ! 1088: case 'f': ! 1089: case 'F': ! 1090: case 's': ! 1091: case 'S': ! 1092: prec = 2; ! 1093: break; ! 1094: ! 1095: case 'd': ! 1096: case 'D': ! 1097: case 'r': ! 1098: case 'R': ! 1099: prec = 4; ! 1100: break; ! 1101: ! 1102: case 'x': ! 1103: case 'X': ! 1104: prec = 6; ! 1105: break; ! 1106: ! 1107: case 'p': ! 1108: case 'P': ! 1109: prec = 6; ! 1110: break; ! 1111: ! 1112: default: ! 1113: *sizeP = 0; ! 1114: return "Bad call to MD_ATOF()"; ! 1115: } ! 1116: t = atof_ieee (input_line_pointer, type, words); ! 1117: if (t) ! 1118: input_line_pointer = t; ! 1119: *sizeP = prec * sizeof (LITTLENUM_TYPE); ! 1120: for (wordP = words; prec--;) ! 1121: { ! 1122: md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); ! 1123: litP += sizeof (LITTLENUM_TYPE); ! 1124: } ! 1125: return ""; ! 1126: } ! 1127: ! 1128: /* ! 1129: * Write out big-endian. ! 1130: */ ! 1131: void ! 1132: md_number_to_chars (buf, val, n) ! 1133: char *buf; ! 1134: long val; ! 1135: int n; ! 1136: { ! 1137: // sigh, all architectures do this.., ! 1138: switch(n) { ! 1139: ! 1140: case 4: ! 1141: *buf++ = val >> 24; ! 1142: *buf++ = val >> 16; ! 1143: case 2: ! 1144: *buf++ = val >> 8; ! 1145: case 1: ! 1146: *buf = val; ! 1147: break; ! 1148: ! 1149: default: ! 1150: abort(); ! 1151: } ! 1152: } ! 1153: ! 1154: /* Apply a fixS to the frags, now that we know the value it ought to ! 1155: hold. */ ! 1156: ! 1157: ! 1158: void ! 1159: md_number_to_imm(unsigned char *buf, long val, int size, fixS *fixP, int nsect) ! 1160: { ! 1161: ! 1162: /* handle the most common case quickly */ ! 1163: if ((fixP->fx_r_type == NO_RELOC) || ! 1164: (fixP->fx_r_type == SPARC_RELOC_NONE) || ! 1165: (fixP->fx_r_type == SPARC_RELOC_VANILLA)) { ! 1166: switch(size){ ! 1167: case 4: ! 1168: *buf++ = val >> 24; ! 1169: *buf++ = val >> 16; ! 1170: case 2: ! 1171: *buf++ = val >> 8; ! 1172: case 1: ! 1173: *buf = val; ! 1174: break; ! 1175: default: ! 1176: abort(); ! 1177: } ! 1178: return; ! 1179: } ! 1180: ! 1181: switch (fixP->fx_r_type) { ! 1182: case SPARC_RELOC_WDISP30: ! 1183: val = (val >> 2) + 1; /* adjust for word displacement */ ! 1184: buf[0] |= (val >> 24) & 0x3f; ! 1185: buf[1] = (val >> 16); ! 1186: buf[2] = val >> 8; ! 1187: buf[3] = val; ! 1188: break; ! 1189: case SPARC_RELOC_WDISP22: ! 1190: val = (val >>= 2) + 1; ! 1191: buf[1] |= (val >> 16) & 0x3f; ! 1192: buf[2] = val >> 8; ! 1193: buf[3] = val; ! 1194: break; ! 1195: case SPARC_RELOC_HI22: ! 1196: buf[1] |= (val >> 26) & 0x3f; ! 1197: buf[2] = val >> 18; ! 1198: buf[3] = val >> 10; ! 1199: break; ! 1200: case SPARC_RELOC_LO10: ! 1201: buf[2] |= (val >> 8) & 0x03; ! 1202: buf[3] = val; ! 1203: break; ! 1204: ! 1205: /* special cases that need to be handled internally by the as */ ! 1206: case SPARC_RELOC_22: ! 1207: if (!fixP->fx_addsy) { ! 1208: if (val & ~0x003fffff) { ! 1209: as_bad ("relocation overflow"); ! 1210: } /* on overflow */ ! 1211: buf[1] |= (val >> 16) & 0x3f; ! 1212: buf[2] = val >> 8; ! 1213: buf[3] = val & 0xff; ! 1214: } else ! 1215: as_bad ("Undefined symbolic 22-bit immediate reference: %s", ! 1216: fixP->fx_addsy->sy_name); ! 1217: break; ! 1218: case SPARC_RELOC_13: ! 1219: if (!fixP->fx_addsy) { ! 1220: if (((val > 0) && (val & ~(offsetT)0x00001fff)) ! 1221: || ((val < 0) && (~(val - 1) & ~(offsetT)0x00001fff))) { ! 1222: as_bad ("relocation overflow"); ! 1223: } ! 1224: buf[2] |= (val >> 8) & 0x1f; ! 1225: buf[3] = val; ! 1226: } else ! 1227: as_bad ("Undefined symbolic 13-bit immediate reference: %s", ! 1228: fixP->fx_addsy->sy_name); ! 1229: break; ! 1230: case SPARC_RELOC_NONE: ! 1231: default: ! 1232: as_bad ("bad or unhandled relocation type: 0x%02x", fixP->fx_r_type); ! 1233: break; ! 1234: } ! 1235: } ! 1236: ! 1237: ! 1238: /* ! 1239: * md_parse_option ! 1240: * Invocation line includes a switch not recognized by the base assembler. ! 1241: * See if it's a processor-specific option. These are: ! 1242: * ! 1243: * -bump ! 1244: * Warn on architecture bumps. See also -A. ! 1245: * ! 1246: * -Av6, -Av7, -Av8, -Asparclite ! 1247: * Select the architecture. Instructions or features not ! 1248: * supported by the selected architecture cause fatal errors. ! 1249: * ! 1250: * The default is to start at v6, and bump the architecture up ! 1251: * whenever an instruction is seen at a higher level. ! 1252: * ! 1253: * If -bump is specified, a warning is printing when bumping to ! 1254: * higher levels. ! 1255: * ! 1256: * If an architecture is specified, all instructions must match ! 1257: * that architecture. Any higher level instructions are flagged ! 1258: * as errors. ! 1259: * ! 1260: * if both an architecture and -bump are specified, the ! 1261: * architecture starts at the specified level, but bumps are ! 1262: * warnings. ! 1263: * ! 1264: */ ! 1265: ! 1266: int ! 1267: md_parse_option (argP, cntP, vecP) ! 1268: char **argP; ! 1269: int *cntP; ! 1270: char ***vecP; ! 1271: { ! 1272: char *p; ! 1273: const char **arch; ! 1274: ! 1275: if (!strcmp (*argP, "bump")) ! 1276: { ! 1277: warn_on_bump = 1; ! 1278: } ! 1279: else if (**argP == 'A') ! 1280: { ! 1281: p = (*argP) + 1; ! 1282: ! 1283: for (arch = architecture_pname; *arch != NULL; ++arch) ! 1284: { ! 1285: if (strcmp (p, *arch) == 0) ! 1286: { ! 1287: break; ! 1288: } /* found a match */ ! 1289: } /* walk the pname table */ ! 1290: ! 1291: if (*arch == NULL) ! 1292: { ! 1293: as_bad ("unknown architecture: %s", p); ! 1294: } ! 1295: else ! 1296: { ! 1297: current_architecture = (enum sparc_architecture) (arch - architecture_pname); ! 1298: architecture_requested = 1; ! 1299: } ! 1300: } ! 1301: #ifndef NeXT ! 1302: #ifdef OBJ_ELF ! 1303: else if (**argP == 'V') ! 1304: { ! 1305: print_version_id (); ! 1306: } ! 1307: else if (**argP == 'Q') ! 1308: { ! 1309: /* Qy - do emit .comment ! 1310: Qn - do not emit .comment */ ! 1311: } ! 1312: else if (**argP == 's') ! 1313: { ! 1314: /* use .stab instead of .stab.excl */ ! 1315: } ! 1316: #endif ! 1317: else if (strcmp (*argP, "sparc") == 0) ! 1318: { ! 1319: /* Ignore -sparc, used by SunOS make default .s.o rule. */ ! 1320: } ! 1321: #endif /* NeXT */ ! 1322: else ! 1323: { ! 1324: /* Unknown option */ ! 1325: (*argP)++; ! 1326: return 0; ! 1327: } ! 1328: **argP = '\0'; /* Done parsing this switch */ ! 1329: return 1; ! 1330: } /* md_parse_option() */ ! 1331: ! 1332: ! 1333: int ! 1334: md_estimate_size_before_relax( ! 1335: fragS *fragP, ! 1336: int segment_type) ! 1337: { ! 1338: as_fatal("internal error: Relaxation should never occur"); ! 1339: return(0); ! 1340: } ! 1341: ! 1342: void ! 1343: md_convert_frag( ! 1344: fragS *fragP) ! 1345: { ! 1346: as_fatal("internal error: Relaxation should never occur"); ! 1347: } ! 1348: ! 1349: ! 1350: #ifdef DEBUGINSN ! 1351: ! 1352: char * ! 1353: S_GET_NAME(sym) ! 1354: symbolS *sym; ! 1355: { ! 1356: return (sym->sy_nlist.n_un.n_name); ! 1357: } ! 1358: ! 1359: /* for debugging only */ ! 1360: static void ! 1361: print_insn (insn) ! 1362: struct sparc_it *insn; ! 1363: { ! 1364: const char *const Reloc[] = { ! 1365: "VANILLA", ! 1366: "PAIR", ! 1367: "HI22", ! 1368: "LO10", ! 1369: "DISP22", ! 1370: "PCREL", ! 1371: "22", ! 1372: "13", ! 1373: "SECTDIFF", ! 1374: "HI22_SECTDIFF", ! 1375: "LO10_SECTDIFF", ! 1376: "NONE", ! 1377: "UNUSED" ! 1378: ! 1379: }; ! 1380: ! 1381: if (insn->error) ! 1382: fprintf (stderr, "ERROR: %s\n", insn->error); ! 1383: fprintf (stderr, "opcode=0x%08x\n", (unsigned int)insn->opcode); ! 1384: fprintf (stderr, "reloc = %s\n", Reloc[insn->reloc]); ! 1385: fprintf (stderr, "X_add_number = 0x%x\n", ! 1386: insn->exp.X_add_number); ! 1387: ! 1388: if (insn->exp.X_add_symbol != NULL) ! 1389: fprintf(stderr, "Add symbol: %s\n", S_GET_NAME(insn->exp.X_add_symbol)); ! 1390: if (insn->exp.X_subtract_symbol != NULL) ! 1391: fprintf(stderr, "Subtract symbol: %s\n", S_GET_NAME(insn->exp.X_subtract_symbol)); ! 1392: } ! 1393: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.