X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-sparc.c;h=70f5bfb4dd404470ad42cf26ca689808199a7664;hb=feb4bea70a297eb6316d1b0685bbbb8095b7fb29;hp=952658307ebce07df212e8532f23b72499897d46;hpb=6d4af3c269e64b0093b23bd63d302bd9f90de6a9;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index 952658307e..70f5bfb4dd 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -90,10 +90,15 @@ static int warn_on_bump; architecture, issue a warning. */ static enum sparc_opcode_arch_val warn_after_architecture; -/* Non-zero if as should generate error if an undeclared g[23] register - has been used in -64. */ +/* Non-zero if the assembler should generate error if an undeclared + g[23] register has been used in -64. */ static int no_undeclared_regs; +/* Non-zero if the assembler should generate a warning if an + unpredictable DCTI (delayed control transfer instruction) couple is + found. */ +static int dcti_couples_detect; + /* Non-zero if we should try to relax jumps and calls. */ static int sparc_relax; @@ -264,8 +269,8 @@ static struct sparc_arch { { "sparcvis3", "v9b", v9, 0, 1, HWS_VB|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC, 0 }, { "sparcvis3r", "v9b", v9, 0, 1, HWS_VB|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_FJFMAU, 0 }, - { "sparc4", "v9b", v9, 0, 1, HWS_VV, 0 }, - { "sparc5", "v9b", v9, 0, 1, HWS_VM, HWS2_VM }, + { "sparc4", "v9v", v9, 0, 1, HWS_VV, 0 }, + { "sparc5", "v9m", v9, 0, 1, HWS_VM, HWS2_VM }, { "leon", "leon", leon, 32, 1, HWS_V8, 0 }, { "sparclet", "sparclet", sparclet, 32, 1, HWS_V8, 0 }, @@ -275,20 +280,20 @@ static struct sparc_arch { { "v8plus", "v9", v9, 0, 1, HWCAP_V8PLUS|HWS_V9, 0 }, { "v8plusa", "v9a", v9, 0, 1, HWCAP_V8PLUS|HWS_VA, 0 }, { "v8plusb", "v9b", v9, 0, 1, HWCAP_V8PLUS|HWS_VB, 0 }, - { "v8plusc", "v9b", v9, 0, 1, HWCAP_V8PLUS|HWS_VC, 0 }, - { "v8plusd", "v9b", v9, 0, 1, HWCAP_V8PLUS|HWS_VD, 0 }, - { "v8pluse", "v9b", v9, 0, 1, HWCAP_V8PLUS|HWS_VE, 0 }, - { "v8plusv", "v9b", v9, 0, 1, HWCAP_V8PLUS|HWS_VV, 0 }, - { "v8plusm", "v9b", v9, 0, 1, HWCAP_V8PLUS|HWS_VM, 0 }, + { "v8plusc", "v9c", v9, 0, 1, HWCAP_V8PLUS|HWS_VC, 0 }, + { "v8plusd", "v9d", v9, 0, 1, HWCAP_V8PLUS|HWS_VD, 0 }, + { "v8pluse", "v9e", v9, 0, 1, HWCAP_V8PLUS|HWS_VE, 0 }, + { "v8plusv", "v9v", v9, 0, 1, HWCAP_V8PLUS|HWS_VV, 0 }, + { "v8plusm", "v9m", v9, 0, 1, HWCAP_V8PLUS|HWS_VM, 0 }, { "v9", "v9", v9, 0, 1, HWS_V9, 0 }, { "v9a", "v9a", v9, 0, 1, HWS_VA, 0 }, { "v9b", "v9b", v9, 0, 1, HWS_VB, 0 }, - { "v9c", "v9b", v9, 0, 1, HWS_VC, 0 }, - { "v9d", "v9b", v9, 0, 1, HWS_VD, 0 }, - { "v9e", "v9b", v9, 0, 1, HWS_VE, 0 }, - { "v9v", "v9b", v9, 0, 1, HWS_VV, 0 }, - { "v9m", "v9b", v9, 0, 1, HWS_VM, HWS2_VM }, + { "v9c", "v9c", v9, 0, 1, HWS_VC, 0 }, + { "v9d", "v9d", v9, 0, 1, HWS_VD, 0 }, + { "v9e", "v9e", v9, 0, 1, HWS_VE, 0 }, + { "v9v", "v9v", v9, 0, 1, HWS_VV, 0 }, + { "v9m", "v9m", v9, 0, 1, HWS_VM, HWS2_VM }, /* This exists to allow configure.tgt to pass one value to specify both the default machine and default word size. */ @@ -484,6 +489,8 @@ struct option md_longopts[] = { {"relax", no_argument, NULL, OPTION_RELAX}, #define OPTION_NO_RELAX (OPTION_MD_BASE + 15) {"no-relax", no_argument, NULL, OPTION_NO_RELAX}, +#define OPTION_DCTI_COUPLES_DETECT (OPTION_MD_BASE + 16) + {"dcti-couples-detect", no_argument, NULL, OPTION_DCTI_COUPLES_DETECT}, {NULL, no_argument, NULL, 0} }; @@ -667,6 +674,10 @@ md_parse_option (int c, const char *arg) sparc_relax = 0; break; + case OPTION_DCTI_COUPLES_DETECT: + dcti_couples_detect = 1; + break; + default: return 0; } @@ -744,6 +755,7 @@ md_show_usage (FILE *stream) appropriate .register directive (default)\n\ -no-undeclared-regs force error on application global register usage\n\ without appropriate .register directive\n\ +--dcti-couples-detect warn when an unpredictable DCTI couple is found\n\ -q ignored\n\ -Qy, -Qn ignored\n\ -s ignored\n")); @@ -758,7 +770,7 @@ md_show_usage (FILE *stream) } /* Native operand size opcode translation. */ -struct +static struct { const char *name; const char *name32; @@ -807,7 +819,7 @@ struct priv_reg_entry priv_reg_table[] = {"gl", 16}, {"pmcdper", 23}, {"ver", 31}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; struct priv_reg_entry hpriv_reg_table[] = @@ -817,14 +829,16 @@ struct priv_reg_entry hpriv_reg_table[] = {"hintp", 3}, {"htba", 5}, {"hver", 6}, + {"hmcdper", 23}, + {"hmcddfr", 24}, + {"hva_mask_nz", 27}, {"hstick_offset", 28}, {"hstick_enable", 29}, {"hstick_cmpr", 31}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; -/* v9a specific asrs. This table is ordered by initial - letter, in reverse. */ +/* v9a or later specific ancillary state registers. */ struct priv_reg_entry v9a_asr_table[] = { @@ -845,7 +859,7 @@ struct priv_reg_entry v9a_asr_table[] = {"dcr", 18}, {"cfr", 26}, {"clear_softint", 21}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; static int @@ -854,7 +868,130 @@ cmp_reg_entry (const void *parg, const void *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); + if (p->name == q->name) + return 0; + else if (p->name == NULL) + return 1; + else if (q->name == NULL) + return -1; + else + return strcmp (q->name, p->name); +} + +/* sparc %-pseudo-operations. */ + + +#define F_POP_V9 0x1 /* The pseudo-op is for v9 only. */ +#define F_POP_PCREL 0x2 /* The pseudo-op can be used in pc-relative + contexts. */ +#define F_POP_TLS_CALL 0x4 /* The pseudo-op marks a tls call. */ +#define F_POP_POSTFIX 0x8 /* The pseudo-op should appear after the + last operand of an + instruction. (Generally they can appear + anywhere an immediate operand is + expected. */ +struct pop_entry +{ + /* The name as it appears in assembler. */ + const char *name; + /* The reloc this pseudo-op translates to. */ + bfd_reloc_code_real_type reloc; + /* Flags. See F_POP_* above. */ + int flags; +}; + +struct pop_entry pop_table[] = +{ + { "hix", BFD_RELOC_SPARC_HIX22, F_POP_V9 }, + { "lox", BFD_RELOC_SPARC_LOX10, F_POP_V9 }, + { "hi", BFD_RELOC_HI22, F_POP_PCREL }, + { "lo", BFD_RELOC_LO10, F_POP_PCREL }, + { "pc22", BFD_RELOC_SPARC_PC22, F_POP_PCREL }, + { "pc10", BFD_RELOC_SPARC_PC10, F_POP_PCREL }, + { "hh", BFD_RELOC_SPARC_HH22, F_POP_V9|F_POP_PCREL }, + { "hm", BFD_RELOC_SPARC_HM10, F_POP_V9|F_POP_PCREL }, + { "lm", BFD_RELOC_SPARC_LM22, F_POP_V9|F_POP_PCREL }, + { "h34", BFD_RELOC_SPARC_H34, F_POP_V9 }, + { "l34", BFD_RELOC_SPARC_L44, F_POP_V9 }, + { "h44", BFD_RELOC_SPARC_H44, F_POP_V9 }, + { "m44", BFD_RELOC_SPARC_M44, F_POP_V9 }, + { "l44", BFD_RELOC_SPARC_L44, F_POP_V9 }, + { "uhi", BFD_RELOC_SPARC_HH22, F_POP_V9 }, + { "ulo", BFD_RELOC_SPARC_HM10, F_POP_V9 }, + { "tgd_hi22", BFD_RELOC_SPARC_TLS_GD_HI22, 0 }, + { "tgd_lo10", BFD_RELOC_SPARC_TLS_GD_LO10, 0 }, + { "tldm_hi22", BFD_RELOC_SPARC_TLS_LDM_HI22, 0 }, + { "tldm_lo10", BFD_RELOC_SPARC_TLS_LDM_LO10, 0 }, + { "tldo_hix22", BFD_RELOC_SPARC_TLS_LDO_HIX22, 0 }, + { "tldo_lox10", BFD_RELOC_SPARC_TLS_LDO_LOX10, 0 }, + { "tie_hi22", BFD_RELOC_SPARC_TLS_IE_HI22, 0 }, + { "tie_lo10", BFD_RELOC_SPARC_TLS_IE_LO10, 0 }, + { "tle_hix22", BFD_RELOC_SPARC_TLS_LE_HIX22, 0 }, + { "tle_lox10", BFD_RELOC_SPARC_TLS_LE_LOX10, 0 }, + { "gdop_hix22", BFD_RELOC_SPARC_GOTDATA_OP_HIX22, 0 }, + { "gdop_lox10", BFD_RELOC_SPARC_GOTDATA_OP_LOX10, 0 }, + { "tgd_add", BFD_RELOC_SPARC_TLS_GD_ADD, F_POP_POSTFIX }, + { "tgd_call", BFD_RELOC_SPARC_TLS_GD_CALL, F_POP_POSTFIX|F_POP_TLS_CALL }, + { "tldm_add", BFD_RELOC_SPARC_TLS_LDM_ADD, F_POP_POSTFIX }, + { "tldm_call", BFD_RELOC_SPARC_TLS_LDM_CALL, F_POP_POSTFIX|F_POP_TLS_CALL }, + { "tldo_add", BFD_RELOC_SPARC_TLS_LDO_ADD, F_POP_POSTFIX }, + { "tie_ldx", BFD_RELOC_SPARC_TLS_IE_LDX, F_POP_POSTFIX }, + { "tie_ld", BFD_RELOC_SPARC_TLS_IE_LD, F_POP_POSTFIX }, + { "tie_add", BFD_RELOC_SPARC_TLS_IE_ADD, F_POP_POSTFIX }, + { "gdop", BFD_RELOC_SPARC_GOTDATA_OP, F_POP_POSTFIX } +}; + +/* Table of %-names that can appear in a sparc assembly program. This + table is initialized in md_begin and contains entries for each + privileged/hyperprivileged/alternate register and %-pseudo-op. */ + +enum perc_entry_type +{ + perc_entry_none = 0, + perc_entry_reg, + perc_entry_post_pop, + perc_entry_imm_pop +}; + +struct perc_entry +{ + /* Entry type. */ + enum perc_entry_type type; + /* Name of the %-entity. */ + const char *name; + /* strlen (name). */ + int len; + /* Value. Either a pop or a reg depending on type.*/ + union + { + struct pop_entry *pop; + struct priv_reg_entry *reg; + }; +}; + +#define NUM_PERC_ENTRIES \ + (((sizeof (priv_reg_table) / sizeof (priv_reg_table[0])) - 1) \ + + ((sizeof (hpriv_reg_table) / sizeof (hpriv_reg_table[0])) - 1) \ + + ((sizeof (v9a_asr_table) / sizeof (v9a_asr_table[0])) - 1) \ + + ARRAY_SIZE (pop_table) \ + + 1) + +struct perc_entry perc_table[NUM_PERC_ENTRIES]; + +static int +cmp_perc_entry (const void *parg, const void *qarg) +{ + const struct perc_entry *p = (const struct perc_entry *) parg; + const struct perc_entry *q = (const struct perc_entry *) qarg; + + if (p->name == q->name) + return 0; + else if (p->name == NULL) + return 1; + else if (q->name == NULL) + return -1; + else + return strcmp (q->name, p->name); } /* This function is called once, at assembler startup time. It should @@ -932,7 +1069,11 @@ md_begin (void) qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]), sizeof (priv_reg_table[0]), cmp_reg_entry); - + qsort (hpriv_reg_table, sizeof (hpriv_reg_table) / sizeof (hpriv_reg_table[0]), + sizeof (hpriv_reg_table[0]), cmp_reg_entry); + qsort (v9a_asr_table, sizeof (v9a_asr_table) / sizeof (v9a_asr_table[0]), + sizeof (v9a_asr_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 @@ -964,6 +1105,46 @@ md_begin (void) current_max_architecture)) break; } + + /* Prepare the tables of %-pseudo-ops. */ + { + struct priv_reg_entry *reg_tables[] + = {priv_reg_table, hpriv_reg_table, v9a_asr_table, NULL}; + struct priv_reg_entry **reg_table; + int entry = 0; + + /* Add registers. */ + for (reg_table = reg_tables; reg_table[0]; reg_table++) + { + struct priv_reg_entry *reg; + for (reg = *reg_table; reg->name; reg++) + { + struct perc_entry *p = &perc_table[entry++]; + p->type = perc_entry_reg; + p->name = reg->name; + p->len = strlen (reg->name); + p->reg = reg; + } + } + + /* Add %-pseudo-ops. */ + for (i = 0; i < ARRAY_SIZE (pop_table); i++) + { + struct perc_entry *p = &perc_table[entry++]; + p->type = (pop_table[i].flags & F_POP_POSTFIX + ? perc_entry_post_pop : perc_entry_imm_pop); + p->name = pop_table[i].name; + p->len = strlen (pop_table[i].name); + p->pop = &pop_table[i]; + } + + /* Last entry is the centinel. */ + perc_table[entry].type = perc_entry_none; + + qsort (perc_table, sizeof (perc_table) / sizeof (perc_table[0]), + sizeof (perc_table[0]), cmp_perc_entry); + + } } /* Called after all assembly has been done. */ @@ -981,6 +1162,11 @@ sparc_md_end (void) { case SPARC_OPCODE_ARCH_V9A: mach = bfd_mach_sparc_v9a; break; case SPARC_OPCODE_ARCH_V9B: mach = bfd_mach_sparc_v9b; break; + case SPARC_OPCODE_ARCH_V9C: mach = bfd_mach_sparc_v9c; break; + case SPARC_OPCODE_ARCH_V9D: mach = bfd_mach_sparc_v9d; break; + case SPARC_OPCODE_ARCH_V9E: mach = bfd_mach_sparc_v9e; break; + case SPARC_OPCODE_ARCH_V9V: mach = bfd_mach_sparc_v9v; break; + case SPARC_OPCODE_ARCH_V9M: mach = bfd_mach_sparc_v9m; break; default: mach = bfd_mach_sparc_v9; break; } else @@ -990,6 +1176,11 @@ sparc_md_end (void) 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; + case SPARC_OPCODE_ARCH_V9C: mach = bfd_mach_sparc_v8plusc; break; + case SPARC_OPCODE_ARCH_V9D: mach = bfd_mach_sparc_v8plusd; break; + case SPARC_OPCODE_ARCH_V9E: mach = bfd_mach_sparc_v8pluse; break; + case SPARC_OPCODE_ARCH_V9V: mach = bfd_mach_sparc_v8plusv; break; + case SPARC_OPCODE_ARCH_V9M: mach = bfd_mach_sparc_v8plusm; 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). */ @@ -1391,16 +1582,38 @@ md_assemble (char *str) if (insn == NULL) return; - /* We warn about attempts to put a floating point branch in a delay slot, - unless the delay slot has been annulled. */ + /* Certain instructions may not appear on delay slots. Check for + these situations. */ if (last_insn != NULL - && (insn->flags & F_FBR) != 0 - && (last_insn->flags & F_DELAYED) != 0 - /* ??? This test isn't completely accurate. We assume anything with - F_{UNBR,CONDBR,FBR} set is annullable. */ - && ((last_insn->flags & (F_UNBR | F_CONDBR | F_FBR)) == 0 - || (last_opcode & ANNUL) == 0)) - as_warn (_("FP branch in delay slot")); + && (last_insn->flags & F_DELAYED) != 0) + { + /* Before SPARC V9 the effect of having a delayed branch + instruction in the delay slot of a conditional delayed branch + was undefined. + + In SPARC V9 DCTI couples are well defined. + + However, starting with the UltraSPARC Architecture 2005, DCTI + couples (of all kind) are deprecated and should not be used, + as they may be slow or behave differently to what the + programmer expects. */ + if (dcti_couples_detect + && (insn->flags & F_DELAYED) != 0 + && ((max_architecture < SPARC_OPCODE_ARCH_V9 + && (last_insn->flags & F_CONDBR) != 0) + || max_architecture >= SPARC_OPCODE_ARCH_V9C)) + as_warn (_("unpredictable DCTI couple")); + + + /* We warn about attempts to put a floating point branch in a + delay slot, unless the delay slot has been annulled. */ + if ((insn->flags & F_FBR) != 0 + /* ??? This test isn't completely accurate. We assume anything with + F_{UNBR,CONDBR,FBR} set is annullable. */ + && ((last_insn->flags & (F_UNBR | F_CONDBR | F_FBR)) == 0 + || (last_opcode & ANNUL) == 0)) + as_warn (_("FP branch in delay slot")); + } /* SPARC before v9 requires a nop instruction between a floating point instruction and a floating point branch. We insert one @@ -1709,28 +1922,30 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) /* Parse a sparc64 privileged register. */ if (*s == '%') { - struct priv_reg_entry *p = priv_reg_table; + struct priv_reg_entry *p; unsigned int len = 9999999; /* Init to make gcc happy. */ s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) + for (p = priv_reg_table; p->name; p++) + if (p->name[0] == s[0]) + { + len = strlen (p->name); + if (strncmp (p->name, s, len) == 0) + break; + } + + if (!p->name) { error_message = _(": unrecognizable privileged register"); goto error; } - if (*args == '?') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); + + if (((opcode >> (*args == '?' ? 14 : 25)) & 0x1f) != (unsigned) p->regnum) + { + error_message = _(": unrecognizable privileged register"); + goto error; + } + s += len; continue; } @@ -1745,29 +1960,31 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) /* Parse a sparc64 hyperprivileged register. */ if (*s == '%') { - struct priv_reg_entry *p = hpriv_reg_table; + struct priv_reg_entry *p; unsigned int len = 9999999; /* Init to make gcc happy. */ s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) + for (p = hpriv_reg_table; p->name; p++) + if (p->name[0] == s[0]) + { + len = strlen (p->name); + if (strncmp (p->name, s, len) == 0) + break; + } + + if (!p->name) { error_message = _(": unrecognizable hyperprivileged register"); goto error; } - if (*args == '$') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); - s += len; + + if (((opcode >> (*args == '$' ? 14 : 25)) & 0x1f) != (unsigned) p->regnum) + { + error_message = _(": unrecognizable hyperprivileged register"); + goto error; + } + + s += len; continue; } else @@ -1778,50 +1995,39 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case '_': case '/': - /* Parse a v9a/v9b ancillary state register. */ + /* Parse a v9a or later ancillary state register. */ if (*s == '%') { - struct priv_reg_entry *p = v9a_asr_table; + struct priv_reg_entry *p; unsigned int len = 9999999; /* Init to make gcc happy. */ s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) - { - error_message = _(": unrecognizable v9a or v9b ancillary state register"); - goto error; - } - if (*args == '/' && (p->regnum == 20 || p->regnum == 21)) - { - error_message = _(": rd on write only ancillary state register"); - goto error; - } - if (p->regnum >= 24 - && (insn->architecture - & SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A))) + for (p = v9a_asr_table; p->name; p++) + if (p->name[0] == s[0]) + { + len = strlen (p->name); + if (strncmp (p->name, s, len) == 0) + break; + } + + if (!p->name) { - /* %sys_tick and %sys_tick_cmpr are v9bnotv9a */ - error_message = _(": unrecognizable v9a ancillary state register"); + error_message = _(": unrecognizable ancillary state register"); goto error; } - if (*args == '/') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); + + if (((opcode >> (*args == '/' ? 14 : 25)) & 0x1f) != (unsigned) p->regnum) + { + error_message = _(": unrecognizable ancillary state register"); + goto error; + } + s += len; continue; } else { - error_message = _(": unrecognizable v9a or v9b ancillary state register"); + error_message = _(": unrecognizable ancillary state register"); goto error; } @@ -2062,67 +2268,45 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case '\0': /* End of args. */ if (s[0] == ',' && s[1] == '%') { - static const struct ops - { - /* The name as it appears in assembler. */ - const char *name; - /* strlen (name), precomputed for speed */ - int len; - /* The reloc this pseudo-op translates to. */ - int reloc; - /* 1 if tls call. */ - int tls_call; - } - ops[] = - { - { "tgd_add", 7, BFD_RELOC_SPARC_TLS_GD_ADD, 0 }, - { "tgd_call", 8, BFD_RELOC_SPARC_TLS_GD_CALL, 1 }, - { "tldm_add", 8, BFD_RELOC_SPARC_TLS_LDM_ADD, 0 }, - { "tldm_call", 9, BFD_RELOC_SPARC_TLS_LDM_CALL, 1 }, - { "tldo_add", 8, BFD_RELOC_SPARC_TLS_LDO_ADD, 0 }, - { "tie_ldx", 7, BFD_RELOC_SPARC_TLS_IE_LDX, 0 }, - { "tie_ld", 6, BFD_RELOC_SPARC_TLS_IE_LD, 0 }, - { "tie_add", 7, BFD_RELOC_SPARC_TLS_IE_ADD, 0 }, - { "gdop", 4, BFD_RELOC_SPARC_GOTDATA_OP, 0 }, - { NULL, 0, 0, 0 } - }; - const struct ops *o; char *s1; int npar = 0; + const struct perc_entry *p; - for (o = ops; o->name; o++) - if (strncmp (s + 2, o->name, o->len) == 0) - break; - if (o->name == NULL) - break; + for (p = perc_table; p->type != perc_entry_none; p++) + if ((p->type == perc_entry_post_pop || p->type == perc_entry_reg) + && strncmp (s + 2, p->name, p->len) == 0) + break; + if (p->type == perc_entry_none || p->type == perc_entry_reg) + break; - if (s[o->len + 2] != '(') + if (s[p->len + 2] != '(') { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); + as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name); return special_case; } - if (! o->tls_call && the_insn.reloc != BFD_RELOC_NONE) + if (! (p->pop->flags & F_POP_TLS_CALL) + && the_insn.reloc != BFD_RELOC_NONE) { as_bad (_("Illegal operands: %%%s cannot be used together with other relocs in the insn ()"), - o->name); + p->name); return special_case; } - if (o->tls_call + if ((p->pop->flags & F_POP_TLS_CALL) && (the_insn.reloc != BFD_RELOC_32_PCREL_S2 || the_insn.exp.X_add_number != 0 || the_insn.exp.X_add_symbol != symbol_find_or_make ("__tls_get_addr"))) { as_bad (_("Illegal operands: %%%s can be only used with call __tls_get_addr"), - o->name); + p->name); return special_case; } - the_insn.reloc = o->reloc; + the_insn.reloc = p->pop->reloc; memset (&the_insn.exp, 0, sizeof (the_insn.exp)); - s += o->len + 3; + s += p->len + 3; for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) if (*s1 == '(') @@ -2136,7 +2320,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) if (*s1 != ')') { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); + as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name); return special_case; } @@ -2525,72 +2709,25 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) /* Check for %hi, etc. */ if (*s == '%') { - static const struct ops { - /* The name as it appears in assembler. */ - const char *name; - /* strlen (name), precomputed for speed */ - int len; - /* The reloc this pseudo-op translates to. */ - int reloc; - /* Non-zero if for v9 only. */ - int v9_p; - /* Non-zero if can be used in pc-relative contexts. */ - int pcrel_p;/*FIXME:wip*/ - } ops[] = { - /* hix/lox must appear before hi/lo so %hix won't be - mistaken for %hi. */ - { "hix", 3, BFD_RELOC_SPARC_HIX22, 1, 0 }, - { "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 }, - { "hi", 2, BFD_RELOC_HI22, 0, 1 }, - { "lo", 2, BFD_RELOC_LO10, 0, 1 }, - { "pc22", 4, BFD_RELOC_SPARC_PC22, 0, 1 }, - { "pc10", 4, BFD_RELOC_SPARC_PC10, 0, 1 }, - { "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 }, - { "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 }, - { "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 }, - { "h34", 3, BFD_RELOC_SPARC_H34, 1, 0 }, - { "l34", 3, BFD_RELOC_SPARC_L44, 1, 0 }, - { "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 }, - { "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 }, - { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 }, - { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 }, - { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 }, - { "tgd_hi22", 8, BFD_RELOC_SPARC_TLS_GD_HI22, 0, 0 }, - { "tgd_lo10", 8, BFD_RELOC_SPARC_TLS_GD_LO10, 0, 0 }, - { "tldm_hi22", 9, BFD_RELOC_SPARC_TLS_LDM_HI22, 0, 0 }, - { "tldm_lo10", 9, BFD_RELOC_SPARC_TLS_LDM_LO10, 0, 0 }, - { "tldo_hix22", 10, BFD_RELOC_SPARC_TLS_LDO_HIX22, 0, - 0 }, - { "tldo_lox10", 10, BFD_RELOC_SPARC_TLS_LDO_LOX10, 0, - 0 }, - { "tie_hi22", 8, BFD_RELOC_SPARC_TLS_IE_HI22, 0, 0 }, - { "tie_lo10", 8, BFD_RELOC_SPARC_TLS_IE_LO10, 0, 0 }, - { "tle_hix22", 9, BFD_RELOC_SPARC_TLS_LE_HIX22, 0, 0 }, - { "tle_lox10", 9, BFD_RELOC_SPARC_TLS_LE_LOX10, 0, 0 }, - { "gdop_hix22", 10, BFD_RELOC_SPARC_GOTDATA_OP_HIX22, - 0, 0 }, - { "gdop_lox10", 10, BFD_RELOC_SPARC_GOTDATA_OP_LOX10, - 0, 0 }, - { NULL, 0, 0, 0, 0 } - }; - const struct ops *o; - - for (o = ops; o->name; o++) - if (strncmp (s + 1, o->name, o->len) == 0) - break; - if (o->name == NULL) - break; - - if (s[o->len + 1] != '(') + const struct perc_entry *p; + + for (p = perc_table; p->type != perc_entry_none; p++) + if ((p->type == perc_entry_imm_pop || p->type == perc_entry_reg) + && strncmp (s + 1, p->name, p->len) == 0) + break; + if (p->type == perc_entry_none || p->type == perc_entry_reg) + break; + + if (s[p->len + 1] != '(') { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); + as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name); return special_case; } - op_arg = o->name; - the_insn.reloc = o->reloc; - s += o->len + 2; - v9_arg_p = o->v9_p; + op_arg = p->name; + the_insn.reloc = p->pop->reloc; + s += p->len + 2; + v9_arg_p = p->pop->flags & F_POP_V9; } /* Note that if the get_expression() fails, we will still @@ -2626,6 +2763,11 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) *s1 = '\0'; (void) get_expression (s); *s1 = ')'; + if (expr_end != s1) + { + as_bad (_("Expression inside %%%s could not be parsed"), op_arg); + return special_case; + } s = s1 + 1; if (*s == ',' || *s == ']' || !*s) continue; @@ -3082,7 +3224,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) ++arch; } - as_bad (_("Architecture mismatch on \"%s\"."), str); + as_bad (_("Architecture mismatch on \"%s %s\"."), str, argsStart); as_tsktsk (_(" (Requires %s; requested architecture is %s.)"), required_archs, sparc_opcode_archs[max_architecture].name); @@ -3680,10 +3822,10 @@ tc_gen_reloc (asection *section, fixS *fixp) arelent *reloc; bfd_reloc_code_real_type code; - relocs[0] = reloc = (arelent *) xmalloc (sizeof (arelent)); + relocs[0] = reloc = XNEW (arelent); relocs[1] = NULL; - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; @@ -3888,10 +4030,10 @@ tc_gen_reloc (asection *section, fixS *fixp) on the same location. */ if (code == BFD_RELOC_SPARC_OLO10) { - relocs[1] = reloc = (arelent *) xmalloc (sizeof (arelent)); + relocs[1] = reloc = XNEW (arelent); relocs[2] = NULL; - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (section_symbol (absolute_section)); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; @@ -4782,6 +4924,15 @@ cons_fix_new_sparc (fragS *frag, && now_seg->flags & SEC_ALLOC) r = BFD_RELOC_SPARC_REV32; +#ifdef TE_SOLARIS + /* The Solaris linker does not allow R_SPARC_UA64 + relocations for 32-bit executables. */ + if (!target_little_endian_data + && sparc_arch_size != 64 + && r == BFD_RELOC_64) + r = BFD_RELOC_32; +#endif + if (sparc_cons_special_reloc) { if (*sparc_cons_special_reloc == 'd') @@ -4812,7 +4963,14 @@ cons_fix_new_sparc (fragS *frag, { case 2: r = BFD_RELOC_SPARC_UA16; break; case 4: r = BFD_RELOC_SPARC_UA32; break; +#ifdef TE_SOLARIS + /* The Solaris linker does not allow R_SPARC_UA64 + relocations for 32-bit executables. */ + case 8: r = sparc_arch_size == 64 ? + BFD_RELOC_SPARC_UA64 : BFD_RELOC_SPARC_UA32; break; +#else case 8: r = BFD_RELOC_SPARC_UA64; break; +#endif default: abort (); } }