gas: sparc: fix collision of registers and pseudo-ops.
[deliverable/binutils-gdb.git] / gas / config / tc-sparc.c
index f4537330671077b023c78a88bd821fe7d2fff863..c8076bf191866d6d4f3db4b7355c71fddee98c79 100644 (file)
@@ -1,8 +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,
-   2011
-   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
@@ -50,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.  */
@@ -80,11 +77,11 @@ 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 int hwcap_seen;
+static bfd_uint64_t hwcap_seen;
 #endif
 #endif
 
-static int hwcap_allowed;
+static bfd_uint64_t hwcap_allowed;
 
 static int architecture_requested;
 static int warn_on_bump;
@@ -203,7 +200,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 struct sparc_it
   {
-    char *error;
+    const char *error;
     unsigned long opcode;
     struct nlist *nlistp;
     expressionS exp;
@@ -221,12 +218,31 @@ 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.  */
@@ -234,44 +250,57 @@ static struct sparc_arch {
   /* Allowable arg to -A?  */
   int user_option_p;
   int hwcap_allowed;
+  int hwcap2_allowed;
 } sparc_arch_table[] = {
-  { "v6", "v6", v6, 0, 1, 0 },
-  { "v7", "v7", v7, 0, 1, 0 },
-  { "v8", "v8", v8, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
-  { "v8a", "v8", v8, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
-  { "sparc", "v9", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS },
-  { "sparcvis", "v9a", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS },
-  { "sparcvis2", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2 },
-  { "sparcfmaf", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF },
-  { "sparcima", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF|F_IMA },
-  { "sparcvis3", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF|F_VIS3|F_HPC },
-  { "sparcvis3r", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF|F_VIS3|F_HPC|F_RANDOM|F_TRANS|F_FJFMAU },
-  { "sparclet", "sparclet", sparclet, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
-  { "sparclite", "sparclite", sparclite, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
-  { "sparc86x", "sparclite", sparc86x, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
-  { "v8plus", "v9", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS },
-  { "v8plusa", "v9a", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS },
-  { "v8plusb", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2 },
-  { "v8plusc", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2|F_ASI_BLK_INIT },
-  { "v8plusd", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC },
-  { "v8plusv", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC|F_RANDOM|F_TRANS|F_FJFMAU|F_IMA|F_ASI_CACHE_SPARING },
-  { "v9", "v9", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC },
-  { "v9a", "v9a", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS },
-  { "v9b", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2 },
-  { "v9c", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_ASI_BLK_INIT },
-  { "v9d", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC },
-  { "v9v", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC|F_RANDOM|F_TRANS|F_FJFMAU|F_IMA|F_ASI_CACHE_SPARING },
-  /* 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",     "v9b", v9,  0, 1, HWS_VV, 0 },
+  { "sparc5",     "v9b", 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", "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 },
+
+  { "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 },
+
+  /* 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, F_MUL32|F_DIV32|F_FSMULD|F_POPC },
-  { NULL, NULL, v8, 0, 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;
 
@@ -360,7 +389,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).
@@ -461,7 +490,7 @@ struct option md_longopts[] = {
 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.  */
@@ -477,10 +506,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.  */
 
@@ -507,7 +544,8 @@ md_parse_option (int c, char *arg)
        if (!architecture_requested
            || opcode_arch > max_architecture)
          max_architecture = opcode_arch;
-       hwcap_allowed |= sa->hwcap_allowed;
+       hwcap_allowed
+          |= (((bfd_uint64_t) sa->hwcap2_allowed) << 32) | sa->hwcap_allowed;
        architecture_requested = 1;
       }
       break;
@@ -720,11 +758,11 @@ md_show_usage (FILE *stream)
 }
 \f
 /* 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"},
@@ -744,7 +782,7 @@ struct
 
 struct priv_reg_entry
 {
-  char *name;
+  const char *name;
   int regnum;
 };
 
@@ -767,8 +805,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[] =
@@ -778,12 +817,13 @@ struct priv_reg_entry hpriv_reg_table[] =
   {"hintp", 3},
   {"htba", 5},
   {"hver", 6},
+  {"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[] =
 {
@@ -796,13 +836,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
@@ -811,7 +853,131 @@ 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);
+}
+\f
+/* 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.  */
+  int 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 },
+  { NULL, 0, 0 },
+};
+\f
+/* 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)         \
+   + ((sizeof (pop_table) / sizeof (pop_table[0])) - 1) \
+   + 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);
 }
 \f
 /* This function is called once, at assembler startup time.  It should
@@ -821,9 +987,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
@@ -861,7 +1027,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);
@@ -889,7 +1055,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
@@ -903,16 +1073,68 @@ 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.  */
+    {
+      struct pop_entry *pop;
+
+      for (pop = pop_table; pop->name; pop++)
+        {
+          struct perc_entry *p = &perc_table[entry++];
+          p->type = (pop->flags & F_POP_POSTFIX
+                     ? perc_entry_post_pop : perc_entry_imm_pop);
+          p->name = pop->name;
+          p->len = strlen (pop->name);
+          p->pop = pop;
+        }
     }
+
+    /* 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.  */
@@ -921,6 +1143,9 @@ 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)
@@ -944,45 +1169,13 @@ sparc_md_end (void)
   bfd_set_arch_mach (stdoutput, bfd_arch_sparc, mach);
 
 #if defined(OBJ_ELF) && !defined(TE_SOLARIS)
-  if (hwcap_seen)
-    {
-      int bits = 0;
-
-      if (hwcap_seen & F_MUL32)
-       bits |= ELF_SPARC_HWCAP_MUL32;
-      if (hwcap_seen & F_DIV32)
-       bits |= ELF_SPARC_HWCAP_DIV32;
-      if (hwcap_seen & F_FSMULD)
-       bits |= ELF_SPARC_HWCAP_FSMULD;
-      if (hwcap_seen & F_V8PLUS)
-       bits |= ELF_SPARC_HWCAP_V8PLUS;
-      if (hwcap_seen & F_POPC)
-       bits |= ELF_SPARC_HWCAP_POPC;
-      if (hwcap_seen & F_VIS)
-       bits |= ELF_SPARC_HWCAP_VIS;
-      if (hwcap_seen & F_VIS2)
-       bits |= ELF_SPARC_HWCAP_VIS2;
-      if (hwcap_seen & F_ASI_BLK_INIT)
-       bits |= ELF_SPARC_HWCAP_ASI_BLK_INIT;
-      if (hwcap_seen & F_FMAF)
-       bits |= ELF_SPARC_HWCAP_FMAF;
-      if (hwcap_seen & F_VIS3)
-       bits |= ELF_SPARC_HWCAP_VIS3;
-      if (hwcap_seen & F_HPC)
-       bits |= ELF_SPARC_HWCAP_HPC;
-      if (hwcap_seen & F_RANDOM)
-       bits |= ELF_SPARC_HWCAP_RANDOM;
-      if (hwcap_seen & F_TRANS)
-       bits |= ELF_SPARC_HWCAP_TRANS;
-      if (hwcap_seen & F_FJFMAU)
-       bits |= ELF_SPARC_HWCAP_FJFMAU;
-      if (hwcap_seen & F_IMA)
-       bits |= ELF_SPARC_HWCAP_IMA;
-      if (hwcap_seen & F_ASI_CACHE_SPARING)
-       bits |= ELF_SPARC_HWCAP_ASI_CACHE_SPARING;
-
-      bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS, bits);
-    }
+  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
 }
 \f
@@ -1190,7 +1383,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)
@@ -1438,40 +1631,85 @@ md_assemble (char *str)
 }
 
 static const char *
-get_hwcap_name (int mask)
+get_hwcap_name (bfd_uint64_t mask)
 {
-  if (mask & F_MUL32)
+  if (mask & HWCAP_MUL32)
     return "mul32";
-  if (mask & F_DIV32)
+  if (mask & HWCAP_DIV32)
     return "div32";
-  if (mask & F_FSMULD)
+  if (mask & HWCAP_FSMULD)
     return "fsmuld";
-  if (mask & F_V8PLUS)
+  if (mask & HWCAP_V8PLUS)
     return "v8plus";
-  if (mask & F_POPC)
+  if (mask & HWCAP_POPC)
     return "popc";
-  if (mask & F_VIS)
+  if (mask & HWCAP_VIS)
     return "vis";
-  if (mask & F_VIS2)
+  if (mask & HWCAP_VIS2)
     return "vis2";
-  if (mask & F_ASI_BLK_INIT)
+  if (mask & HWCAP_ASI_BLK_INIT)
     return "ASIBlkInit";
-  if (mask & F_FMAF)
+  if (mask & HWCAP_FMAF)
     return "fmaf";
-  if (mask & F_VIS3)
+  if (mask & HWCAP_VIS3)
     return "vis3";
-  if (mask & F_HPC)
+  if (mask & HWCAP_HPC)
     return "hpc";
-  if (mask & F_RANDOM)
+  if (mask & HWCAP_RANDOM)
     return "random";
-  if (mask & F_TRANS)
+  if (mask & HWCAP_TRANS)
     return "trans";
-  if (mask & F_FJFMAU)
+  if (mask & HWCAP_FJFMAU)
     return "fjfmau";
-  if (mask & F_IMA)
+  if (mask & HWCAP_IMA)
     return "ima";
-  if (mask & F_ASI_CACHE_SPARING)
+  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";
 }
 
@@ -1480,7 +1718,7 @@ get_hwcap_name (int mask)
 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;
@@ -1498,7 +1736,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)
@@ -1642,20 +1880,19 @@ 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;
@@ -1678,20 +1915,19 @@ 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;
@@ -1714,20 +1950,19 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
              /* Parse a v9a/v9b 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])
+                  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 = _(": unrecognizable v9a or v9b ancillary state register");
                      goto error;
@@ -1774,22 +2009,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;
@@ -1810,6 +2045,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))
@@ -1835,6 +2111,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;
@@ -1861,7 +2142,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;
@@ -1873,7 +2155,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;
@@ -1947,67 +2230,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 == '(')
@@ -2021,7 +2282,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;
                    }
 
@@ -2250,11 +2511,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)
@@ -2265,19 +2529,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)
                      {
@@ -2312,6 +2580,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':
@@ -2334,6 +2609,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
                  case 'g':
                  case 'H':
                  case 'J':
+                 case '}':
                    opcode |= RD (mask);
                    continue;
                  }             /* Pack it in.  */
@@ -2388,77 +2664,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
@@ -2494,6 +2725,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;
@@ -2581,6 +2817,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;
@@ -2658,6 +2899,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;
@@ -2760,6 +3021,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;
@@ -2850,7 +3117,8 @@ 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;
-         int hwcaps = insn->flags & F_HWCAP_MASK;
+         bfd_uint64_t hwcaps
+           = (((bfd_uint64_t) insn->hwcaps2) << 32) | insn->hwcaps;
 
 #if defined(OBJ_ELF) && !defined(TE_SOLARIS)
          if (hwcaps)
@@ -2888,6 +3156,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
@@ -2924,7 +3193,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
              return special_case;
            }
 
-         /* Make sure the the hwcaps used by the instruction are
+         /* Make sure the hwcaps used by the instruction are
             currently enabled.  */
          if (hwcaps & ~hwcap_allowed)
            {
@@ -3069,7 +3338,7 @@ output_insn (const struct sparc_opcode *insn, struct sparc_it *theinsn)
 #endif
 }
 \f
-char *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
   return ieee_md_atof (type, litP, sizeP, target_big_endian);
@@ -3360,6 +3629,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
@@ -3433,6 +3714,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)
            {
@@ -3494,10 +3784,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;
 
@@ -3513,6 +3803,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:
@@ -3528,6 +3819,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:
@@ -3683,6 +3975,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)
@@ -3699,10 +3992,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;
@@ -3793,11 +4086,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 != ',')
     {
@@ -3935,12 +4227,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"));
@@ -4169,11 +4460,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.  */
@@ -4211,7 +4497,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'
@@ -4225,20 +4511,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 (&regname);
       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 (&regname);
     }
+
   if (sparc_arch_size == 64)
     {
       if (globals[reg])
@@ -4285,7 +4570,7 @@ s_register (int ignore ATTRIBUTE_UNUSED)
        }
     }
 
-  *input_line_pointer = c;
+  (void) restore_line_pointer (c);
 
   demand_empty_rest_of_line ();
 }
@@ -4441,13 +4726,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'
@@ -4574,6 +4859,7 @@ sparc_cons (expressionS *exp, int size)
     }
   if (sparc_cons_special_reloc == NULL)
     expression (exp);
+  return sparc_cons_special_reloc;
 }
 
 #endif
@@ -4586,7 +4872,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;
 
@@ -4635,7 +4922,6 @@ cons_fix_new_sparc (fragS *frag,
    }
 
   fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
-  sparc_cons_special_reloc = NULL;
 }
 
 void
@@ -4647,18 +4933,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;
@@ -4669,7 +4962,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))
@@ -4689,9 +4982,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;
 }
This page took 0.055611 seconds and 4 git commands to generate.