Remove documention of dead "target vxworks"
[deliverable/binutils-gdb.git] / gas / config / tc-sparc.c
index 692a7fa15a1e08023cef5c451d7e81abdf5f89ac..74976182bb72a22cc9919feaf7e825b4985f0621 100644 (file)
@@ -1,12 +1,10 @@
 /* tc-sparc.c -- Assemble for the SPARC
-   Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright (C) 1989-2014 Free Software Foundation, Inc.
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public
    License along with GAS; see the file COPYING.  If not, write
-   to the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <stdio.h>
+   to the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
 
 #include "opcode/sparc.h"
+#include "dw2gencfi.h"
 
 #ifdef OBJ_ELF
 #include "elf/sparc.h"
 #include "dwarf2dbg.h"
 #endif
 
-static struct sparc_arch *lookup_arch PARAMS ((char *));
-static void init_default_arch PARAMS ((void));
-static int sparc_ip PARAMS ((char *, const struct sparc_opcode **));
-static int in_signed_range PARAMS ((bfd_signed_vma, bfd_signed_vma));
-static int in_unsigned_range PARAMS ((bfd_vma, bfd_vma));
-static int in_bitfield_range PARAMS ((bfd_signed_vma, bfd_signed_vma));
-static int sparc_ffs PARAMS ((unsigned int));
-static void synthetize_setuw PARAMS ((const struct sparc_opcode *));
-static void synthetize_setsw PARAMS ((const struct sparc_opcode *));
-static void synthetize_setx PARAMS ((const struct sparc_opcode *));
-static bfd_vma BSR PARAMS ((bfd_vma, int));
-static int cmp_reg_entry PARAMS ((const PTR, const PTR));
-static int parse_keyword_arg PARAMS ((int (*) (const char *), char **, int *));
-static int parse_const_expr_arg PARAMS ((char **, int *));
-static int get_expression PARAMS ((char *str));
+/* Some ancient Sun C compilers would not take such hex constants as
+   unsigned, and would end up sign-extending them to form an offsetT,
+   so use these constants instead.  */
+#define U0xffffffff ((((unsigned long) 1 << 16) << 16) - 1)
+#define U0x80000000 ((((unsigned long) 1 << 16) << 15))
+
+static int sparc_ip (char *, const struct sparc_opcode **);
+static int parse_keyword_arg (int (*) (const char *), char **, int *);
+static int parse_const_expr_arg (char **, int *);
+static int get_expression (char *);
 
 /* Default architecture.  */
 /* ??? The default value should be V8, but sparclite support was added
@@ -81,7 +73,15 @@ 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 int hwcap_seen;
 #endif
+#endif
+
+static int hwcap_allowed;
 
 static int architecture_requested;
 static int warn_on_bump;
@@ -110,6 +110,9 @@ static int target_little_endian_data;
 /* Symbols for global registers on v9.  */
 static symbolS *globals[8];
 
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
+int sparc_cie_data_alignment;
+
 /* V9 and 86x have big and little endian data, but instructions are always big
    endian.  The sparclet has bi-endian support but both data and insns have
    the same endianness.  Global `target_big_endian' is used for data.
@@ -123,16 +126,17 @@ static symbolS *globals[8];
 /* Handle of the OPCODE hash table.  */
 static struct hash_control *op_hash;
 
-static int log2 PARAMS ((int));
-static void s_data1 PARAMS ((void));
-static void s_seg PARAMS ((int));
-static void s_proc PARAMS ((int));
-static void s_reserve PARAMS ((int));
-static void s_common PARAMS ((int));
-static void s_empty PARAMS ((int));
-static void s_uacons PARAMS ((int));
-static void s_ncons PARAMS ((int));
-static void s_register PARAMS ((int));
+static void s_data1 (void);
+static void s_seg (int);
+static void s_proc (int);
+static void s_reserve (int);
+static void s_common (int);
+static void s_empty (int);
+static void s_uacons (int);
+static void s_ncons (int);
+#ifdef OBJ_ELF
+static void s_register (int);
+#endif
 
 const pseudo_typeS md_pseudo_table[] =
 {
@@ -153,8 +157,6 @@ const pseudo_typeS md_pseudo_table[] =
   {"uaword", s_uacons, 4},
   {"uaxword", s_uacons, 8},
 #ifdef OBJ_ELF
-  {"file", dwarf2_directive_file, 0},
-  {"loc", dwarf2_directive_loc, 0},
   /* These are specific to sparc/svr4.  */
   {"2byte", s_uacons, 2},
   {"4byte", s_uacons, 4},
@@ -164,9 +166,6 @@ const pseudo_typeS md_pseudo_table[] =
   {NULL, 0, 0},
 };
 
-/* Size of relocation record.  */
-const int md_reloc_size = 12;
-
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  */
 const char comment_chars[] = "!";      /* JF removed '|' from
@@ -197,7 +196,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
    changed in read.c.  Ideally it shouldn't have to know about it at all,
    but nothing is ideal around here.  */
 
-#define isoctal(c)  ((unsigned) ((c) - '0') < '8')
+#define isoctal(c)  ((unsigned) ((c) - '0') < 8)
 
 struct sparc_it
   {
@@ -212,15 +211,14 @@ struct sparc_it
 
 struct sparc_it the_insn, set_insn;
 
-static void output_insn
-  PARAMS ((const struct sparc_opcode *, struct sparc_it *));
+static void output_insn (const struct sparc_opcode *, struct sparc_it *);
 \f
 /* Table of arguments to -A.
    The sparc_opcode_arch table in sparc-opc.c is insufficient and incorrect
    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};
 
 static struct sparc_arch {
@@ -232,31 +230,49 @@ static struct sparc_arch {
   int default_arch_size;
   /* Allowable arg to -A?  */
   int user_option_p;
+  int hwcap_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 },
+  { "v7", "v7", v7, 0, 1, 0 },
+  { "v8", "v8", v8, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD },
+  { "v8a", "v8", v8, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD },
+  { "sparc", "v9", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS },
+  { "sparcvis", "v9a", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS },
+  { "sparcvis2", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2 },
+  { "sparcfmaf", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF },
+  { "sparcima", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_IMA },
+  { "sparcvis3", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC },
+  { "sparcvis3r", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU },
+  { "sparc4", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU|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 },
+  { "leon", "leon", leon, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD },
+  { "sparclet", "sparclet", sparclet, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD },
+  { "sparclite", "sparclite", sparclite, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD },
+  { "sparc86x", "sparclite", sparc86x, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD },
+  { "v8plus", "v9", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS },
+  { "v8plusa", "v9a", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS },
+  { "v8plusb", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2 },
+  { "v8plusc", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT },
+  { "v8plusd", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC },
+  { "v8pluse", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|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 },
+  { "v8plusv", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU|HWCAP_IMA|HWCAP_ASI_CACHE_SPARING|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 },
+  { "v9", "v9", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC },
+  { "v9a", "v9a", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS },
+  { "v9b", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2 },
+  { "v9c", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT },
+  { "v9d", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC },
+  { "v9e", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|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 },
+  { "v9v", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU|HWCAP_IMA|HWCAP_ASI_CACHE_SPARING|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 },
+  /* 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, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC },
+  { NULL, NULL, v8, 0, 0, 0 }
 };
 
 /* Variant of default_arch */
 static enum sparc_arch_types default_arch_type;
 
 static struct sparc_arch *
-lookup_arch (name)
-     char *name;
+lookup_arch (char *name)
 {
   struct sparc_arch *sa;
 
@@ -272,7 +288,7 @@ lookup_arch (name)
    architecture name.  */
 
 static void
-init_default_arch ()
+init_default_arch (void)
 {
   struct sparc_arch *sa = lookup_arch (default_arch);
 
@@ -291,7 +307,7 @@ init_default_arch ()
 /* Called by TARGET_FORMAT.  */
 
 const char *
-sparc_target_format ()
+sparc_target_format (void)
 {
   /* We don't get a chance to initialize anything before we're called,
      so handle that now.  */
@@ -327,8 +343,12 @@ sparc_target_format ()
 #endif
 #endif
 
+#ifdef TE_VXWORKS
+  return "elf32-sparc-vxworks";
+#endif
+
 #ifdef OBJ_ELF
-  return sparc_arch_size == 64 ? "elf64-sparc" : "elf32-sparc";
+  return sparc_arch_size == 64 ? ELF64_TARGET_FORMAT : ELF_TARGET_FORMAT;
 #endif
 
   abort ();
@@ -341,7 +361,7 @@ sparc_target_format ()
  *     -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).
@@ -389,12 +409,12 @@ sparc_target_format ()
  */
 
 #ifdef OBJ_ELF
-CONST char *md_shortopts = "A:K:VQ:sq";
+const char *md_shortopts = "A:K:VQ:sq";
 #else
 #ifdef OBJ_AOUT
-CONST char *md_shortopts = "A:k";
+const char *md_shortopts = "A:k";
 #else
-CONST char *md_shortopts = "A:";
+const char *md_shortopts = "A:";
 #endif
 #endif
 struct option md_longopts[] = {
@@ -442,9 +462,7 @@ struct option md_longopts[] = {
 size_t md_longopts_size = sizeof (md_longopts);
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+md_parse_option (int c, char *arg)
 {
   /* We don't get a chance to initialize anything before we're called,
      so handle that now.  */
@@ -460,10 +478,18 @@ md_parse_option (c, 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.  */
 
@@ -487,7 +513,10 @@ md_parse_option (c, 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 |= sa->hwcap_allowed;
        architecture_requested = 1;
       }
       break;
@@ -536,12 +565,12 @@ md_parse_option (c, arg)
          {
            if (sparc_arch_size == 32)
              {
-               if (strcmp (*l, "elf32-sparc") == 0)
+               if (CONST_STRNEQ (*l, "elf32-sparc"))
                  break;
              }
            else
              {
-               if (strcmp (*l, "elf64-sparc") == 0)
+               if (CONST_STRNEQ (*l, "elf64-sparc"))
                  break;
              }
          }
@@ -549,6 +578,10 @@ md_parse_option (c, arg)
          as_fatal (_("No compiled in support for %d bit object file format"),
                    sparc_arch_size);
        free (list);
+
+       if (sparc_arch_size == 64
+           && max_architecture < SPARC_OPCODE_ARCH_V9)
+         max_architecture = SPARC_OPCODE_ARCH_V9;
       }
       break;
 
@@ -613,8 +646,7 @@ md_parse_option (c, arg)
 }
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   const struct sparc_arch *arch;
   int column;
@@ -717,7 +749,7 @@ struct
   {NULL, NULL, NULL},
 };
 \f
-/* sparc64 priviledged registers.  */
+/* sparc64 privileged and hyperprivileged registers.  */
 
 struct priv_reg_entry
 {
@@ -743,31 +775,51 @@ struct priv_reg_entry priv_reg_table[] =
   {"otherwin", 13},
   {"wstate", 14},
   {"fq", 15},
+  {"gl", 16},
   {"ver", 31},
   {"", -1},                    /* End marker.  */
 };
 
-/* v9a specific asrs.  */
+struct priv_reg_entry hpriv_reg_table[] =
+{
+  {"hpstate", 0},
+  {"htstate", 1},
+  {"hintp", 3},
+  {"htba", 5},
+  {"hver", 6},
+  {"hstick_offset", 28},
+  {"hstick_enable", 29},
+  {"hstick_cmpr", 31},
+  {"", -1},                    /* End marker.  */
+};
+
+/* v9a specific asrs.  This table is ordered by initial
+   letter, in reverse.  */
 
 struct priv_reg_entry v9a_asr_table[] =
 {
   {"tick_cmpr", 23},
   {"sys_tick_cmpr", 25},
   {"sys_tick", 24},
+  {"stick_cmpr", 25},
+  {"stick", 24},
+  {"softint_clear", 21},
+  {"softint_set", 20},
   {"softint", 22},
   {"set_softint", 20},
+  {"pause", 27},
   {"pic", 17},
   {"pcr", 16},
   {"gsr", 19},
   {"dcr", 18},
+  {"cps", 28},
+  {"cfr", 26},
   {"clear_softint", 21},
   {"", -1},                    /* End marker.  */
 };
 
 static int
-cmp_reg_entry (parg, qarg)
-     const PTR parg;
-     const PTR qarg;
+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;
@@ -780,7 +832,7 @@ cmp_reg_entry (parg, qarg)
    need.  */
 
 void
-md_begin ()
+md_begin (void)
 {
   register const char *retval = NULL;
   int lose = 0;
@@ -792,12 +844,13 @@ md_begin ()
   if (! default_init_p)
     init_default_arch ();
 
+  sparc_cie_data_alignment = sparc_arch_size == 64 ? -8 : -4;
   op_hash = hash_new ();
 
   while (i < (unsigned int) sparc_num_opcodes)
     {
       const char *name = sparc_opcodes[i].name;
-      retval = hash_insert (op_hash, name, (PTR) &sparc_opcodes[i]);
+      retval = hash_insert (op_hash, name, (void *) &sparc_opcodes[i]);
       if (retval != NULL)
        {
          as_bad (_("Internal error: can't hash `%s': %s\n"),
@@ -833,7 +886,8 @@ md_begin ()
        }
       else
        {
-         retval = hash_insert (op_hash, native_op_table[i].name, (PTR) insn);
+         retval = hash_insert (op_hash, native_op_table[i].name,
+                               (void *) insn);
          if (retval != NULL)
            {
              as_bad (_("Internal error: can't hash `%s': %s\n"),
@@ -862,22 +916,30 @@ md_begin ()
       /* `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;
+  }
 }
 
 /* Called after all assembly has been done.  */
 
 void
-sparc_md_end ()
+sparc_md_end (void)
 {
   unsigned long mach = bfd_mach_sparc;
 
@@ -901,13 +963,17 @@ sparc_md_end ()
       default: break;
       }
   bfd_set_arch_mach (stdoutput, bfd_arch_sparc, mach);
+
+#if defined(OBJ_ELF) && !defined(TE_SOLARIS)
+  if (hwcap_seen)
+    bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS, hwcap_seen);
+#endif
 }
 \f
 /* Return non-zero if VAL is in the range -(MAX+1) to MAX.  */
 
-static INLINE int
-in_signed_range (val, max)
-     bfd_signed_vma val, max;
+static inline int
+in_signed_range (bfd_signed_vma val, bfd_signed_vma max)
 {
   if (max <= 0)
     abort ();
@@ -916,7 +982,7 @@ in_signed_range (val, max)
   if (sparc_arch_size == 32)
     {
       bfd_signed_vma sign = (bfd_signed_vma) 1 << 31;
-      val = ((val & 0xffffffff) ^ sign) - sign;
+      val = ((val & U0xffffffff) ^ sign) - sign;
     }
   if (val > max)
     return 0;
@@ -927,9 +993,8 @@ in_signed_range (val, max)
 
 /* Return non-zero if VAL is in the range 0 to MAX.  */
 
-static INLINE int
-in_unsigned_range (val, max)
-     bfd_vma val, max;
+static inline int
+in_unsigned_range (bfd_vma val, bfd_vma max)
 {
   if (val > max)
     return 0;
@@ -939,9 +1004,8 @@ in_unsigned_range (val, max)
 /* Return non-zero if VAL is in the range -(MAX/2+1) to MAX.
    (e.g. -15 to +31).  */
 
-static INLINE int
-in_bitfield_range (val, max)
-     bfd_signed_vma val, max;
+static inline int
+in_bitfield_range (bfd_signed_vma val, bfd_signed_vma max)
 {
   if (max <= 0)
     abort ();
@@ -953,8 +1017,7 @@ in_bitfield_range (val, max)
 }
 
 static int
-sparc_ffs (mask)
-     unsigned int mask;
+sparc_ffs (unsigned int mask)
 {
   int i;
 
@@ -968,9 +1031,7 @@ sparc_ffs (mask)
 
 /* Implement big shift right.  */
 static bfd_vma
-BSR (val, amount)
-     bfd_vma val;
-     int amount;
+BSR (bfd_vma val, int amount)
 {
   if (sizeof (bfd_vma) <= 4 && amount >= 32)
     as_fatal (_("Support for 64-bit arithmetic not compiled in."));
@@ -1007,8 +1068,7 @@ static unsigned long last_opcode;
 /* Handle the set and setuw synthetic instructions.  */
 
 static void
-synthetize_setuw (insn)
-     const struct sparc_opcode *insn;
+synthetize_setuw (const struct sparc_opcode *insn)
 {
   int need_hi22_p = 0;
   int rd = (the_insn.opcode & RD (~0)) >> 25;
@@ -1019,14 +1079,14 @@ synthetize_setuw (insn)
        {
          if (sizeof (offsetT) > 4
              && (the_insn.exp.X_add_number < 0
-                 || the_insn.exp.X_add_number > (offsetT) 0xffffffff))
+                 || the_insn.exp.X_add_number > (offsetT) U0xffffffff))
            as_warn (_("set: number not in 0..4294967295 range"));
        }
       else
        {
          if (sizeof (offsetT) > 4
-             && (the_insn.exp.X_add_number < -(offsetT) 0x80000000
-                 || the_insn.exp.X_add_number > (offsetT) 0xffffffff))
+             && (the_insn.exp.X_add_number < -(offsetT) U0x80000000
+                 || the_insn.exp.X_add_number > (offsetT) U0xffffffff))
            as_warn (_("set: number not in -2147483648..4294967295 range"));
          the_insn.exp.X_add_number = (int) the_insn.exp.X_add_number;
        }
@@ -1066,8 +1126,7 @@ synthetize_setuw (insn)
 /* Handle the setsw synthetic instruction.  */
 
 static void
-synthetize_setsw (insn)
-     const struct sparc_opcode *insn;
+synthetize_setsw (const struct sparc_opcode *insn)
 {
   int low32, rd, opc;
 
@@ -1085,8 +1144,8 @@ synthetize_setsw (insn)
     }
 
   if (sizeof (offsetT) > 4
-      && (the_insn.exp.X_add_number < -(offsetT) 0x80000000
-         || the_insn.exp.X_add_number > (offsetT) 0xffffffff))
+      && (the_insn.exp.X_add_number < -(offsetT) U0x80000000
+         || the_insn.exp.X_add_number > (offsetT) U0xffffffff))
     as_warn (_("setsw: number not in -2147483648..4294967295 range"));
 
   low32 = the_insn.exp.X_add_number;
@@ -1118,8 +1177,7 @@ synthetize_setsw (insn)
 /* Handle the setsw synthetic instruction.  */
 
 static void
-synthetize_setx (insn)
-     const struct sparc_opcode *insn;
+synthetize_setx (const struct sparc_opcode *insn)
 {
   int upper32, lower32;
   int tmpreg = (the_insn.opcode & RS1 (~0)) >> 14;
@@ -1128,7 +1186,7 @@ synthetize_setx (insn)
   int need_hh22_p = 0, need_hm10_p = 0, need_hi22_p = 0, need_lo10_p = 0;
   int need_xor10_p = 0;
 
-#define SIGNEXT32(x) ((((x) & 0xffffffff) ^ 0x80000000) - 0x80000000)
+#define SIGNEXT32(x) ((((x) & U0xffffffff) ^ U0x80000000) - U0x80000000)
   lower32 = SIGNEXT32 (the_insn.exp.X_add_number);
   upper32 = SIGNEXT32 (BSR (the_insn.exp.X_add_number, 32));
 #undef SIGNEXT32
@@ -1285,19 +1343,19 @@ synthetize_setx (insn)
 /* Main entry point to assemble one instruction.  */
 
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   const struct sparc_opcode *insn;
   int special_case;
 
   know (str);
   special_case = sparc_ip (str, &insn);
+  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.  */
-  if (insn != NULL
-      && last_insn != NULL
+  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
@@ -1310,7 +1368,6 @@ md_assemble (str)
      point instruction and a floating point branch.  We insert one
      automatically, with a warning.  */
   if (max_architecture < SPARC_OPCODE_ARCH_V9
-      && insn != NULL
       && last_insn != NULL
       && (insn->flags & F_FBR) != 0
       && (last_insn->flags & F_FLOAT) != 0)
@@ -1353,7 +1410,7 @@ md_assemble (str)
           The workaround is to add an fmovs of the destination register to
           itself just after the instruction.  This was true on machines
           with Weitek 1165 float chips, such as the Sun-4/260 and /280.  */
-       assert (the_insn.reloc == BFD_RELOC_NONE);
+       gas_assert (the_insn.reloc == BFD_RELOC_NONE);
        the_insn.opcode = FMOVS_INSN | rd | RD (rd);
        output_insn (insn, &the_insn);
        return;
@@ -1364,12 +1421,74 @@ md_assemble (str)
     }
 }
 
+static const char *
+get_hwcap_name (int 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";
+  return "UNKNOWN";
+}
+
 /* Subroutine of md_assemble to do the actual parsing.  */
 
 static int
-sparc_ip (str, pinsn)
-     char *str;
-     const struct sparc_opcode **pinsn;
+sparc_ip (char *str, const struct sparc_opcode **pinsn)
 {
   char *error_message = "";
   char *s;
@@ -1389,7 +1508,7 @@ sparc_ip (str, pinsn)
     {
       do
        ++s;
-      while (ISLOWER (*s) || ISDIGIT (*s));
+      while (ISLOWER (*s) || ISDIGIT (*s) || *s == '_');
     }
 
   switch (*s)
@@ -1406,7 +1525,9 @@ sparc_ip (str, pinsn)
       break;
 
     default:
-      as_fatal (_("Unknown opcode: `%s'"), str);
+      as_bad (_("Unknown opcode: `%s'"), str);
+      *pinsn = NULL;
+      return special_case;
     }
   insn = (struct sparc_opcode *) hash_find (op_hash, str);
   *pinsn = insn;
@@ -1443,15 +1564,15 @@ sparc_ip (str, pinsn)
                  {
                    while (*s == '#')
                      {
-                       int mask;
+                       int jmask;
 
                        if (! parse_keyword_arg (sparc_encode_membar, &s,
-                                                &mask))
+                                                &jmask))
                          {
                            error_message = _(": invalid membar mask name");
                            goto error;
                          }
-                       kmask |= mask;
+                       kmask |= jmask;
                        while (*s == ' ')
                          ++s;
                        if (*s == '|' || *s == '+')
@@ -1562,6 +1683,42 @@ sparc_ip (str, pinsn)
                  goto error;
                }
 
+           case '$':
+           case '%':
+             /* Parse a sparc64 hyperprivileged register.  */
+             if (*s == '%')
+               {
+                 struct priv_reg_entry *p = hpriv_reg_table;
+                 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 hyperprivileged register");
+                     goto error;
+                   }
+                 if (*args == '$')
+                   opcode |= (p->regnum << 14);
+                 else
+                   opcode |= (p->regnum << 25);
+                 s += len;
+                 continue;
+               }
+             else
+               {
+                 error_message = _(": unrecognizable hyperprivileged register");
+                 goto error;
+               }
+
            case '_':
            case '/':
              /* Parse a v9a/v9b ancillary state register.  */
@@ -1663,6 +1820,47 @@ sparc_ip (str, 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))
@@ -1688,6 +1886,11 @@ sparc_ip (str, 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;
@@ -1798,10 +2001,93 @@ sparc_ip (str, pinsn)
              break;
 
            case '\0':          /* End of args.  */
-             if (*s == '\0')
+             if (s[0] == ',' && s[1] == '%')
                {
-                 match = 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;
+
+                 for (o = ops; o->name; o++)
+                   if (strncmp (s + 2, o->name, o->len) == 0)
+                     break;
+                 if (o->name == NULL)
+                   break;
+
+                 if (s[o->len + 2] != '(')
+                   {
+                     as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
+                     return special_case;
+                   }
+
+                 if (! o->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);
+                     return special_case;
+                   }
+
+                 if (o->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);
+                     return special_case;
+                   }
+
+                 the_insn.reloc = o->reloc;
+                 memset (&the_insn.exp, 0, sizeof (the_insn.exp));
+                 s += o->len + 3;
+
+                 for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
+                   if (*s1 == '(')
+                     npar++;
+                   else if (*s1 == ')')
+                     {
+                       if (!npar)
+                         break;
+                       npar--;
+                     }
+
+                 if (*s1 != ')')
+                   {
+                     as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
+                     return special_case;
+                   }
+
+                 *s1 = '\0';
+                 (void) get_expression (s);
+                 *s1 = ')';
+                 s = s1 + 1;
                }
+             if (*s == '\0')
+               match = 1;
              break;
 
            case '+':
@@ -2014,6 +2300,9 @@ sparc_ip (str, pinsn)
            case 'B':
            case 'R':
 
+           case '4':
+           case '5':
+
            case 'g':
            case 'H':
            case 'J':
@@ -2031,6 +2320,7 @@ sparc_ip (str, pinsn)
 
                    if ((*args == 'v'
                         || *args == 'B'
+                        || *args == '5'
                         || *args == 'H')
                        && (mask & 1))
                      {
@@ -2057,6 +2347,12 @@ sparc_ip (str, pinsn)
                      {
                        if (SPARC_OPCODE_ARCH_V9_P (max_architecture))
                          {
+                           if (*args == 'e' || *args == 'f' || *args == 'g')
+                             {
+                               error_message
+                                 = _(": There are only 32 single precision f registers; [0-31]");
+                               goto error;
+                             }
                            v9_arg_p = 1;
                            mask -= 31; /* wrap high bit */
                          }
@@ -2086,6 +2382,11 @@ sparc_ip (str, pinsn)
                    opcode |= RS2 (mask);
                    continue;
 
+                 case '4':
+                 case '5':
+                   opcode |= RS3 (mask);
+                   continue;
+
                  case 'g':
                  case 'H':
                  case 'J':
@@ -2105,6 +2406,14 @@ sparc_ip (str, pinsn)
                }
              break;
 
+           case '(':
+             if (strncmp (s, "%efsr", 5) == 0)
+               {
+                 s += 5;
+                 continue;
+               }
+             break;
+
            case '0':           /* 64 bit immediate (set, setsw, setx insn)  */
              the_insn.reloc = BFD_RELOC_NONE; /* reloc handled elsewhere  */
              goto immediate;
@@ -2136,7 +2445,7 @@ sparc_ip (str, pinsn)
              {
                char *s1;
                char *op_arg = NULL;
-               expressionS op_exp;
+               static expressionS op_exp;
                bfd_reloc_code_real_type old_reloc = the_insn.reloc;
 
                /* Check for %hi, etc.  */
@@ -2160,14 +2469,34 @@ sparc_ip (str, pinsn)
                      { "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 },
                      { "hi", 2, BFD_RELOC_HI22, 0, 1 },
                      { "lo", 2, BFD_RELOC_LO10, 0, 1 },
+                     { "pc22", 4, BFD_RELOC_SPARC_PC22, 0, 1 },
+                     { "pc10", 4, BFD_RELOC_SPARC_PC10, 0, 1 },
                      { "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 },
                      { "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 },
                      { "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 },
+                     { "h34", 3, BFD_RELOC_SPARC_H34, 1, 0 },
+                     { "l34", 3, BFD_RELOC_SPARC_L44, 1, 0 },
                      { "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 },
                      { "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 },
                      { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 },
                      { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 },
                      { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 },
+                     { "tgd_hi22", 8, BFD_RELOC_SPARC_TLS_GD_HI22, 0, 0 },
+                     { "tgd_lo10", 8, BFD_RELOC_SPARC_TLS_GD_LO10, 0, 0 },
+                     { "tldm_hi22", 9, BFD_RELOC_SPARC_TLS_LDM_HI22, 0, 0 },
+                     { "tldm_lo10", 9, BFD_RELOC_SPARC_TLS_LDM_LO10, 0, 0 },
+                     { "tldo_hix22", 10, BFD_RELOC_SPARC_TLS_LDO_HIX22, 0,
+                                                                        0 },
+                     { "tldo_lox10", 10, BFD_RELOC_SPARC_TLS_LDO_LOX10, 0,
+                                                                        0 },
+                     { "tie_hi22", 8, BFD_RELOC_SPARC_TLS_IE_HI22, 0, 0 },
+                     { "tie_lo10", 8, BFD_RELOC_SPARC_TLS_IE_LO10, 0, 0 },
+                     { "tle_hix22", 9, BFD_RELOC_SPARC_TLS_LE_HIX22, 0, 0 },
+                     { "tle_lox10", 9, BFD_RELOC_SPARC_TLS_LE_LOX10, 0, 0 },
+                     { "gdop_hix22", 10, BFD_RELOC_SPARC_GOTDATA_OP_HIX22,
+                       0, 0 },
+                     { "gdop_lox10", 10, BFD_RELOC_SPARC_GOTDATA_OP_LOX10,
+                       0, 0 },
                      { NULL, 0, 0, 0, 0 }
                    };
                    const struct ops *o;
@@ -2244,8 +2573,10 @@ sparc_ip (str, pinsn)
                  {
                    if (s1[-2] == '%' && s1[-3] == '+')
                      s1 -= 3;
-                   else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
+                   else if (strchr ("golir0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
                      s1 -= 4;
+                   else if (s1[-3] == 'r' && s1[-4] == '%' && s1[-5] == '+')
+                     s1 -= 5;
                    else
                      s1 = NULL;
                    if (s1)
@@ -2308,6 +2639,11 @@ sparc_ip (str, pinsn)
                            val &= 0x3ff;
                            break;
 
+                         case BFD_RELOC_SPARC_H34:
+                           val >>= 12;
+                           val &= 0x3fffff;
+                           break;
+
                          case BFD_RELOC_SPARC_H44:
                            val >>= 22;
                            val &= 0x3fffff;
@@ -2370,14 +2706,41 @@ sparc_ip (str, pinsn)
                      goto error;
                    }
 
-                 /* Constants that won't fit are checked in md_apply_fix3
+                 if (the_insn.reloc >= BFD_RELOC_SPARC_TLS_GD_HI22
+                     && the_insn.reloc <= BFD_RELOC_SPARC_TLS_TPOFF64)
+                   {
+                     error_message = _(": TLS operand can't be a constant");
+                     goto error;
+                   }
+
+                 /* Constants that won't fit are checked in md_apply_fix
                     and bfd_install_relocation.
                     ??? It would be preferable to install the constants
                     into the insn here and save having to create a fixS
                     for each one.  There already exists code to handle
-                    all the various cases (e.g. in md_apply_fix3 and
+                    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;
@@ -2570,7 +2933,12 @@ sparc_ip (str, pinsn)
        {
          /* We have a match.  Now see if the architecture is OK.  */
          int needed_arch_mask = insn->architecture;
+         int hwcaps = insn->hwcaps;
 
+#if defined(OBJ_ELF) && !defined(TE_SOLARIS)
+         if (hwcaps)
+                 hwcap_seen |= hwcaps;
+#endif
          if (v9_arg_p)
            {
              needed_arch_mask &=
@@ -2592,7 +2960,7 @@ sparc_ip (str, pinsn)
                sparc_ffs (SPARC_OPCODE_SUPPORTED (max_architecture)
                           & needed_arch_mask);
 
-             assert (needed_architecture <= SPARC_OPCODE_ARCH_MAX);
+             gas_assert (needed_architecture <= SPARC_OPCODE_ARCH_MAX);
              if (warn_on_bump
                  && needed_architecture > warn_after_architecture)
                {
@@ -2603,6 +2971,7 @@ sparc_ip (str, 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
@@ -2638,6 +3007,17 @@ sparc_ip (str, pinsn)
                         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;
@@ -2653,10 +3033,9 @@ sparc_ip (str, pinsn)
    If successful, INPUT_POINTER is updated.  */
 
 static int
-parse_keyword_arg (lookup_fn, input_pointerP, valueP)
-     int (*lookup_fn) PARAMS ((const char *));
-     char **input_pointerP;
-     int *valueP;
+parse_keyword_arg (int (*lookup_fn) (const char *),
+                  char **input_pointerP,
+                  int *valueP)
 {
   int value;
   char c, *p, *q;
@@ -2681,9 +3060,7 @@ parse_keyword_arg (lookup_fn, input_pointerP, valueP)
    The result is a boolean indicating success.  */
 
 static int
-parse_const_expr_arg (input_pointerP, valueP)
-     char **input_pointerP;
-     int *valueP;
+parse_const_expr_arg (char **input_pointerP, int *valueP)
 {
   char *save = input_line_pointer;
   expressionS exp;
@@ -2713,8 +3090,7 @@ parse_const_expr_arg (input_pointerP, valueP)
 /* Subroutine of sparc_ip to parse an expression.  */
 
 static int
-get_expression (str)
-     char *str;
+get_expression (char *str)
 {
   char *save_in;
   segT seg;
@@ -2741,131 +3117,53 @@ get_expression (str)
 /* Subroutine of md_assemble to output one insn.  */
 
 static void
-output_insn (insn, the_insn)
-     const struct sparc_opcode *insn;
-     struct sparc_it *the_insn;
+output_insn (const struct sparc_opcode *insn, struct sparc_it *theinsn)
 {
   char *toP = frag_more (4);
 
   /* Put out the opcode.  */
   if (INSN_BIG_ENDIAN)
-    number_to_chars_bigendian (toP, (valueT) the_insn->opcode, 4);
+    number_to_chars_bigendian (toP, (valueT) theinsn->opcode, 4);
   else
-    number_to_chars_littleendian (toP, (valueT) the_insn->opcode, 4);
+    number_to_chars_littleendian (toP, (valueT) theinsn->opcode, 4);
 
   /* Put out the symbol-dependent stuff.  */
-  if (the_insn->reloc != BFD_RELOC_NONE)
+  if (theinsn->reloc != BFD_RELOC_NONE)
     {
       fixS *fixP =  fix_new_exp (frag_now,     /* Which frag.  */
                                 (toP - frag_now->fr_literal),  /* Where.  */
                                 4,             /* Size.  */
-                                &the_insn->exp,
-                                the_insn->pcrel,
-                                the_insn->reloc);
+                                &theinsn->exp,
+                                theinsn->pcrel,
+                                theinsn->reloc);
       /* Turn off overflow checking in fixup_segment.  We'll do our
-        own overflow checking in md_apply_fix3.  This is necessary because
+        own overflow checking in md_apply_fix.  This is necessary because
         the insn size is 4 and fixup_segment will signal an overflow for
         large 8 byte quantities.  */
       fixP->fx_no_overflow = 1;
-      if (the_insn->reloc == BFD_RELOC_SPARC_OLO10)
-       fixP->tc_fix_data = the_insn->exp2.X_add_number;
+      if (theinsn->reloc == BFD_RELOC_SPARC_OLO10)
+       fixP->tc_fix_data = theinsn->exp2.X_add_number;
     }
 
   last_insn = insn;
-  last_opcode = the_insn->opcode;
+  last_opcode = theinsn->opcode;
 
 #ifdef OBJ_ELF
   dwarf2_emit_insn (4);
 #endif
 }
 \f
-/* This is identical to the md_atof in m68k.c.  I think this is right,
-   but I'm not sure.
-
-   Turn a string in input_line_pointer into a floating point constant
-   of type TYPE, and store the appropriate bytes in *LITP.  The number
-   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
-   returned, or NULL on OK.  */
-
-/* Equal to MAX_PRECISION in atof-ieee.c.  */
-#define MAX_LITTLENUMS 6
-
 char *
-md_atof (type, litP, sizeP)
-     char type;
-     char *litP;
-     int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
 {
-  int i, prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  char *t;
-
-  switch (type)
-    {
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-      prec = 2;
-      break;
-
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-      prec = 4;
-      break;
-
-    case 'x':
-    case 'X':
-      prec = 6;
-      break;
-
-    case 'p':
-    case 'P':
-      prec = 6;
-      break;
-
-    default:
-      *sizeP = 0;
-      return _("Bad call to MD_ATOF()");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-  *sizeP = prec * sizeof (LITTLENUM_TYPE);
-
-  if (target_big_endian)
-    {
-      for (i = 0; i < prec; i++)
-       {
-         md_number_to_chars (litP, (valueT) words[i],
-                             sizeof (LITTLENUM_TYPE));
-         litP += sizeof (LITTLENUM_TYPE);
-       }
-    }
-  else
-    {
-      for (i = prec - 1; i >= 0; i--)
-       {
-         md_number_to_chars (litP, (valueT) words[i],
-                             sizeof (LITTLENUM_TYPE));
-         litP += sizeof (LITTLENUM_TYPE);
-       }
-    }
-
-  return 0;
+  return ieee_md_atof (type, litP, sizeP, target_big_endian);
 }
 
 /* Write a value out to the object file, using the appropriate
    endianness.  */
 
 void
-md_number_to_chars (buf, val, n)
-     char *buf;
-     valueT val;
-     int n;
+md_number_to_chars (char *buf, valueT val, int n)
 {
   if (target_big_endian)
     number_to_chars_bigendian (buf, val, n);
@@ -2881,47 +3179,54 @@ md_number_to_chars (buf, val, n)
 /* Apply a fixS to the frags, now that we know the value it ought to
    hold.  */
 
-int
-md_apply_fix3 (fixP, value, segment)
-     fixS *fixP;
-     valueT *value;
-     segT segment;
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED)
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
-  offsetT val;
+  offsetT val = * (offsetT *) valP;
   long insn;
 
-  val = *value;
-
-  assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+  gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
 
   fixP->fx_addnumber = val;    /* Remember value for emit_reloc.  */
 
 #ifdef OBJ_ELF
-  /* FIXME: SPARC ELF relocations don't use an addend in the data
-     field itself.  This whole approach should be somehow combined
-     with the calls to bfd_install_relocation.  Also, the value passed
-     in by fixup_segment includes the value of a defined symbol.  We
-     don't want to include the value of an externally visible symbol.  */
+  /* SPARC ELF relocations don't use an addend in the data field.  */
   if (fixP->fx_addsy != NULL)
     {
-      if (symbol_used_in_reloc_p (fixP->fx_addsy)
-         && (S_IS_EXTERNAL (fixP->fx_addsy)
-             || S_IS_WEAK (fixP->fx_addsy)
-             || (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE)
-             || (sparc_pic_code && ! fixP->fx_pcrel)
-             || (S_GET_SEGMENT (fixP->fx_addsy) != segment
-                 && ((bfd_get_section_flags (stdoutput,
-                                             S_GET_SEGMENT (fixP->fx_addsy))
-                      & SEC_LINK_ONCE) != 0
-                     || strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
-                                 ".gnu.linkonce",
-                                 sizeof ".gnu.linkonce" - 1) == 0)))
-         && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section
-         && S_GET_SEGMENT (fixP->fx_addsy) != undefined_section
-         && ! bfd_is_com_section (S_GET_SEGMENT (fixP->fx_addsy)))
-       fixP->fx_addnumber -= S_GET_VALUE (fixP->fx_addsy);
-      return 1;
+      switch (fixP->fx_r_type)
+       {
+       case BFD_RELOC_SPARC_TLS_GD_HI22:
+       case BFD_RELOC_SPARC_TLS_GD_LO10:
+       case BFD_RELOC_SPARC_TLS_GD_ADD:
+       case BFD_RELOC_SPARC_TLS_GD_CALL:
+       case BFD_RELOC_SPARC_TLS_LDM_HI22:
+       case BFD_RELOC_SPARC_TLS_LDM_LO10:
+       case BFD_RELOC_SPARC_TLS_LDM_ADD:
+       case BFD_RELOC_SPARC_TLS_LDM_CALL:
+       case BFD_RELOC_SPARC_TLS_LDO_HIX22:
+       case BFD_RELOC_SPARC_TLS_LDO_LOX10:
+       case BFD_RELOC_SPARC_TLS_LDO_ADD:
+       case BFD_RELOC_SPARC_TLS_IE_HI22:
+       case BFD_RELOC_SPARC_TLS_IE_LO10:
+       case BFD_RELOC_SPARC_TLS_IE_LD:
+       case BFD_RELOC_SPARC_TLS_IE_LDX:
+       case BFD_RELOC_SPARC_TLS_IE_ADD:
+       case BFD_RELOC_SPARC_TLS_LE_HIX22:
+       case BFD_RELOC_SPARC_TLS_LE_LOX10:
+       case BFD_RELOC_SPARC_TLS_DTPMOD32:
+       case BFD_RELOC_SPARC_TLS_DTPMOD64:
+       case BFD_RELOC_SPARC_TLS_DTPOFF32:
+       case BFD_RELOC_SPARC_TLS_DTPOFF64:
+       case BFD_RELOC_SPARC_TLS_TPOFF32:
+       case BFD_RELOC_SPARC_TLS_TPOFF64:
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
+
+       default:
+         break;
+       }
+
+      return;
     }
 #endif
 
@@ -2972,8 +3277,12 @@ md_apply_fix3 (fixP, value, segment)
 
   /* 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);
     }
@@ -2992,7 +3301,7 @@ md_apply_fix3 (fixP, value, segment)
            || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     {
       fixP->fx_done = 0;
-      return 1;
+      return;
     }
   else
     {
@@ -3135,10 +3444,22 @@ md_apply_fix3 (fixP, value, segment)
          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:
-         /* FIXME: simplify.  */
-         if (((val > 0) && (val & ~0x3fffc))
-             || ((val < 0) && (~(val - 1) & ~0x3fffc)))
+         if ((val & 3)
+             || val >= 0x1fffc
+             || val <= -(offsetT) 0x20008)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relocation overflow"));
          /* FIXME: The +1 deserves a comment.  */
@@ -3147,9 +3468,9 @@ md_apply_fix3 (fixP, value, segment)
          break;
 
        case BFD_RELOC_SPARC_WDISP19:
-         /* FIXME: simplify.  */
-         if (((val > 0) && (val & ~0x1ffffc))
-             || ((val < 0) && (~(val - 1) & ~0x1ffffc)))
+         if ((val & 3)
+             || val >= 0xffffc
+             || val <= -(offsetT) 0x100008)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relocation overflow"));
          /* FIXME: The +1 deserves a comment.  */
@@ -3164,14 +3485,10 @@ md_apply_fix3 (fixP, value, segment)
        case BFD_RELOC_SPARC_LM22:
        case BFD_RELOC_HI22:
          if (!fixP->fx_addsy)
-           {
-             insn |= (val >> 10) & 0x3fffff;
-           }
+           insn |= (val >> 10) & 0x3fffff;
          else
-           {
-             /* FIXME: Need comment explaining why we do this.  */
-             insn &= ~0xffff;
-           }
+           /* FIXME: Need comment explaining why we do this.  */
+           insn &= ~0xffff;
          break;
 
        case BFD_RELOC_SPARC22:
@@ -3187,14 +3504,10 @@ md_apply_fix3 (fixP, value, segment)
 
        case BFD_RELOC_LO10:
          if (!fixP->fx_addsy)
-           {
-             insn |= val & 0x3ff;
-           }
+           insn |= val & 0x3ff;
          else
-           {
-             /* FIXME: Need comment explaining why we do this.  */
-             insn &= ~0xff;
-           }
+           /* FIXME: Need comment explaining why we do this.  */
+           insn &= ~0xff;
          break;
 
        case BFD_RELOC_SPARC_OLO10:
@@ -3216,6 +3529,15 @@ md_apply_fix3 (fixP, value, segment)
          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)
            {
@@ -3265,17 +3587,13 @@ md_apply_fix3 (fixP, value, segment)
   /* Are we finished with this relocation now?  */
   if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
     fixP->fx_done = 1;
-
-  return 1;
 }
 
 /* Translate internal representation of relocation info to BFD target
    format.  */
 
 arelent **
-tc_gen_reloc (section, fixp)
-     asection *section;
-     fixS *fixp;
+tc_gen_reloc (asection *section, fixS *fixp)
 {
   static arelent *relocs[3];
   arelent *reloc;
@@ -3297,7 +3615,10 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_32_PCREL_S2:
     case BFD_RELOC_SPARC13:
     case BFD_RELOC_SPARC22:
+    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:
@@ -3313,6 +3634,7 @@ tc_gen_reloc (section, 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:
@@ -3323,8 +3645,37 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_SPARC_UA16:
     case BFD_RELOC_SPARC_UA32:
     case BFD_RELOC_SPARC_UA64:
+    case BFD_RELOC_8_PCREL:
+    case BFD_RELOC_16_PCREL:
+    case BFD_RELOC_32_PCREL:
+    case BFD_RELOC_64_PCREL:
+    case BFD_RELOC_SPARC_PLT32:
+    case BFD_RELOC_SPARC_PLT64:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_SPARC_TLS_GD_HI22:
+    case BFD_RELOC_SPARC_TLS_GD_LO10:
+    case BFD_RELOC_SPARC_TLS_GD_ADD:
+    case BFD_RELOC_SPARC_TLS_GD_CALL:
+    case BFD_RELOC_SPARC_TLS_LDM_HI22:
+    case BFD_RELOC_SPARC_TLS_LDM_LO10:
+    case BFD_RELOC_SPARC_TLS_LDM_ADD:
+    case BFD_RELOC_SPARC_TLS_LDM_CALL:
+    case BFD_RELOC_SPARC_TLS_LDO_HIX22:
+    case BFD_RELOC_SPARC_TLS_LDO_LOX10:
+    case BFD_RELOC_SPARC_TLS_LDO_ADD:
+    case BFD_RELOC_SPARC_TLS_IE_HI22:
+    case BFD_RELOC_SPARC_TLS_IE_LO10:
+    case BFD_RELOC_SPARC_TLS_IE_LD:
+    case BFD_RELOC_SPARC_TLS_IE_LDX:
+    case BFD_RELOC_SPARC_TLS_IE_ADD:
+    case BFD_RELOC_SPARC_TLS_LE_HIX22:
+    case BFD_RELOC_SPARC_TLS_LE_LOX10:
+    case BFD_RELOC_SPARC_TLS_DTPOFF32:
+    case BFD_RELOC_SPARC_TLS_DTPOFF64:
+    case BFD_RELOC_SPARC_GOTDATA_OP_HIX22:
+    case BFD_RELOC_SPARC_GOTDATA_OP_LOX10:
+    case BFD_RELOC_SPARC_GOTDATA_OP:
       code = fixp->fx_r_type;
       break;
     default:
@@ -3340,6 +3691,10 @@ tc_gen_reloc (section, fixp)
 #define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
 #else
 #define GOT_NAME "__GLOBAL_OFFSET_TABLE_"
+#endif
+#ifdef TE_VXWORKS
+#define GOTT_BASE "__GOTT_BASE__"
+#define GOTT_INDEX "__GOTT_INDEX__"
 #endif
 
   /* This code must be parallel to the OBJ_ELF tc_fix_adjustable.  */
@@ -3349,25 +3704,34 @@ tc_gen_reloc (section, fixp)
       switch (code)
        {
        case BFD_RELOC_32_PCREL_S2:
-         if (! S_IS_DEFINED (fixp->fx_addsy)
-             || S_IS_COMMON (fixp->fx_addsy)
-             || S_IS_EXTERNAL (fixp->fx_addsy)
-             || S_IS_WEAK (fixp->fx_addsy))
+         if (generic_force_reloc (fixp))
            code = BFD_RELOC_SPARC_WPLT30;
          break;
        case BFD_RELOC_HI22:
-         if (fixp->fx_addsy != NULL
-             && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
-           code = BFD_RELOC_SPARC_PC22;
-         else
-           code = BFD_RELOC_SPARC_GOT22;
+         code = BFD_RELOC_SPARC_GOT22;
+         if (fixp->fx_addsy != NULL)
+           {
+             if (strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
+               code = BFD_RELOC_SPARC_PC22;
+#ifdef TE_VXWORKS
+             if (strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_BASE) == 0
+                 || strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_INDEX) == 0)
+               code = BFD_RELOC_HI22; /* Unchanged.  */
+#endif
+           }
          break;
        case BFD_RELOC_LO10:
-         if (fixp->fx_addsy != NULL
-             && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
-           code = BFD_RELOC_SPARC_PC10;
-         else
-           code = BFD_RELOC_SPARC_GOT10;
+         code = BFD_RELOC_SPARC_GOT10;
+         if (fixp->fx_addsy != NULL)
+           {
+             if (strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
+               code = BFD_RELOC_SPARC_PC10;
+#ifdef TE_VXWORKS
+             if (strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_BASE) == 0
+                 || strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_INDEX) == 0)
+               code = BFD_RELOC_LO10; /* Unchanged.  */
+#endif
+           }
          break;
        case BFD_RELOC_SPARC13:
          code = BFD_RELOC_SPARC_GOT13;
@@ -3378,6 +3742,16 @@ tc_gen_reloc (section, fixp)
     }
 #endif /* defined (OBJ_ELF) || defined (OBJ_AOUT)  */
 
+  /* Nothing is aligned in DWARF debugging sections.  */
+  if (bfd_get_section_flags (stdoutput, section) & SEC_DEBUGGING)
+    switch (code)
+      {
+      case BFD_RELOC_16: code = BFD_RELOC_SPARC_UA16; break;
+      case BFD_RELOC_32: code = BFD_RELOC_SPARC_UA32; break;
+      case BFD_RELOC_64: code = BFD_RELOC_SPARC_UA64; break;
+      default: break;
+      }
+
   if (code == BFD_RELOC_SPARC_OLO10)
     reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO10);
   else
@@ -3412,9 +3786,14 @@ tc_gen_reloc (section, fixp)
 
 #else /* elf or coff  */
 
-  if (reloc->howto->pc_relative == 0
-      || code == BFD_RELOC_SPARC_PC10
-      || code == BFD_RELOC_SPARC_PC22)
+  if (code != BFD_RELOC_32_PCREL_S2
+      && 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)
     reloc->addend = fixp->fx_addnumber;
   else if (symbol_section_p (fixp->fx_addsy))
     reloc->addend = (section->vma
@@ -3445,8 +3824,7 @@ tc_gen_reloc (section, fixp)
 /* We have no need to default values of symbols.  */
 
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
@@ -3454,9 +3832,7 @@ md_undefined_symbol (name)
 /* Round up a section size to the appropriate boundary.  */
 
 valueT
-md_section_align (segment, size)
-     segT segment ATTRIBUTE_UNUSED;
-     valueT size;
+md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
 {
 #ifndef OBJ_ELF
   /* This is not right for ELF; a.out wants it, and COFF will force
@@ -3479,8 +3855,7 @@ md_section_align (segment, size)
    its size.  This gets us to the following instruction.
    (??? Is this right?  FIXME-SOON)  */
 long
-md_pcrel_from (fixP)
-     fixS *fixP;
+md_pcrel_from (fixS *fixP)
 {
   long ret;
 
@@ -3496,8 +3871,7 @@ md_pcrel_from (fixP)
    of two.  */
 
 static int
-log2 (value)
-     int value;
+mylog2 (int value)
 {
   int shift;
 
@@ -3517,8 +3891,7 @@ static int max_alignment = 15;
 #endif
 
 static void
-s_reserve (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_reserve (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   char *p;
@@ -3598,7 +3971,7 @@ s_reserve (ignore)
 
       if (align != 0)
        {
-         temp = log2 (align);
+         temp = mylog2 (align);
          if (temp < 0)
            {
              as_bad (_("alignment not a power of 2"));
@@ -3654,21 +4027,20 @@ s_reserve (ignore)
     }
   else
     {
-      as_warn ("Ignoring attempt to re-define symbol %s",
+      as_warn (_("Ignoring attempt to re-define symbol %s"),
               S_GET_NAME (symbolP));
-    }                          /* if not redefining.  */
+    }
 
   demand_empty_rest_of_line ();
 }
 
 static void
-s_common (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_common (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   char c;
   char *p;
-  int temp, size;
+  offsetT temp, size;
   symbolS *symbolP;
 
   name = input_line_pointer;
@@ -3689,7 +4061,8 @@ s_common (ignore)
 
   if ((temp = get_absolute_expression ()) < 0)
     {
-      as_bad (_(".COMMon length (%d.) <0! Ignored."), temp);
+      as_bad (_(".COMMon length (%lu) out of range ignored"),
+             (unsigned long) temp);
       ignore_rest_of_line ();
       return;
     }
@@ -3707,8 +4080,8 @@ s_common (ignore)
     {
       if (S_GET_VALUE (symbolP) != (valueT) size)
        {
-         as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."),
-                  S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
+         as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
+                  S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size);
        }
     }
   else
@@ -3735,7 +4108,7 @@ s_common (ignore)
       if (temp > max_alignment)
        {
          temp = max_alignment;
-         as_warn (_("alignment too large; assuming %d"), temp);
+         as_warn (_("alignment too large; assuming %ld"), (long) temp);
        }
 #endif
 
@@ -3751,7 +4124,6 @@ s_common (ignore)
        {
          segT old_sec;
          int old_subsec;
-         char *p;
          int align;
 
          old_sec = now_seg;
@@ -3760,7 +4132,7 @@ s_common (ignore)
          if (temp == 0)
            align = 0;
          else
-           align = log2 (temp);
+           align = mylog2 (temp);
 
          if (align < 0)
            {
@@ -3817,9 +4189,7 @@ s_common (ignore)
       goto allocate_common;
     }
 
-#ifdef BFD_ASSEMBLER
   symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
-#endif
 
   demand_empty_rest_of_line ();
   return;
@@ -3839,12 +4209,11 @@ s_common (ignore)
   }
 }
 
-/* Handle the .empty pseudo-op.  This supresses the warnings about
+/* Handle the .empty pseudo-op.  This suppresses the warnings about
    invalid delay slot usage.  */
 
 static void
-s_empty (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_empty (int ignore ATTRIBUTE_UNUSED)
 {
   /* The easy way to implement is to just forget about the last
      instruction.  */
@@ -3852,8 +4221,7 @@ s_empty (ignore)
 }
 
 static void
-s_seg (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_seg (int ignore ATTRIBUTE_UNUSED)
 {
 
   if (strncmp (input_line_pointer, "\"text\"", 6) == 0)
@@ -3888,15 +4256,14 @@ s_seg (ignore)
 }
 
 static void
-s_data1 ()
+s_data1 (void)
 {
   subseg_set (data_section, 1);
   demand_empty_rest_of_line ();
 }
 
 static void
-s_proc (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_proc (int ignore ATTRIBUTE_UNUSED)
 {
   while (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
@@ -3906,7 +4273,7 @@ s_proc (ignore)
 }
 
 /* This static variable is set by s_uacons to tell sparc_cons_align
-   that the expession does not need to be aligned.  */
+   that the expression does not need to be aligned.  */
 
 static int sparc_no_align_cons = 0;
 
@@ -3915,8 +4282,7 @@ static int sparc_no_align_cons = 0;
    to be aligned.  */
 
 static void
-s_uacons (bytes)
-     int bytes;
+s_uacons (int bytes)
 {
   /* Tell sparc_cons_align not to align this value.  */
   sparc_no_align_cons = 1;
@@ -3929,8 +4295,7 @@ s_uacons (bytes)
    sparc_arch_size 64 it is equivalent to .xword.  */
 
 static void
-s_ncons (bytes)
-     int bytes ATTRIBUTE_UNUSED;
+s_ncons (int bytes ATTRIBUTE_UNUSED)
 {
   cons (sparc_arch_size == 32 ? 4 : 8);
 }
@@ -3944,8 +4309,7 @@ s_ncons (bytes)
 */
 
 static void
-s_register (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_register (int ignore ATTRIBUTE_UNUSED)
 {
   char c;
   int reg;
@@ -4033,7 +4397,7 @@ s_register (ignore)
    symbols which need it.  */
 
 void
-sparc_adjust_symtab ()
+sparc_adjust_symtab (void)
 {
   symbolS *sym;
 
@@ -4064,11 +4428,9 @@ sparc_adjust_symtab ()
    option to check for it.  */
 
 void
-sparc_cons_align (nbytes)
-     int nbytes;
+sparc_cons_align (int nbytes)
 {
   int nalign;
-  char *p;
 
   /* Only do this if we are enforcing aligned data.  */
   if (! enforce_aligned_data)
@@ -4078,11 +4440,11 @@ sparc_cons_align (nbytes)
   if (sparc_no_align_cons)
     return;
 
-  nalign = log2 (nbytes);
+  nalign = mylog2 (nbytes);
   if (nalign == 0)
     return;
 
-  assert (nalign > 0);
+  gas_assert (nalign > 0);
 
   if (now_seg == absolute_section)
     {
@@ -4091,8 +4453,8 @@ sparc_cons_align (nbytes)
       return;
     }
 
-  p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
-               (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
+  frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
+           (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
 
   record_alignment (now_seg, nalign);
 }
@@ -4100,8 +4462,7 @@ sparc_cons_align (nbytes)
 /* This is called from HANDLE_ALIGN in tc-sparc.h.  */
 
 void
-sparc_handle_align (fragp)
-     fragS *fragp;
+sparc_handle_align (fragS *fragp)
 {
   int count, fix;
   char *p;
@@ -4157,7 +4518,7 @@ sparc_handle_align (fragp)
 /* Some special processing for a Sparc ELF file.  */
 
 void
-sparc_elf_final_processing ()
+sparc_elf_final_processing (void)
 {
   /* Set the Sparc ELF flag bits.  FIXME: There should probably be some
      sort of BFD interface for this.  */
@@ -4182,6 +4543,143 @@ sparc_elf_final_processing ()
   else if (current_architecture == SPARC_OPCODE_ARCH_V9B)
     elf_elfheader (stdoutput)->e_flags |= EF_SPARC_SUN_US1|EF_SPARC_SUN_US3;
 }
+
+const char *
+sparc_cons (expressionS *exp, int size)
+{
+  char *save;
+  const char *sparc_cons_special_reloc = NULL;
+
+  SKIP_WHITESPACE ();
+  save = input_line_pointer;
+  if (input_line_pointer[0] == '%'
+      && input_line_pointer[1] == 'r'
+      && input_line_pointer[2] == '_')
+    {
+      if (strncmp (input_line_pointer + 3, "disp", 4) == 0)
+       {
+         input_line_pointer += 7;
+         sparc_cons_special_reloc = "disp";
+       }
+      else if (strncmp (input_line_pointer + 3, "plt", 3) == 0)
+       {
+         if (size != 4 && size != 8)
+           as_bad (_("Illegal operands: %%r_plt in %d-byte data field"), size);
+         else
+           {
+             input_line_pointer += 6;
+             sparc_cons_special_reloc = "plt";
+           }
+       }
+      else if (strncmp (input_line_pointer + 3, "tls_dtpoff", 10) == 0)
+       {
+         if (size != 4 && size != 8)
+           as_bad (_("Illegal operands: %%r_tls_dtpoff in %d-byte data field"), size);
+         else
+           {
+             input_line_pointer += 13;
+             sparc_cons_special_reloc = "tls_dtpoff";
+           }
+       }
+      if (sparc_cons_special_reloc)
+       {
+         int bad = 0;
+
+         switch (size)
+           {
+           case 1:
+             if (*input_line_pointer != '8')
+               bad = 1;
+             input_line_pointer--;
+             break;
+           case 2:
+             if (input_line_pointer[0] != '1' || input_line_pointer[1] != '6')
+               bad = 1;
+             break;
+           case 4:
+             if (input_line_pointer[0] != '3' || input_line_pointer[1] != '2')
+               bad = 1;
+             break;
+           case 8:
+             if (input_line_pointer[0] != '6' || input_line_pointer[1] != '4')
+               bad = 1;
+             break;
+           default:
+             bad = 1;
+             break;
+           }
+
+         if (bad)
+           {
+             as_bad (_("Illegal operands: Only %%r_%s%d allowed in %d-byte data fields"),
+                     sparc_cons_special_reloc, size * 8, size);
+           }
+         else
+           {
+             input_line_pointer += 2;
+             if (*input_line_pointer != '(')
+               {
+                 as_bad (_("Illegal operands: %%r_%s%d requires arguments in ()"),
+                         sparc_cons_special_reloc, size * 8);
+                 bad = 1;
+               }
+           }
+
+         if (bad)
+           {
+             input_line_pointer = save;
+             sparc_cons_special_reloc = NULL;
+           }
+         else
+           {
+             int c;
+             char *end = ++input_line_pointer;
+             int npar = 0;
+
+             while (! is_end_of_line[(c = *end)])
+               {
+                 if (c == '(')
+                   npar++;
+                 else if (c == ')')
+                   {
+                     if (!npar)
+                       break;
+                     npar--;
+                   }
+                 end++;
+               }
+
+             if (c != ')')
+               as_bad (_("Illegal operands: %%r_%s%d requires arguments in ()"),
+                       sparc_cons_special_reloc, size * 8);
+             else
+               {
+                 *end = '\0';
+                 expression (exp);
+                 *end = c;
+                 if (input_line_pointer != end)
+                   {
+                     as_bad (_("Illegal operands: %%r_%s%d requires arguments in ()"),
+                             sparc_cons_special_reloc, size * 8);
+                   }
+                 else
+                   {
+                     input_line_pointer++;
+                     SKIP_WHITESPACE ();
+                     c = *input_line_pointer;
+                     if (! is_end_of_line[c] && c != ',')
+                       as_bad (_("Illegal operands: garbage after %%r_%s%d()"),
+                               sparc_cons_special_reloc, size * 8);
+                   }
+               }
+           }
+       }
+    }
+  if (sparc_cons_special_reloc == NULL)
+    expression (exp);
+  return sparc_cons_special_reloc;
+}
+
 #endif
 
 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
@@ -4189,11 +4687,11 @@ sparc_elf_final_processing ()
    we want to handle little endian relocs specially.  */
 
 void
-cons_fix_new_sparc (frag, where, nbytes, exp)
-     fragS *frag;
-     int where;
-     unsigned int nbytes;
-     expressionS *exp;
+cons_fix_new_sparc (fragS *frag,
+                   int where,
+                   unsigned int nbytes,
+                   expressionS *exp,
+                   const char *sparc_cons_special_reloc)
 {
   bfd_reloc_code_real_type r;
 
@@ -4206,7 +4704,31 @@ cons_fix_new_sparc (frag, where, nbytes, exp)
       && now_seg->flags & SEC_ALLOC)
     r = BFD_RELOC_SPARC_REV32;
 
-  if (sparc_no_align_cons)
+  if (sparc_cons_special_reloc)
+    {
+      if (*sparc_cons_special_reloc == 'd')
+       switch (nbytes)
+         {
+         case 1: r = BFD_RELOC_8_PCREL; break;
+         case 2: r = BFD_RELOC_16_PCREL; break;
+         case 4: r = BFD_RELOC_32_PCREL; break;
+         case 8: r = BFD_RELOC_64_PCREL; break;
+         default: abort ();
+         }
+      else if (*sparc_cons_special_reloc == 'p')
+       switch (nbytes)
+         {
+         case 4: r = BFD_RELOC_SPARC_PLT32; break;
+         case 8: r = BFD_RELOC_SPARC_PLT64; break;
+         }
+      else
+       switch (nbytes)
+         {
+         case 4: r = BFD_RELOC_SPARC_TLS_DTPOFF32; break;
+         case 8: r = BFD_RELOC_SPARC_TLS_DTPOFF64; break;
+         }
+    }
+  else if (sparc_no_align_cons)
     {
       switch (nbytes)
        {
@@ -4220,15 +4742,58 @@ cons_fix_new_sparc (frag, where, nbytes, exp)
   fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
 }
 
-#ifdef OBJ_ELF
+void
+sparc_cfi_frame_initial_instructions (void)
+{
+  cfi_add_CFA_def_cfa (14, sparc_arch_size == 64 ? 0x7ff : 0);
+}
+
 int
-elf32_sparc_force_relocation (fixp)
-     struct fix *fixp;
+sparc_regname_to_dw2regnum (char *regname)
 {
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    return 1;
+  char *p, *q;
 
-  return 0;
+  if (!regname[0])
+    return -1;
+
+  q = "goli";
+  p = strchr (q, regname[0]);
+  if (p)
+    {
+      if (regname[1] < '0' || regname[1] > '8' || regname[2])
+       return -1;
+      return (p - q) * 8 + regname[1] - '0';
+    }
+  if (regname[0] == 's' && regname[1] == 'p' && !regname[2])
+    return 14;
+  if (regname[0] == 'f' && regname[1] == 'p' && !regname[2])
+    return 30;
+  if (regname[0] == 'f' || regname[0] == 'r')
+    {
+      unsigned int regnum;
+
+      regnum = strtoul (regname + 1, &q, 10);
+      if (p == q || *q)
+        return -1;
+      if (regnum >= ((regname[0] == 'f'
+                     && SPARC_OPCODE_ARCH_V9_P (max_architecture))
+                    ? 64 : 32))
+       return -1;
+      if (regname[0] == 'f')
+       {
+          regnum += 32;
+          if (regnum >= 64 && (regnum & 1))
+           return -1;
+        }
+      return regnum;
+    }
+  return -1;
+}
+
+void
+sparc_cfi_emit_pcrel_expr (expressionS *exp, unsigned int nbytes)
+{
+  sparc_no_align_cons = 1;
+  emit_expr_with_reloc (exp, nbytes, "disp");
+  sparc_no_align_cons = 0;
 }
-#endif
This page took 0.069257 seconds and 4 git commands to generate.