📄 tc-sparc.c
字号:
case OPTION_32: case OPTION_64: { const char **list, **l; sparc_arch_size = c == OPTION_32 ? 32 : 64; list = bfd_target_list (); for (l = list; *l != NULL; l++) { if (sparc_arch_size == 32) { if (strcmp (*l, "elf32-sparc") == 0) break; } else { if (strcmp (*l, "elf64-sparc") == 0) break; } } if (*l == NULL) as_fatal (_("No compiled in support for %d bit object file format"), sparc_arch_size); free (list); } break; case OPTION_TSO: sparc_memory_model = MM_TSO; break; case OPTION_PSO: sparc_memory_model = MM_PSO; break; case OPTION_RMO: sparc_memory_model = MM_RMO; break; case 'V': print_version_id (); break; case 'Q': /* Qy - do emit .comment Qn - do not emit .comment. */ break; case 's': /* Use .stab instead of .stab.excl. */ break; case 'q': /* quick -- Native assembler does fewer checks. */ break; case 'K': if (strcmp (arg, "PIC") != 0) as_warn (_("Unrecognized option following -K")); else sparc_pic_code = 1; break; case OPTION_NO_UNDECLARED_REGS: no_undeclared_regs = 1; break; case OPTION_UNDECLARED_REGS: no_undeclared_regs = 0; break;#endif case OPTION_RELAX: sparc_relax = 1; break; case OPTION_NO_RELAX: sparc_relax = 0; break; default: return 0; } return 1;}voidmd_show_usage (stream) FILE *stream;{ const struct sparc_arch *arch; int column; /* We don't get a chance to initialize anything before we're called, so handle that now. */ if (! default_init_p) init_default_arch (); fprintf (stream, _("SPARC options:\n")); column = 0; for (arch = &sparc_arch_table[0]; arch->name; arch++) { if (!arch->user_option_p) continue; if (arch != &sparc_arch_table[0]) fprintf (stream, " | "); if (column + strlen(arch->name) > 70) { column = 0; fputc ('\n', stream); } column += 5 + 2 + strlen(arch->name); fprintf (stream, "-A%s", arch->name); } for (arch = &sparc_arch_table[0]; arch->name; arch++) { if (!arch->user_option_p) continue; fprintf (stream, " | "); if (column + strlen(arch->name) > 65) { column = 0; fputc ('\n', stream); } column += 5 + 7 + strlen(arch->name); fprintf (stream, "-xarch=%s", arch->name); } fprintf (stream, _("\n\ specify variant of SPARC architecture\n\-bump warn when assembler switches architectures\n\-sparc ignored\n\--enforce-aligned-data force .long, etc., to be aligned correctly\n\-relax relax jumps and branches (default)\n\-no-relax avoid changing any jumps and branches\n"));#ifdef OBJ_AOUT fprintf (stream, _("\-k generate PIC\n"));#endif#ifdef OBJ_ELF fprintf (stream, _("\-32 create 32 bit object file\n\-64 create 64 bit object file\n")); fprintf (stream, _("\ [default is %d]\n"), default_arch_size); fprintf (stream, _("\-TSO use Total Store Ordering\n\-PSO use Partial Store Ordering\n\-RMO use Relaxed Memory Ordering\n")); fprintf (stream, _("\ [default is %s]\n"), (default_arch_size == 64) ? "RMO" : "TSO"); fprintf (stream, _("\-KPIC generate PIC\n\-V print assembler version number\n\-undeclared-regs ignore application global register usage without\n\ appropriate .register directive (default)\n\-no-undeclared-regs force error on application global register usage\n\ without appropriate .register directive\n\-q ignored\n\-Qy, -Qn ignored\n\-s ignored\n"));#endif#ifdef SPARC_BIENDIAN fprintf (stream, _("\-EL generate code for a little endian machine\n\-EB generate code for a big endian machine\n\--little-endian-data generate code for a machine having big endian\n\ instructions and little endian data.\n"));#endif}/* Native operand size opcode translation. */struct { char *name; char *name32; char *name64; } native_op_table[] ={ {"ldn", "ld", "ldx"}, {"ldna", "lda", "ldxa"}, {"stn", "st", "stx"}, {"stna", "sta", "stxa"}, {"slln", "sll", "sllx"}, {"srln", "srl", "srlx"}, {"sran", "sra", "srax"}, {"casn", "cas", "casx"}, {"casna", "casa", "casxa"}, {"clrn", "clr", "clrx"}, {NULL, NULL, NULL},};/* sparc64 priviledged registers. */struct priv_reg_entry{ char *name; int regnum;};struct priv_reg_entry priv_reg_table[] ={ {"tpc", 0}, {"tnpc", 1}, {"tstate", 2}, {"tt", 3}, {"tick", 4}, {"tba", 5}, {"pstate", 6}, {"tl", 7}, {"pil", 8}, {"cwp", 9}, {"cansave", 10}, {"canrestore", 11}, {"cleanwin", 12}, {"otherwin", 13}, {"wstate", 14}, {"fq", 15}, {"ver", 31}, {"", -1}, /* End marker. */};/* v9a specific asrs. */struct priv_reg_entry v9a_asr_table[] ={ {"tick_cmpr", 23}, {"sys_tick_cmpr", 25}, {"sys_tick", 24}, {"softint", 22}, {"set_softint", 20}, {"pic", 17}, {"pcr", 16}, {"gsr", 19}, {"dcr", 18}, {"clear_softint", 21}, {"", -1}, /* End marker. */};static intcmp_reg_entry (parg, qarg) const PTR parg; const PTR qarg;{ const struct priv_reg_entry *p = (const struct priv_reg_entry *) parg; const struct priv_reg_entry *q = (const struct priv_reg_entry *) qarg; return strcmp (q->name, p->name);}/* This function is called once, at assembler startup time. It should set up all the tables, etc. that the MD part of the assembler will need. */voidmd_begin (){ register const char *retval = NULL; int lose = 0; register unsigned int i = 0; /* We don't get a chance to initialize anything before md_parse_option is called, and it may not be called, so handle default initialization now if not already done. */ if (! default_init_p) init_default_arch (); op_hash = hash_new (); while (i < (unsigned int) sparc_num_opcodes) { const char *name = sparc_opcodes[i].name; retval = hash_insert (op_hash, name, (PTR) &sparc_opcodes[i]); if (retval != NULL) { as_bad (_("Internal error: can't hash `%s': %s\n"), sparc_opcodes[i].name, retval); lose = 1; } do { if (sparc_opcodes[i].match & sparc_opcodes[i].lose) { as_bad (_("Internal error: losing opcode: `%s' \"%s\"\n"), sparc_opcodes[i].name, sparc_opcodes[i].args); lose = 1; } ++i; } while (i < (unsigned int) sparc_num_opcodes && !strcmp (sparc_opcodes[i].name, name)); } for (i = 0; native_op_table[i].name; i++) { const struct sparc_opcode *insn; char *name = ((sparc_arch_size == 32) ? native_op_table[i].name32 : native_op_table[i].name64); insn = (struct sparc_opcode *) hash_find (op_hash, name); if (insn == NULL) { as_bad (_("Internal error: can't find opcode `%s' for `%s'\n"), name, native_op_table[i].name); lose = 1; } else { retval = hash_insert (op_hash, native_op_table[i].name, (PTR) insn); if (retval != NULL) { as_bad (_("Internal error: can't hash `%s': %s\n"), sparc_opcodes[i].name, retval); lose = 1; } } } if (lose) as_fatal (_("Broken assembler. No assembly attempted.")); qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]), sizeof (priv_reg_table[0]), cmp_reg_entry); /* If -bump, record the architecture level at which we start issuing warnings. The behaviour is different depending upon whether an architecture was explicitly specified. If it wasn't, we issue warnings for all upwards bumps. If it was, we don't start issuing warnings until we need to bump beyond the requested architecture or when we bump between conflicting architectures. */ if (warn_on_bump && architecture_requested) { /* `max_architecture' records the requested architecture. Issue warnings if we go above it. */ warn_after_architecture = max_architecture; /* Find the highest architecture level that doesn't conflict with the requested one. */ for (max_architecture = SPARC_OPCODE_ARCH_MAX; max_architecture > warn_after_architecture; --max_architecture) if (! SPARC_OPCODE_CONFLICT_P (max_architecture, warn_after_architecture)) break; }}/* Called after all assembly has been done. */voidsparc_md_end (){ unsigned long mach = bfd_mach_sparc; if (sparc_arch_size == 64) switch (current_architecture) { case SPARC_OPCODE_ARCH_V9A: mach = bfd_mach_sparc_v9a; break; case SPARC_OPCODE_ARCH_V9B: mach = bfd_mach_sparc_v9b; break; default: mach = bfd_mach_sparc_v9; break; } else switch (current_architecture) { case SPARC_OPCODE_ARCH_SPARCLET: mach = bfd_mach_sparc_sparclet; break; case SPARC_OPCODE_ARCH_V9: mach = bfd_mach_sparc_v8plus; break; case SPARC_OPCODE_ARCH_V9A: mach = bfd_mach_sparc_v8plusa; break; case SPARC_OPCODE_ARCH_V9B: mach = bfd_mach_sparc_v8plusb; break; /* The sparclite is treated like a normal sparc. Perhaps it shouldn't be but for now it is (since that's the way it's always been treated). */ default: break; } bfd_set_arch_mach (stdoutput, bfd_arch_sparc, mach);}/* Return non-zero if VAL is in the range -(MAX+1) to MAX. */static INLINE intin_signed_range (val, max) bfd_signed_vma val, max;{ if (max <= 0) abort (); /* Sign-extend the value from the architecture word size, so that 0xffffffff is always considered -1 on sparc32. */ if (sparc_arch_size == 32) { bfd_signed_vma sign = (bfd_signed_vma) 1 << 31; val = ((val & 0xffffffff) ^ sign) - sign; } if (val > max) return 0; if (val < ~max) return 0; return 1;}/* Return non-zero if VAL is in the range 0 to MAX. */static INLINE intin_unsigned_range (val, max) bfd_vma val, max;{ if (val > max) return 0; return 1;}/* Return non-zero if VAL is in the range -(MAX/2+1) to MAX. (e.g. -15 to +31). */static INLINE intin_bitfield_range (val, max) bfd_signed_vma val, max;{ if (max <= 0) abort (); if (val > max) return 0; if (val < ~(max >> 1)) return 0; return 1;}static intsparc_ffs (mask) unsigned int mask;{ int i; if (mask == 0) return -1; for (i = 0; (mask & 1) == 0; ++i) mask >>= 1; return i;}/* Implement big shift right. */static bfd_vmaBSR (val, amount) bfd_vma val; int amount;{ if (sizeof (bfd_vma) <= 4 && amount >= 32) as_fatal (_("Support for 64-bit arithmetic not compiled in.")); return val >> amount;}/* For communication between sparc_ip and get_expression. */static char *expr_end;/* Values for `special_case'. Instructions that require wierd handling because they're longer than 4 bytes. */#define SPECIAL_CASE_NONE 0#define SPECIAL_CASE_SET 1#define SPECIAL_CASE_SETSW 2#define SPECIAL_CASE_SETX 3/* FIXME: sparc-opc.c doesn't have necessary "S" trigger to enable this. */#define SPECIAL_CASE_FDIV 4/* Bit masks of various insns. */#define NOP_INSN 0x01000000#define OR_INSN 0x80100000#define XOR_INSN 0x80180000#define FMOVS_INSN 0x81A00020#define SETHI_INSN 0x01000000#define SLLX_INSN 0x81281000#define SRA_INSN 0x81380000/* The last instruction to be assembled. */static const struct sparc_opcode *last_insn;/* The assembled opcode of `last_insn'. */static unsigned long last_opcode;/* Handle the set and setuw synthetic instructions. */static voidsynthetize_setuw (insn) const struct sparc_opcode *insn;{ int need_hi22_p = 0; int rd = (the_insn.opcode & RD (~0)) >> 25; if (the_insn.exp.X_op == O_constant) { if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) { if (sizeof (offsetT) > 4 && (the_insn.exp.X_add_number < 0 || the_insn.exp.X_add_number > (offsetT) 0xffffffff)) as_warn (_("set: number not in 0..4294967295 range")); } else { if (sizeof (offsetT) > 4 && (the_insn.exp.X_add_number < -(offsetT) 0x80000000 || the_insn.exp.X_add_number > (offsetT) 0xffffffff)) as_warn (_("set: number not in -2147483648..4294967295 range")); the_insn.exp.X_add_number = (int) the_insn.exp.X_add_number; } } /* See if operand is absolute and small; skip sethi if so. */ if (the_insn.exp.X_op != O_constant || the_insn.exp.X_add_number >= (1 << 12) || the_insn.exp.X_add_number < -(1 << 12)) { the_insn.opcode = (SETHI_INSN | RD (rd) | ((the_insn.exp.X_add_number >> 10) & (the_insn.exp.X_op == O_constant ? 0x3fffff : 0))); the_insn.reloc = (the_insn.exp.X_op != O_constant ? BFD_RELOC_HI22 : BFD_RELOC_NONE); output_insn (insn, &the_insn); need_hi22_p = 1; } /* See if operand has no low-order bits; skip OR if so. */ if (the_insn.exp.X_op != O_constant || (need_hi22_p && (the_insn.exp.X_add_number & 0x3FF) != 0) || ! need_hi22_p) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -