X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-sparc.c;h=70f5bfb4dd404470ad42cf26ca689808199a7664;hb=fc7514d6f2784390b7e6c65c0c9603ede0203f58;hp=be8d9878920addcb6f21a3ee38054b0cb3e55d05;hpb=f124dd4f3f9511447b5782d334b3c66172db7451;p=binutils-gdb.git diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index be8d9878920..70f5bfb4dd4 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -1,7 +1,5 @@ /* tc-sparc.c -- Assemble for the SPARC - Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 1989-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify @@ -49,7 +47,7 @@ static int get_expression (char *); #ifndef DEFAULT_ARCH #define DEFAULT_ARCH "sparclite" #endif -static char *default_arch = DEFAULT_ARCH; +static const char *default_arch = DEFAULT_ARCH; /* Non-zero if the initial values of `max_architecture' and `sparc_arch_size' have been set. */ @@ -75,8 +73,16 @@ static int default_arch_size; /* The currently selected v9 memory model. Currently only used for ELF. */ static enum { MM_TSO, MM_PSO, MM_RMO } sparc_memory_model = MM_RMO; + +#ifndef TE_SOLARIS +/* Bitmask of instruction types seen so far, used to populate the + GNU attributes section with hwcap information. */ +static bfd_uint64_t hwcap_seen; +#endif #endif +static bfd_uint64_t hwcap_allowed; + static int architecture_requested; static int warn_on_bump; @@ -84,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; @@ -194,7 +205,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; struct sparc_it { - char *error; + const char *error; unsigned long opcode; struct nlist *nlistp; expressionS exp; @@ -212,42 +223,89 @@ static void output_insn (const struct sparc_opcode *, struct sparc_it *); for this use. That table is for opcodes only. This table is for opcodes and file formats. */ -enum sparc_arch_types {v6, v7, v8, sparclet, sparclite, sparc86x, v8plus, +enum sparc_arch_types {v6, v7, v8, leon, sparclet, sparclite, sparc86x, v8plus, v8plusa, v9, v9a, v9b, v9_64}; +/* Hardware capability sets, used to keep sparc_arch_table easy to + read. */ +#define HWS_V8 HWCAP_MUL32 | HWCAP_DIV32 | HWCAP_FSMULD +#define HWS_V9 HWS_V8 | HWCAP_POPC +#define HWS_VA HWS_V9 | HWCAP_VIS +#define HWS_VB HWS_VA | HWCAP_VIS2 +#define HWS_VC HWS_VB | HWCAP_ASI_BLK_INIT +#define HWS_VD HWS_VC | HWCAP_FMAF | HWCAP_VIS3 | HWCAP_HPC +#define HWS_VE HWS_VD \ + | HWCAP_AES | HWCAP_DES | HWCAP_KASUMI | HWCAP_CAMELLIA \ + | HWCAP_MD5 | HWCAP_SHA1 | HWCAP_SHA256 |HWCAP_SHA512 | HWCAP_MPMUL \ + | HWCAP_MONT | HWCAP_CRC32C | HWCAP_CBCOND | HWCAP_PAUSE +#define HWS_VV HWS_VE | HWCAP_FJFMAU | HWCAP_IMA +#define HWS_VM HWS_VV + +#define HWS2_VM \ + HWCAP2_VIS3B | HWCAP2_ADP | HWCAP2_SPARC5 | HWCAP2_MWAIT \ + | HWCAP2_XMPMUL | HWCAP2_XMONT + static struct sparc_arch { - char *name; - char *opcode_arch; + const char *name; + const char *opcode_arch; enum sparc_arch_types arch_type; /* Default word size, as specified during configuration. A value of zero means can't be used to specify default architecture. */ int default_arch_size; /* Allowable arg to -A? */ int user_option_p; + int hwcap_allowed; + int hwcap2_allowed; } sparc_arch_table[] = { - { "v6", "v6", v6, 0, 1 }, - { "v7", "v7", v7, 0, 1 }, - { "v8", "v8", v8, 32, 1 }, - { "sparclet", "sparclet", sparclet, 32, 1 }, - { "sparclite", "sparclite", sparclite, 32, 1 }, - { "sparc86x", "sparclite", sparc86x, 32, 1 }, - { "v8plus", "v9", v9, 0, 1 }, - { "v8plusa", "v9a", v9, 0, 1 }, - { "v8plusb", "v9b", v9, 0, 1 }, - { "v9", "v9", v9, 0, 1 }, - { "v9a", "v9a", v9, 0, 1 }, - { "v9b", "v9b", v9, 0, 1 }, - /* This exists to allow configure.in/Makefile.in to pass one + { "v6", "v6", v6, 0, 1, 0, 0 }, + { "v7", "v7", v7, 0, 1, 0, 0 }, + { "v8", "v8", v8, 32, 1, HWS_V8, 0 }, + { "v8a", "v8", v8, 32, 1, HWS_V8, 0 }, + { "sparc", "v9", v9, 0, 1, HWCAP_V8PLUS|HWS_V9, 0 }, + { "sparcvis", "v9a", v9, 0, 1, HWS_VA, 0 }, + { "sparcvis2", "v9b", v9, 0, 1, HWS_VB, 0 }, + { "sparcfmaf", "v9b", v9, 0, 1, HWS_VB|HWCAP_FMAF, 0 }, + { "sparcima", "v9b", v9, 0, 1, HWS_VB|HWCAP_FMAF|HWCAP_IMA, 0 }, + { "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", "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 }, + { "sparclite", "sparclite", sparclite, 32, 1, HWS_V8, 0 }, + { "sparc86x", "sparclite", sparc86x, 32, 1, HWS_V8, 0 }, + + { "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", "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", "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. */ - { "v9-64", "v9", v9, 64, 0 }, - { NULL, NULL, v8, 0, 0 } + { "v9-64", "v9", v9, 64, 0, HWS_V9, 0 }, + { NULL, NULL, v8, 0, 0, 0, 0 } }; /* Variant of default_arch */ static enum sparc_arch_types default_arch_type; static struct sparc_arch * -lookup_arch (char *name) +lookup_arch (const char *name) { struct sparc_arch *sa; @@ -336,7 +394,7 @@ sparc_target_format (void) * -bump * Warn on architecture bumps. See also -A. * - * -Av6, -Av7, -Av8, -Asparclite, -Asparclet + * -Av6, -Av7, -Av8, -Aleon, -Asparclite, -Asparclet * Standard 32 bit architectures. * -Av9, -Av9a, -Av9b * Sparc64 in either a 32 or 64 bit world (-32/-64 says which). @@ -431,13 +489,15 @@ 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} }; size_t md_longopts_size = sizeof (md_longopts); int -md_parse_option (int c, char *arg) +md_parse_option (int c, const char *arg) { /* We don't get a chance to initialize anything before we're called, so handle that now. */ @@ -453,10 +513,18 @@ md_parse_option (int c, char *arg) case OPTION_XARCH: #ifdef OBJ_ELF - if (strncmp (arg, "v9", 2) != 0) - md_parse_option (OPTION_32, NULL); - else + if (!strncmp (arg, "v9", 2)) md_parse_option (OPTION_64, NULL); + else + { + if (!strncmp (arg, "v8", 2) + || !strncmp (arg, "v7", 2) + || !strncmp (arg, "v6", 2) + || !strcmp (arg, "sparclet") + || !strcmp (arg, "sparclite") + || !strcmp (arg, "sparc86x")) + md_parse_option (OPTION_32, NULL); + } #endif /* Fall through. */ @@ -480,7 +548,11 @@ md_parse_option (int c, char *arg) if (opcode_arch == SPARC_OPCODE_ARCH_BAD) as_fatal (_("Bad opcode table, broken assembler.")); - max_architecture = opcode_arch; + if (!architecture_requested + || opcode_arch > max_architecture) + max_architecture = opcode_arch; + hwcap_allowed + |= (((bfd_uint64_t) sa->hwcap2_allowed) << 32) | sa->hwcap_allowed; architecture_requested = 1; } break; @@ -602,6 +674,10 @@ md_parse_option (int c, char *arg) sparc_relax = 0; break; + case OPTION_DCTI_COUPLES_DETECT: + dcti_couples_detect = 1; + break; + default: return 0; } @@ -679,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")); @@ -693,11 +770,11 @@ md_show_usage (FILE *stream) } /* Native operand size opcode translation. */ -struct +static struct { - char *name; - char *name32; - char *name64; + const char *name; + const char *name32; + const char *name64; } native_op_table[] = { {"ldn", "ld", "ldx"}, @@ -717,7 +794,7 @@ struct struct priv_reg_entry { - char *name; + const char *name; int regnum; }; @@ -740,8 +817,9 @@ struct priv_reg_entry priv_reg_table[] = {"wstate", 14}, {"fq", 15}, {"gl", 16}, + {"pmcdper", 23}, {"ver", 31}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; struct priv_reg_entry hpriv_reg_table[] = @@ -751,12 +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[] = { @@ -769,13 +851,15 @@ struct priv_reg_entry v9a_asr_table[] = {"softint_set", 20}, {"softint", 22}, {"set_softint", 20}, + {"pause", 27}, {"pic", 17}, {"pcr", 16}, + {"mwait", 28}, {"gsr", 19}, {"dcr", 18}, - {"cps", 28}, + {"cfr", 26}, {"clear_softint", 21}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; static int @@ -784,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 @@ -794,9 +1001,9 @@ cmp_reg_entry (const void *parg, const void *qarg) void md_begin (void) { - register const char *retval = NULL; + const char *retval = NULL; int lose = 0; - register unsigned int i = 0; + 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 @@ -834,7 +1041,7 @@ md_begin (void) for (i = 0; native_op_table[i].name; i++) { const struct sparc_opcode *insn; - char *name = ((sparc_arch_size == 32) + const 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); @@ -862,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 @@ -876,16 +1087,64 @@ md_begin (void) /* `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; } + + /* Find the highest architecture level that doesn't conflict with + the requested one. */ + + if (warn_on_bump + || !architecture_requested) + { + enum sparc_opcode_arch_val current_max_architecture + = max_architecture; + + for (max_architecture = SPARC_OPCODE_ARCH_MAX; + max_architecture > warn_after_architecture; + --max_architecture) + if (! SPARC_OPCODE_CONFLICT_P (max_architecture, + 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. */ @@ -894,12 +1153,20 @@ void sparc_md_end (void) { unsigned long mach = bfd_mach_sparc; +#if defined(OBJ_ELF) && !defined(TE_SOLARIS) + int hwcaps, hwcaps2; +#endif 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; + 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 @@ -909,12 +1176,27 @@ 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). */ default: break; } bfd_set_arch_mach (stdoutput, bfd_arch_sparc, mach); + +#if defined(OBJ_ELF) && !defined(TE_SOLARIS) + hwcaps = hwcap_seen & U0xffffffff; + hwcaps2 = hwcap_seen >> 32; + + if (hwcaps) + bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS, hwcaps); + if (hwcaps2) + bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS2, hwcaps2); +#endif } /* Return non-zero if VAL is in the range -(MAX+1) to MAX. */ @@ -1121,7 +1403,7 @@ synthetize_setsw (const struct sparc_opcode *insn) output_insn (insn, &the_insn); } -/* Handle the setsw synthetic instruction. */ +/* Handle the setx synthetic instruction. */ static void synthetize_setx (const struct sparc_opcode *insn) @@ -1300,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 @@ -1368,12 +1672,95 @@ md_assemble (char *str) } } +static const char * +get_hwcap_name (bfd_uint64_t mask) +{ + if (mask & HWCAP_MUL32) + return "mul32"; + if (mask & HWCAP_DIV32) + return "div32"; + if (mask & HWCAP_FSMULD) + return "fsmuld"; + if (mask & HWCAP_V8PLUS) + return "v8plus"; + if (mask & HWCAP_POPC) + return "popc"; + if (mask & HWCAP_VIS) + return "vis"; + if (mask & HWCAP_VIS2) + return "vis2"; + if (mask & HWCAP_ASI_BLK_INIT) + return "ASIBlkInit"; + if (mask & HWCAP_FMAF) + return "fmaf"; + if (mask & HWCAP_VIS3) + return "vis3"; + if (mask & HWCAP_HPC) + return "hpc"; + if (mask & HWCAP_RANDOM) + return "random"; + if (mask & HWCAP_TRANS) + return "trans"; + if (mask & HWCAP_FJFMAU) + return "fjfmau"; + if (mask & HWCAP_IMA) + return "ima"; + if (mask & HWCAP_ASI_CACHE_SPARING) + return "cspare"; + if (mask & HWCAP_AES) + return "aes"; + if (mask & HWCAP_DES) + return "des"; + if (mask & HWCAP_KASUMI) + return "kasumi"; + if (mask & HWCAP_CAMELLIA) + return "camellia"; + if (mask & HWCAP_MD5) + return "md5"; + if (mask & HWCAP_SHA1) + return "sha1"; + if (mask & HWCAP_SHA256) + return "sha256"; + if (mask & HWCAP_SHA512) + return "sha512"; + if (mask & HWCAP_MPMUL) + return "mpmul"; + if (mask & HWCAP_MONT) + return "mont"; + if (mask & HWCAP_PAUSE) + return "pause"; + if (mask & HWCAP_CBCOND) + return "cbcond"; + if (mask & HWCAP_CRC32C) + return "crc32c"; + + mask = mask >> 32; + if (mask & HWCAP2_FJATHPLUS) + return "fjathplus"; + if (mask & HWCAP2_VIS3B) + return "vis3b"; + if (mask & HWCAP2_ADP) + return "adp"; + if (mask & HWCAP2_SPARC5) + return "sparc5"; + if (mask & HWCAP2_MWAIT) + return "mwait"; + if (mask & HWCAP2_XMPMUL) + return "xmpmul"; + if (mask & HWCAP2_XMONT) + return "xmont"; + if (mask & HWCAP2_NSEC) + return "nsec"; + + return "UNKNOWN"; +} + /* Subroutine of md_assemble to do the actual parsing. */ static int sparc_ip (char *str, const struct sparc_opcode **pinsn) { - char *error_message = ""; + const char *error_message = ""; char *s; const char *args; char c; @@ -1391,7 +1778,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { do ++s; - while (ISLOWER (*s) || ISDIGIT (*s)); + while (ISLOWER (*s) || ISDIGIT (*s) || *s == '_'); } switch (*s) @@ -1535,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; } @@ -1571,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 @@ -1604,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)) + 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) { - error_message = _(": rd on write only ancillary state register"); + error_message = _(": unrecognizable ancillary state register"); goto error; } - if (p->regnum >= 24 - && (insn->architecture - & SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A))) - { - /* %sys_tick and %sys_tick_cmpr are v9bnotv9a */ - error_message = _(": unrecognizable v9a 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; } @@ -1667,22 +2047,22 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) ++s; } - if (current_architecture >= SPARC_OPCODE_ARCH_V9) - { - if (num < 16 || 31 < num) - { - error_message = _(": asr number must be between 16 and 31"); - goto error; - } - } - else - { - if (num < 0 || 31 < num) - { - error_message = _(": asr number must be between 0 and 31"); - goto error; - } - } + /* We used to check here for the asr number to + be between 16 and 31 in V9 and later, as + mandated by the section C.1.1 "Register + Names" in the SPARC spec. However, we + decided to remove this restriction as a) it + introduces problems when new V9 asr registers + are introduced, b) the Solaris assembler + doesn't implement this restriction and c) the + restriction will go away in future revisions + of the Oracle SPARC Architecture. */ + + if (num < 0 || 31 < num) + { + error_message = _(": asr number must be between 0 and 31"); + goto error; + } opcode |= (*args == 'M' ? RS1 (num) : RD (num)); continue; @@ -1703,6 +2083,47 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) the_insn.reloc = BFD_RELOC_SPARC_10; goto immediate; + case ')': + if (*s == ' ') + s++; + if ((s[0] == '0' && s[1] == 'x' && ISXDIGIT (s[2])) + || ISDIGIT (*s)) + { + long num = 0; + + if (s[0] == '0' && s[1] == 'x') + { + s += 2; + while (ISXDIGIT (*s)) + { + num <<= 4; + num |= hex_value (*s); + ++s; + } + } + else + { + while (ISDIGIT (*s)) + { + num = num * 10 + *s - '0'; + ++s; + } + } + if (num < 0 || num > 31) + { + error_message = _(": crypto immediate must be between 0 and 31"); + goto error; + } + + opcode |= RS3 (num); + continue; + } + else + { + error_message = _(": expecting crypto immediate"); + goto error; + } + case 'X': /* V8 systems don't understand BFD_RELOC_SPARC_5. */ if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) @@ -1728,6 +2149,11 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) the_insn.pcrel = 1; goto immediate; + case '=': + the_insn.reloc = /* RELOC_WDISP2_8 */ BFD_RELOC_SPARC_WDISP10; + the_insn.pcrel = 1; + goto immediate; + case 'G': the_insn.reloc = BFD_RELOC_SPARC_WDISP19; the_insn.pcrel = 1; @@ -1754,7 +2180,8 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { ++s; } - if (strncmp (s, "%icc", 4) == 0) + if ((strncmp (s, "%icc", 4) == 0) + || (sparc_arch_size == 32 && strncmp (s, "%ncc", 4) == 0)) { s += 4; continue; @@ -1766,7 +2193,8 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { ++s; } - if (strncmp (s, "%xcc", 4) == 0) + if ((strncmp (s, "%xcc", 4) == 0) + || (sparc_arch_size == 64 && strncmp (s, "%ncc", 4) == 0)) { s += 4; continue; @@ -1840,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. */ - 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 == '(') @@ -1914,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; } @@ -2143,11 +2549,14 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case 'g': case 'H': case 'J': + case '}': { char format; if (*s++ == '%' - && ((format = *s) == 'f') + && ((format = *s) == 'f' + || format == 'd' + || format == 'q') && ISDIGIT (*++s)) { for (mask = 0; ISDIGIT (*s); ++s) @@ -2158,19 +2567,23 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) if ((*args == 'v' || *args == 'B' || *args == '5' - || *args == 'H') + || *args == 'H' + || format == 'd') && (mask & 1)) { + /* register must be even numbered */ break; - } /* register must be even numbered */ + } if ((*args == 'V' || *args == 'R' - || *args == 'J') + || *args == 'J' + || format == 'q') && (mask & 3)) { + /* register must be multiple of 4 */ break; - } /* register must be multiple of 4 */ + } if (mask >= 64) { @@ -2205,6 +2618,13 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) break; } /* if not an 'f' register. */ + if (*args == '}' && mask != RS2 (opcode)) + { + error_message + = _(": Instruction requires frs2 and frsd must be the same register"); + goto error; + } + switch (*args) { case 'v': @@ -2227,6 +2647,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case 'g': case 'H': case 'J': + case '}': opcode |= RD (mask); continue; } /* Pack it in. */ @@ -2281,77 +2702,32 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { char *s1; - char *op_arg = NULL; + const char *op_arg = NULL; static expressionS op_exp; bfd_reloc_code_real_type old_reloc = the_insn.reloc; /* Check for %hi, etc. */ if (*s == '%') { - static const struct ops { - /* The name as it appears in assembler. */ - 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 }, - { "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 @@ -2387,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; @@ -2474,6 +2855,11 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) val &= 0x3ff; break; + case BFD_RELOC_SPARC_H34: + val >>= 12; + val &= 0x3fffff; + break; + case BFD_RELOC_SPARC_H44: val >>= 22; val &= 0x3fffff; @@ -2551,6 +2937,26 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) all the various cases (e.g. in md_apply_fix and bfd_install_relocation) so duplicating all that code here isn't right. */ + + /* This is a special case to handle cbcond instructions + properly, which can need two relocations. The first + one is for the 5-bit immediate field and the latter + is going to be for the WDISP10 branch part. We + handle the R_SPARC_5 immediate directly here so that + we don't need to add support for multiple relocations + in one instruction just yet. */ + if (the_insn.reloc == BFD_RELOC_SPARC_5) + { + valueT val = the_insn.exp.X_add_number; + + if (! in_bitfield_range (val, 0x1f)) + { + error_message = _(": Immediate value in cbcond is out of range."); + goto error; + } + opcode |= val & 0x1f; + the_insn.reloc = BFD_RELOC_NONE; + } } continue; @@ -2653,6 +3059,12 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) s += 5; continue; + case '{': + if (strncmp (s, "%mcdper",7) != 0) + break; + s += 7; + continue; + case 'E': if (strncmp (s, "%ccr", 4) != 0) break; @@ -2743,7 +3155,13 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { /* We have a match. Now see if the architecture is OK. */ int needed_arch_mask = insn->architecture; + bfd_uint64_t hwcaps + = (((bfd_uint64_t) insn->hwcaps2) << 32) | insn->hwcaps; +#if defined(OBJ_ELF) && !defined(TE_SOLARIS) + if (hwcaps) + hwcap_seen |= hwcaps; +#endif if (v9_arg_p) { needed_arch_mask &= @@ -2776,6 +3194,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) warn_after_architecture = needed_architecture; } current_architecture = needed_architecture; + hwcap_allowed |= hwcaps; } /* Conflict. */ /* ??? This seems to be a bit fragile. What if the next entry in @@ -2805,12 +3224,23 @@ 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); return special_case; } + + /* Make sure the hwcaps used by the instruction are + currently enabled. */ + if (hwcaps & ~hwcap_allowed) + { + const char *hwcap_name = get_hwcap_name(hwcaps & ~hwcap_allowed); + + as_bad (_("Hardware capability \"%s\" not enabled for \"%s\"."), + hwcap_name, str); + return special_case; + } } /* If no match. */ break; @@ -2946,7 +3376,7 @@ output_insn (const struct sparc_opcode *insn, struct sparc_it *theinsn) #endif } -char * +const char * md_atof (int type, char *litP, int *sizeP) { return ieee_md_atof (type, litP, sizeP, target_big_endian); @@ -3070,8 +3500,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) /* If this is a data relocation, just output VAL. */ - if (fixP->fx_r_type == BFD_RELOC_16 - || fixP->fx_r_type == BFD_RELOC_SPARC_UA16) + if (fixP->fx_r_type == BFD_RELOC_8) + { + md_number_to_chars (buf, val, 1); + } + else if (fixP->fx_r_type == BFD_RELOC_16 + || fixP->fx_r_type == BFD_RELOC_SPARC_UA16) { md_number_to_chars (buf, val, 2); } @@ -3233,6 +3667,18 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) insn |= val & 0x1f; break; + case BFD_RELOC_SPARC_WDISP10: + if ((val & 3) + || val >= 0x007fc + || val <= -(offsetT) 0x808) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("relocation overflow")); + /* FIXME: The +1 deserves a comment. */ + val = (val >> 2) + 1; + insn |= ((val & 0x300) << 11) + | ((val & 0xff) << 5); + break; + case BFD_RELOC_SPARC_WDISP16: if ((val & 3) || val >= 0x1fffc @@ -3306,6 +3752,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) insn |= val & 0x3fffff; break; + case BFD_RELOC_SPARC_H34: + if (!fixP->fx_addsy) + { + bfd_vma tval = val; + tval >>= 12; + insn |= tval & 0x3fffff; + } + break; + case BFD_RELOC_SPARC_H44: if (!fixP->fx_addsy) { @@ -3367,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; @@ -3386,6 +3841,7 @@ tc_gen_reloc (asection *section, fixS *fixp) case BFD_RELOC_SPARC_PC22: case BFD_RELOC_SPARC_PC10: case BFD_RELOC_SPARC_BASE13: + case BFD_RELOC_SPARC_WDISP10: case BFD_RELOC_SPARC_WDISP16: case BFD_RELOC_SPARC_WDISP19: case BFD_RELOC_SPARC_WDISP22: @@ -3401,6 +3857,7 @@ tc_gen_reloc (asection *section, fixS *fixp) case BFD_RELOC_SPARC_PC_HH22: case BFD_RELOC_SPARC_PC_HM10: case BFD_RELOC_SPARC_PC_LM22: + case BFD_RELOC_SPARC_H34: case BFD_RELOC_SPARC_H44: case BFD_RELOC_SPARC_M44: case BFD_RELOC_SPARC_L44: @@ -3556,6 +4013,7 @@ tc_gen_reloc (asection *section, fixS *fixp) && code != BFD_RELOC_SPARC_WDISP22 && code != BFD_RELOC_SPARC_WDISP16 && code != BFD_RELOC_SPARC_WDISP19 + && code != BFD_RELOC_SPARC_WDISP10 && code != BFD_RELOC_SPARC_WPLT30 && code != BFD_RELOC_SPARC_TLS_GD_CALL && code != BFD_RELOC_SPARC_TLS_LDM_CALL) @@ -3572,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; @@ -3666,11 +4124,10 @@ s_reserve (int ignore ATTRIBUTE_UNUSED) int temp; symbolS *symbolP; - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&name); p = input_line_pointer; *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { @@ -3808,12 +4265,11 @@ s_common (int ignore ATTRIBUTE_UNUSED) offsetT temp, size; symbolS *symbolP; - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&name); /* Just after name is now '\0'. */ p = input_line_pointer; *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { as_bad (_("Expected comma after symbol-name")); @@ -4042,11 +4498,6 @@ s_proc (int ignore ATTRIBUTE_UNUSED) static int sparc_no_align_cons = 0; -/* This static variable is set by sparc_cons to emit requested types - of relocations in cons_fix_new_sparc. */ - -static const char *sparc_cons_special_reloc; - /* This handles the unaligned space allocation pseudo-ops, such as .uaword. .uaword is just like .word, but the value does not need to be aligned. */ @@ -4084,7 +4535,7 @@ s_register (int ignore ATTRIBUTE_UNUSED) char c; int reg; int flags; - const char *regname; + char *regname; if (input_line_pointer[0] != '%' || input_line_pointer[1] != 'g' @@ -4098,20 +4549,19 @@ s_register (int ignore ATTRIBUTE_UNUSED) if (*input_line_pointer == '#') { ++input_line_pointer; - regname = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (®name); if (strcmp (regname, "scratch") && strcmp (regname, "ignore")) as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}")); if (regname[0] == 'i') regname = NULL; else - regname = ""; + regname = (char *) ""; } else { - regname = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (®name); } + if (sparc_arch_size == 64) { if (globals[reg]) @@ -4158,7 +4608,7 @@ s_register (int ignore ATTRIBUTE_UNUSED) } } - *input_line_pointer = c; + (void) restore_line_pointer (c); demand_empty_rest_of_line (); } @@ -4314,13 +4764,13 @@ sparc_elf_final_processing (void) elf_elfheader (stdoutput)->e_flags |= EF_SPARC_SUN_US1|EF_SPARC_SUN_US3; } -void +const char * sparc_cons (expressionS *exp, int size) { char *save; + const char *sparc_cons_special_reloc = NULL; SKIP_WHITESPACE (); - sparc_cons_special_reloc = NULL; save = input_line_pointer; if (input_line_pointer[0] == '%' && input_line_pointer[1] == 'r' @@ -4447,6 +4897,7 @@ sparc_cons (expressionS *exp, int size) } if (sparc_cons_special_reloc == NULL) expression (exp); + return sparc_cons_special_reloc; } #endif @@ -4459,7 +4910,8 @@ void cons_fix_new_sparc (fragS *frag, int where, unsigned int nbytes, - expressionS *exp) + expressionS *exp, + const char *sparc_cons_special_reloc) { bfd_reloc_code_real_type r; @@ -4472,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') @@ -4502,13 +4963,19 @@ 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 (); } } fix_new_exp (frag, where, (int) nbytes, exp, 0, r); - sparc_cons_special_reloc = NULL; } void @@ -4520,18 +4987,25 @@ sparc_cfi_frame_initial_instructions (void) int sparc_regname_to_dw2regnum (char *regname) { - char *p, *q; + char *q; + int i; if (!regname[0]) return -1; - q = "goli"; - p = strchr (q, regname[0]); - if (p) + switch (regname[0]) + { + case 'g': i = 0; break; + case 'o': i = 1; break; + case 'l': i = 2; break; + case 'i': i = 3; break; + default: i = -1; break; + } + if (i != -1) { if (regname[1] < '0' || regname[1] > '8' || regname[2]) return -1; - return (p - q) * 8 + regname[1] - '0'; + return i * 8 + regname[1] - '0'; } if (regname[0] == 's' && regname[1] == 'p' && !regname[2]) return 14; @@ -4542,7 +5016,7 @@ sparc_regname_to_dw2regnum (char *regname) unsigned int regnum; regnum = strtoul (regname + 1, &q, 10); - if (p == q || *q) + if (q == NULL || *q) return -1; if (regnum >= ((regname[0] == 'f' && SPARC_OPCODE_ARCH_V9_P (max_architecture)) @@ -4562,9 +5036,7 @@ sparc_regname_to_dw2regnum (char *regname) void sparc_cfi_emit_pcrel_expr (expressionS *exp, unsigned int nbytes) { - sparc_cons_special_reloc = "disp"; sparc_no_align_cons = 1; - emit_expr (exp, nbytes); + emit_expr_with_reloc (exp, nbytes, "disp"); sparc_no_align_cons = 0; - sparc_cons_special_reloc = NULL; }