]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-riscv.c
RISC-V: Support riscv bitmanip frozen ZBA/ZBB/ZBC instructions (v0.93).
[thirdparty/binutils-gdb.git] / gas / config / tc-riscv.c
index ddd4d1457f5d324b4f8f274baa3f6e99183ae9b6..052199ea7404f5a8d88e6a68c2529d501b2df3d9 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-riscv.c -- RISC-V assembler
-   Copyright (C) 2011-2020 Free Software Foundation, Inc.
+   Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
    Contributed by Andrew Waterman (andrew@sifive.com).
    Based on MIPS target.
@@ -63,17 +63,119 @@ struct riscv_cl_insn
 #define DEFAULT_RISCV_ATTR 0
 #endif
 
+/* Let riscv_after_parse_args set the default value according to xlen.  */
+
+#ifndef DEFAULT_RISCV_ARCH_WITH_EXT
+#define DEFAULT_RISCV_ARCH_WITH_EXT NULL
+#endif
+
+/* The default ISA spec is set to 2.2 rather than the lastest version.
+   The reason is that compiler generates the ISA string with fixed 2p0
+   verisons only for the RISCV ELF architecture attributes, but not for
+   the -march option.  Therefore, we should update the compiler or linker
+   to resolve this problem.  */
+
+#ifndef DEFAULT_RISCV_ISA_SPEC
+#define DEFAULT_RISCV_ISA_SPEC "2.2"
+#endif
+
+#ifndef DEFAULT_RISCV_PRIV_SPEC
+#define DEFAULT_RISCV_PRIV_SPEC "1.11"
+#endif
+
 static const char default_arch[] = DEFAULT_ARCH;
+static const char *default_arch_with_ext = DEFAULT_RISCV_ARCH_WITH_EXT;
+static enum riscv_isa_spec_class default_isa_spec = ISA_SPEC_CLASS_NONE;
+static enum riscv_priv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
 
 static unsigned xlen = 0; /* width of an x-register */
 static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
 static bfd_boolean rve_abi = FALSE;
+enum float_abi {
+  FLOAT_ABI_DEFAULT = -1,
+  FLOAT_ABI_SOFT,
+  FLOAT_ABI_SINGLE,
+  FLOAT_ABI_DOUBLE,
+  FLOAT_ABI_QUAD
+};
+static enum float_abi float_abi = FLOAT_ABI_DEFAULT;
 
 #define LOAD_ADDRESS_INSN (abi_xlen == 64 ? "ld" : "lw")
 #define ADD32_INSN (xlen == 64 ? "addiw" : "addi")
 
 static unsigned elf_flags = 0;
 
+/* Set the default_isa_spec.  Return 0 if the input spec string isn't
+   supported.  Otherwise, return 1.  */
+
+static int
+riscv_set_default_isa_spec (const char *s)
+{
+  enum riscv_isa_spec_class class;
+  if (!riscv_get_isa_spec_class (s, &class))
+    {
+      as_bad ("Unknown default ISA spec `%s' set by "
+             "-misa-spec or --with-isa-spec", s);
+      return 0;
+    }
+  else
+    default_isa_spec = class;
+  return 1;
+}
+
+/* Set the default_priv_spec, assembler will find the suitable CSR address
+   according to default_priv_spec.  We will try to check priv attributes if
+   the input string is NULL.  Return 0 if the input priv spec string isn't
+   supported.  Otherwise, return 1.  */
+
+static int
+riscv_set_default_priv_spec (const char *s)
+{
+  enum riscv_priv_spec_class class;
+  unsigned major, minor, revision;
+  obj_attribute *attr;
+
+  /* Find the corresponding priv spec class.  */
+  if (riscv_get_priv_spec_class (s, &class))
+    {
+      default_priv_spec = class;
+      return 1;
+    }
+
+  if (s != NULL)
+    {
+      as_bad (_("Unknown default privilege spec `%s' set by "
+               "-mpriv-spec or --with-priv-spec"), s);
+      return 0;
+    }
+
+  /* Try to set the default_priv_spec according to the priv attributes.  */
+  attr = elf_known_obj_attributes_proc (stdoutput);
+  major = (unsigned) attr[Tag_RISCV_priv_spec].i;
+  minor = (unsigned) attr[Tag_RISCV_priv_spec_minor].i;
+  revision = (unsigned) attr[Tag_RISCV_priv_spec_revision].i;
+
+  if (riscv_get_priv_spec_class_from_numbers (major,
+                                             minor,
+                                             revision,
+                                             &class))
+    {
+      /* The priv attributes setting 0.0.0 is meaningless.  We should have set
+        the default_priv_spec by md_parse_option and riscv_after_parse_args,
+        so just skip the following setting.  */
+      if (class == PRIV_SPEC_CLASS_NONE)
+       return 1;
+
+      default_priv_spec = class;
+      return 1;
+    }
+
+  /* Still can not find the priv spec class.  */
+  as_bad (_("Unknown default privilege spec `%d.%d.%d' set by "
+           "privilege attributes"),  major, minor, revision);
+  return 0;
+}
+
 /* This is the set of options which the .option pseudo-op may modify.  */
 
 struct riscv_set_options
@@ -116,10 +218,12 @@ static riscv_subset_list_t riscv_subsets;
 static bfd_boolean
 riscv_subset_supports (const char *feature)
 {
+  struct riscv_subset_t *subset;
+
   if (riscv_opts.rvc && (strcasecmp (feature, "c") == 0))
     return TRUE;
 
-  return riscv_lookup_subset (&riscv_subsets, feature) != NULL;
+  return riscv_lookup_subset (&riscv_subsets, feature, &subset);
 }
 
 static bfd_boolean
@@ -133,13 +237,29 @@ riscv_multi_subset_supports (enum riscv_insn_class insn_class)
     case INSN_CLASS_M: return riscv_subset_supports ("m");
     case INSN_CLASS_F: return riscv_subset_supports ("f");
     case INSN_CLASS_D: return riscv_subset_supports ("d");
-    case INSN_CLASS_D_AND_C:
-      return riscv_subset_supports ("d") && riscv_subset_supports ("c");
+    case INSN_CLASS_Q: return riscv_subset_supports ("q");
 
     case INSN_CLASS_F_AND_C:
-      return riscv_subset_supports ("f") && riscv_subset_supports ("c");
-
-    case INSN_CLASS_Q: return riscv_subset_supports ("q");
+      return (riscv_subset_supports ("f")
+             && riscv_subset_supports ("c"));
+    case INSN_CLASS_D_AND_C:
+      return (riscv_subset_supports ("d")
+             && riscv_subset_supports ("c"));
+
+    case INSN_CLASS_ZICSR:
+      return riscv_subset_supports ("zicsr");
+    case INSN_CLASS_ZIFENCEI:
+      return riscv_subset_supports ("zifencei");
+
+    case INSN_CLASS_ZBA:
+      return riscv_subset_supports ("zba");
+    case INSN_CLASS_ZBB:
+      return riscv_subset_supports ("zbb");
+    case INSN_CLASS_ZBC:
+      return riscv_subset_supports ("zbc");
+    case INSN_CLASS_ZBA_OR_ZBB:
+      return (riscv_subset_supports ("zba")
+             || riscv_subset_supports ("zbb"));
 
     default:
       as_fatal ("Unreachable");
@@ -147,6 +267,56 @@ riscv_multi_subset_supports (enum riscv_insn_class insn_class)
     }
 }
 
+/* Handle of the extension with version hash table.  */
+static htab_t ext_version_hash = NULL;
+
+static htab_t
+init_ext_version_hash (const struct riscv_ext_version *table)
+{
+  int i = 0;
+  htab_t hash = str_htab_create ();
+
+  while (table[i].name)
+    {
+      const char *name = table[i].name;
+      if (str_hash_insert (hash, name, &table[i], 0) != NULL)
+       as_fatal (_("duplicate %s"), name);
+
+      i++;
+      while (table[i].name
+            && strcmp (table[i].name, name) == 0)
+       i++;
+    }
+
+  return hash;
+}
+
+static void
+riscv_get_default_ext_version (const char *name,
+                              int *major_version,
+                              int *minor_version)
+{
+  struct riscv_ext_version *ext;
+
+  if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
+    return;
+
+  ext = (struct riscv_ext_version *) str_hash_find (ext_version_hash, name);
+  while (ext
+        && ext->name
+        && strcmp (ext->name, name) == 0)
+    {
+      if (ext->isa_spec_class == ISA_SPEC_CLASS_DRAFT
+         || ext->isa_spec_class == default_isa_spec)
+       {
+         *major_version = ext->major_version;
+         *minor_version = ext->minor_version;
+         return;
+       }
+      ext++;
+    }
+}
+
 /* Set which ISA and extensions are available.  */
 
 static void
@@ -154,18 +324,66 @@ riscv_set_arch (const char *s)
 {
   riscv_parse_subset_t rps;
   rps.subset_list = &riscv_subsets;
-  rps.error_handler = as_fatal;
+  rps.error_handler = as_bad;
   rps.xlen = &xlen;
+  rps.get_default_version = riscv_get_default_ext_version;
+
+  if (s == NULL)
+    return;
 
   riscv_release_subset_list (&riscv_subsets);
   riscv_parse_subset (&rps, s);
 }
 
+/* Indicate -mabi= option is explictly set.  */
+static bfd_boolean explicit_mabi = FALSE;
+
+static void
+riscv_set_abi (unsigned new_xlen, enum float_abi new_float_abi, bfd_boolean rve)
+{
+  abi_xlen = new_xlen;
+  float_abi = new_float_abi;
+  rve_abi = rve;
+}
+
+/* If the -mabi option isn't set, then we set the abi according to the arch
+   string.  Otherwise, check if there are conflicts between architecture
+   and abi setting.  */
+
+static void
+riscv_set_abi_by_arch (void)
+{
+  if (!explicit_mabi)
+    {
+      if (riscv_subset_supports ("q"))
+       riscv_set_abi (xlen, FLOAT_ABI_QUAD, FALSE);
+      else if (riscv_subset_supports ("d"))
+       riscv_set_abi (xlen, FLOAT_ABI_DOUBLE, FALSE);
+      else
+       riscv_set_abi (xlen, FLOAT_ABI_SOFT, FALSE);
+    }
+  else
+    {
+      gas_assert (abi_xlen != 0 && xlen != 0 && float_abi != FLOAT_ABI_DEFAULT);
+      if (abi_xlen > xlen)
+       as_bad ("can't have %d-bit ABI on %d-bit ISA", abi_xlen, xlen);
+      else if (abi_xlen < xlen)
+       as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen);
+    }
+
+  /* Update the EF_RISCV_FLOAT_ABI field of elf_flags.  */
+  elf_flags &= ~EF_RISCV_FLOAT_ABI;
+  elf_flags |= float_abi << 1;
+
+  if (rve_abi)
+    elf_flags |= EF_RISCV_RVE;
+}
+
 /* Handle of the OPCODE hash table.  */
-static struct hash_control *op_hash = NULL;
+static htab_t op_hash = NULL;
 
 /* Handle of the type of .insn hash table.  */
-static struct hash_control *insn_type_hash = NULL;
+static htab_t insn_type_hash = NULL;
 
 /* This array holds the chars that always start a comment.  If the
     pre-processor is disabled, these aren't very useful */
@@ -194,8 +412,11 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 /* Indicate we are already assemble any instructions or not.  */
 static bfd_boolean start_assemble = FALSE;
 
-/* Indicate arch attribute is explictly set.  */
-static bfd_boolean explicit_arch_attr = FALSE;
+/* Indicate ELF attributes are explicitly set.  */
+static bfd_boolean explicit_attr = FALSE;
+
+/* Indicate CSR or priv instructions are explicitly used.  */
+static bfd_boolean explicit_priv_attr = FALSE;
 
 /* Macros for encoding relaxation state for RVC branches and far jumps.  */
 #define RELAX_BRANCH_ENCODE(uncond, rvc, length)       \
@@ -235,7 +456,10 @@ static char *expr_end;
 const char *
 riscv_target_format (void)
 {
-  return xlen == 64 ? "elf64-littleriscv" : "elf32-littleriscv";
+  if (target_big_endian)
+    return xlen == 64 ? "elf64-bigriscv" : "elf32-bigriscv";
+  else
+    return xlen == 64 ? "elf64-littleriscv" : "elf32-littleriscv";
 }
 
 /* Return the length of instruction INSN.  */
@@ -264,7 +488,7 @@ static void
 install_insn (const struct riscv_cl_insn *insn)
 {
   char *f = insn->frag->fr_literal + insn->where;
-  md_number_to_chars (f, insn->insn_opcode, insn_length (insn));
+  number_to_chars_littleendian (f, insn->insn_opcode, insn_length (insn));
 }
 
 /* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly
@@ -397,23 +621,17 @@ static const struct opcode_name_t opcode_name_list[] =
 };
 
 /* Hash table for lookup opcode name.  */
-static struct hash_control *opcode_names_hash = NULL;
+static htab_t opcode_names_hash = NULL;
 
 /* Initialization for hash table of opcode name.  */
 static void
 init_opcode_names_hash (void)
 {
-  const char *retval;
   const struct opcode_name_t *opcode;
 
   for (opcode = &opcode_name_list[0]; opcode->name != NULL; ++opcode)
-    {
-      retval = hash_insert (opcode_names_hash, opcode->name, (void *)opcode);
-
-      if (retval != NULL)
-       as_fatal (_("internal error: can't hash `%s': %s"),
-                 opcode->name, retval);
-    }
+    if (str_hash_insert (opcode_names_hash, opcode->name, opcode, 0) != NULL)
+      as_fatal (_("duplicate %s"), opcode->name);
 }
 
 /* Find `s` is a valid opcode name or not,
@@ -436,7 +654,7 @@ opcode_name_lookup (char **s)
   save_c = *e;
   *e = '\0';
 
-  o = (struct opcode_name_t *) hash_find (opcode_names_hash, *s);
+  o = (struct opcode_name_t *) str_hash_find (opcode_names_hash, *s);
 
   /* Advance to next token if one was recognized.  */
   if (o)
@@ -452,12 +670,13 @@ enum reg_class
 {
   RCLASS_GPR,
   RCLASS_FPR,
-  RCLASS_CSR,
-  RCLASS_MAX
+  RCLASS_MAX,
+
+  RCLASS_CSR
 };
 
-static struct hash_control *reg_names_hash = NULL;
-static struct hash_control *csr_extra_hash = NULL;
+static htab_t reg_names_hash = NULL;
+static htab_t csr_extra_hash = NULL;
 
 #define ENCODE_REG_HASH(cls, n) \
   ((void *)(uintptr_t)((n) * RCLASS_MAX + (cls) + 1))
@@ -468,10 +687,8 @@ static void
 hash_reg_name (enum reg_class class, const char *name, unsigned n)
 {
   void *hash = ENCODE_REG_HASH (class, n);
-  const char *retval = hash_insert (reg_names_hash, name, hash);
-
-  if (retval != NULL)
-    as_fatal (_("internal error: can't hash `%s': %s"), name, retval);
+  if (str_hash_insert (reg_names_hash, name, hash, 0) != NULL)
+    as_fatal (_("duplicate %s"), name);
 }
 
 static void
@@ -483,102 +700,151 @@ hash_reg_names (enum reg_class class, const char * const names[], unsigned n)
     hash_reg_name (class, names[i], i);
 }
 
-/* All RISC-V CSRs belong to one of these classes.  */
-
-enum riscv_csr_class
-{
-  CSR_CLASS_NONE,
-
-  CSR_CLASS_I,
-  CSR_CLASS_I_32,      /* rv32 only */
-  CSR_CLASS_F,         /* f-ext only */
-};
-
-/* This structure holds all restricted conditions for a CSR.  */
-
-struct riscv_csr_extra
-{
-  /* Class to which this CSR belongs.  Used to decide whether or
-     not this CSR is legal in the current -march context.  */
-  enum riscv_csr_class csr_class;
-};
-
-/* Init two hashes, csr_extra_hash and reg_names_hash, for CSR.  */
-
+/* Init hash table csr_extra_hash to handle CSR.  */
 static void
-riscv_init_csr_hashes (const char *name,
-                      unsigned address,
-                      enum riscv_csr_class class)
-{
-  struct riscv_csr_extra *entry = XNEW (struct riscv_csr_extra);
-  entry->csr_class = class;
-
-  const char *hash_error =
-    hash_insert (csr_extra_hash, name, (void *) entry);
-  if (hash_error != NULL)
+riscv_init_csr_hash (const char *name,
+                    unsigned address,
+                    enum riscv_csr_class class,
+                    enum riscv_priv_spec_class define_version,
+                    enum riscv_priv_spec_class abort_version)
+{
+  struct riscv_csr_extra *entry, *pre_entry;
+  bfd_boolean need_enrty = TRUE;
+
+  pre_entry = NULL;
+  entry = (struct riscv_csr_extra *) str_hash_find (csr_extra_hash, name);
+  while (need_enrty && entry != NULL)
     {
-      fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
-                     name, hash_error);
-      /* Probably a memory allocation problem?  Give up now.  */
-       as_fatal (_("Broken assembler.  No assembly attempted."));
+      if (entry->csr_class == class
+         && entry->address == address
+         && entry->define_version == define_version
+         && entry->abort_version == abort_version)
+       need_enrty = FALSE;
+      pre_entry = entry;
+      entry = entry->next;
     }
+  /* Duplicate setting for the CSR, just return and do nothing.  */
+  if (!need_enrty)
+    return;
 
-  hash_reg_name (RCLASS_CSR, name, address);
+  entry = XNEW (struct riscv_csr_extra);
+  entry->csr_class = class;
+  entry->address = address;
+  entry->define_version = define_version;
+  entry->abort_version = abort_version;
+  entry->next = NULL;
+
+  /* If the CSR hasn't been inserted in the hash table, then insert it.
+     Otherwise, attach the extra information to the entry which is already
+     in the hash table.  */
+  if (pre_entry == NULL)
+    str_hash_insert (csr_extra_hash, name, entry, 0);
+  else
+    pre_entry->next = entry;
 }
 
-/* Check wether the CSR is valid according to the ISA.  */
+/* Return the suitable CSR address after checking the ISA dependency and
+   priv spec versions.  */
 
-static bfd_boolean
-riscv_csr_class_check (enum riscv_csr_class csr_class)
+static unsigned int
+riscv_csr_address (const char *csr_name,
+                  struct riscv_csr_extra *entry)
 {
+  struct riscv_csr_extra *saved_entry = entry;
+  enum riscv_csr_class csr_class = entry->csr_class;
+  bfd_boolean need_check_version = TRUE;
+  bfd_boolean result = TRUE;
+
   switch (csr_class)
     {
-    case CSR_CLASS_I: return riscv_subset_supports ("i");
-    case CSR_CLASS_F: return riscv_subset_supports ("f");
+    case CSR_CLASS_I:
+      result = riscv_subset_supports ("i");
+      break;
     case CSR_CLASS_I_32:
-      return (xlen == 32 && riscv_subset_supports ("i"));
-
+      result = (xlen == 32 && riscv_subset_supports ("i"));
+      break;
+    case CSR_CLASS_F:
+      result = riscv_subset_supports ("f");
+      need_check_version = FALSE;
+      break;
+    case CSR_CLASS_DEBUG:
+      need_check_version = FALSE;
+      break;
     default:
-      return FALSE;
+      as_bad (_("internal: bad RISC-V CSR class (0x%x)"), csr_class);
+    }
+
+  /* Don't report the ISA conflict when -mcsr-check isn't set.  */
+  if (riscv_opts.csr_check && !result)
+    as_warn (_("Invalid CSR `%s' for the current ISA"), csr_name);
+
+  while (entry != NULL)
+    {
+      if (!need_check_version
+         || (default_priv_spec >= entry->define_version
+             && default_priv_spec < entry->abort_version))
+       {
+         /* Find the suitable CSR according to the specific version.  */
+         return entry->address;
+       }
+      entry = entry->next;
+    }
+
+  /* We can not find the suitable CSR address according to the privilege
+     version.  Therefore, we use the last defined value.  Report the warning
+     only when the -mcsr-check is set.  Enable the -mcsr-check is recommended,
+     otherwise, you may get the unexpected CSR address.  */
+  if (riscv_opts.csr_check)
+    {
+      const char *priv_name = riscv_get_priv_spec_name (default_priv_spec);
+
+      if (priv_name != NULL)
+       as_warn (_("Invalid CSR `%s' for the privilege spec `%s'"),
+                csr_name, priv_name);
     }
+
+  return saved_entry->address;
 }
 
-/* If the CSR is defined, then we call `riscv_csr_class_check` to do the
-   further checking.  Return FALSE if the CSR is not defined.  Otherwise,
-   return TRUE.  */
+/* Once the CSR is defined, including the old privilege spec, then we call
+   riscv_csr_class_check and riscv_csr_version_check to do the further checking
+   and get the corresponding address.  Return -1 if the CSR is never been
+   defined.  Otherwise, return the address.  */
 
-static bfd_boolean
+static unsigned int
 reg_csr_lookup_internal (const char *s)
 {
   struct riscv_csr_extra *r =
-    (struct riscv_csr_extra *) hash_find (csr_extra_hash, s);
+    (struct riscv_csr_extra *) str_hash_find (csr_extra_hash, s);
 
   if (r == NULL)
-    return FALSE;
-
-  /* We just report the warning when the CSR is invalid.  */
-  if (!riscv_csr_class_check (r->csr_class))
-    as_warn (_("Invalid CSR `%s' for the current ISA"), s);
+    return -1U;
 
-  return TRUE;
+  /* We just report the warning when the CSR is invalid.  "Invalid CSR" means
+     the CSR was defined, but isn't allowed for the current ISA setting or
+     the privilege spec.  If the CSR is never been defined, then assembler
+     will regard it as a "Unknown CSR" and report error.  If user use number
+     to set the CSR, but over the range (> 0xfff), then assembler will report
+     "Improper CSR" error for it.  */
+  return riscv_csr_address (s, r);
 }
 
 static unsigned int
 reg_lookup_internal (const char *s, enum reg_class class)
 {
-  void *r = hash_find (reg_names_hash, s);
+  void *r;
+
+  if (class == RCLASS_CSR)
+    return reg_csr_lookup_internal (s);
 
+  r = str_hash_find (reg_names_hash, s);
   if (r == NULL || DECODE_REG_CLASS (r) != class)
     return -1;
 
   if (riscv_opts.rve && class == RCLASS_GPR && DECODE_REG_NUM (r) > 15)
     return -1;
 
-  if (class == RCLASS_CSR
-      && riscv_opts.csr_check
-      && !reg_csr_lookup_internal (s))
-    return -1;
-
   return DECODE_REG_NUM (r);
 }
 
@@ -796,26 +1062,18 @@ struct percent_op_match
 
 /* Common hash table initialization function for
    instruction and .insn directive.  */
-static struct hash_control *
+static htab_t
 init_opcode_hash (const struct riscv_opcode *opcodes,
                  bfd_boolean insn_directive_p)
 {
   int i = 0;
   int length;
-  struct hash_control *hash = hash_new ();
+  htab_t hash = str_htab_create ();
   while (opcodes[i].name)
     {
       const char *name = opcodes[i].name;
-      const char *hash_error =
-       hash_insert (hash, name, (void *) &opcodes[i]);
-
-      if (hash_error != NULL)
-       {
-         fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
-                  opcodes[i].name, hash_error);
-         /* Probably a memory allocation problem?  Give up now.  */
-         as_fatal (_("Broken assembler.  No assembly attempted."));
-       }
+      if (str_hash_insert (hash, name, &opcodes[i], 0) != NULL)
+       as_fatal (_("duplicate %s"), name);
 
       do
        {
@@ -852,7 +1110,7 @@ md_begin (void)
   op_hash = init_opcode_hash (riscv_opcodes, FALSE);
   insn_type_hash = init_opcode_hash (riscv_insn_types, TRUE);
 
-  reg_names_hash = hash_new ();
+  reg_names_hash = str_htab_create ();
   hash_reg_names (RCLASS_GPR, riscv_gpr_names_numeric, NGPR);
   hash_reg_names (RCLASS_GPR, riscv_gpr_names_abi, NGPR);
   hash_reg_names (RCLASS_FPR, riscv_fpr_names_numeric, NFPR);
@@ -861,13 +1119,15 @@ md_begin (void)
   hash_reg_name (RCLASS_GPR, "fp", 8);
 
   /* Create and insert CSR hash tables.  */
-  csr_extra_hash = hash_new ();
-#define DECLARE_CSR(name, num, class) riscv_init_csr_hashes (#name, num, class);
-#define DECLARE_CSR_ALIAS(name, num, class) DECLARE_CSR(name, num, class);
+  csr_extra_hash = str_htab_create ();
+#define DECLARE_CSR(name, num, class, define_version, abort_version) \
+  riscv_init_csr_hash (#name, num, class, define_version, abort_version);
+#define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \
+  DECLARE_CSR(name, num, class, define_version, abort_version);
 #include "opcode/riscv-opc.h"
 #undef DECLARE_CSR
 
-  opcode_names_hash = hash_new ();
+  opcode_names_hash = str_htab_create ();
   init_opcode_names_hash ();
 
   /* Set the default alignment for the text section.  */
@@ -917,6 +1177,13 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
          int j = reloc_type == BFD_RELOC_RISCV_JMP;
          int best_case = riscv_insn_length (ip->insn_opcode);
          unsigned worst_case = relaxed_branch_length (NULL, NULL, 0);
+
+         if (now_seg == absolute_section)
+           {
+             as_bad (_("relaxable branches not supported in absolute section"));
+             return;
+           }
+
          add_relaxed_insn (ip, worst_case, best_case,
                            RELAX_BRANCH_ENCODE (j, best_case == 2, worst_case),
                            address_expr->X_add_symbol,
@@ -944,9 +1211,7 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
      optimized away or compressed by the linker during relaxation, to prevent
      the assembler from computing static offsets across such an instruction.
      This is necessary to get correct EH info.  */
-  if (reloc_type == BFD_RELOC_RISCV_CALL
-      || reloc_type == BFD_RELOC_RISCV_CALL_PLT
-      || reloc_type == BFD_RELOC_RISCV_HI20
+  if (reloc_type == BFD_RELOC_RISCV_HI20
       || reloc_type == BFD_RELOC_RISCV_PCREL_HI20
       || reloc_type == BFD_RELOC_RISCV_TPREL_HI20
       || reloc_type == BFD_RELOC_RISCV_TPREL_ADD)
@@ -972,7 +1237,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
   va_start (args, fmt);
 
   r = BFD_RELOC_UNUSED;
-  mo = (struct riscv_opcode *) hash_find (op_hash, name);
+  mo = (struct riscv_opcode *) str_hash_find (op_hash, name);
   gas_assert (mo);
 
   /* Find a non-RVC variant of the instruction.  append_insn will compress
@@ -1081,8 +1346,8 @@ check_absolute_expr (struct riscv_cl_insn *ip, expressionS *ex,
 static symbolS *
 make_internal_label (void)
 {
-  return (symbolS *) local_symbol_make (FAKE_LABEL_NAME, now_seg,
-                                       (valueT) frag_now_fix (), frag_now);
+  return (symbolS *) local_symbol_make (FAKE_LABEL_NAME, now_seg, frag_now,
+                                       frag_now_fix ());
 }
 
 /* Load an entry from the GOT.  */
@@ -1122,8 +1387,13 @@ static void
 riscv_call (int destreg, int tempreg, expressionS *ep,
            bfd_reloc_code_real_type reloc)
 {
+  /* Ensure the jalr is emitted to the same frag as the auipc.  */
+  frag_grow (8);
   macro_build (ep, "auipc", "d,u", tempreg, reloc);
   macro_build (NULL, "jalr", "d,s", destreg, tempreg);
+  /* See comment at end of append_insn.  */
+  frag_wane (frag_now);
+  frag_new (0);
 }
 
 /* Load an integer constant into a register.  */
@@ -1177,7 +1447,25 @@ load_const (int reg, expressionS *ep)
     }
 }
 
+/* Zero extend and sign extend byte/half-word/word.  */
+
+static void
+riscv_ext (int destreg, int srcreg, unsigned shift, bfd_boolean sign)
+{
+  if (sign)
+    {
+      md_assemblef ("slli x%d, x%d, 0x%x", destreg, srcreg, shift);
+      md_assemblef ("srai x%d, x%d, 0x%x", destreg, destreg, shift);
+    }
+  else
+    {
+      md_assemblef ("slli x%d, x%d, 0x%x", destreg, srcreg, shift);
+      md_assemblef ("srli x%d, x%d, 0x%x", destreg, destreg, shift);
+    }
+}
+
 /* Expand RISC-V assembly macros into one or more instructions.  */
+
 static void
 macro (struct riscv_cl_insn *ip, expressionS *imm_expr,
        bfd_reloc_code_real_type *imm_reloc)
@@ -1298,6 +1586,22 @@ macro (struct riscv_cl_insn *ip, expressionS *imm_expr,
       riscv_call (rd, rs1, imm_expr, *imm_reloc);
       break;
 
+    case M_ZEXTH:
+      riscv_ext (rd, rs1, xlen - 16, FALSE);
+      break;
+
+    case M_ZEXTW:
+      riscv_ext (rd, rs1, xlen - 32, FALSE);
+      break;
+
+    case M_SEXTB:
+      riscv_ext (rd, rs1, xlen - 8, TRUE);
+      break;
+
+    case M_SEXTH:
+      riscv_ext (rd, rs1, xlen - 16, TRUE);
+      break;
+
     default:
       as_bad (_("Macro %s not implemented"), ip->insn_mo->name);
       break;
@@ -1308,6 +1612,7 @@ static const struct percent_op_match percent_op_utype[] =
 {
   {"%tprel_hi", BFD_RELOC_RISCV_TPREL_HI20},
   {"%pcrel_hi", BFD_RELOC_RISCV_PCREL_HI20},
+  {"%got_pcrel_hi", BFD_RELOC_RISCV_GOT_HI20},
   {"%tls_ie_pcrel_hi", BFD_RELOC_RISCV_TLS_GOT_HI20},
   {"%tls_gd_pcrel_hi", BFD_RELOC_RISCV_TLS_GD_HI20},
   {"%hi", BFD_RELOC_RISCV_HI20},
@@ -1536,13 +1841,42 @@ riscv_csr_read_only_check (insn_t insn)
   return TRUE;
 }
 
+/* Return True if it is a privileged instruction.  Otherwise, return FALSE.
+
+   uret is actually a N-ext instruction.  So it is better to regard it as
+   an user instruction rather than the priv instruction.
+
+   hret is used to return from traps in H-mode.  H-mode is removed since
+   the v1.10 priv spec, but probably be added in the new hypervisor spec.
+   Therefore, hret should be controlled by the hypervisor spec rather than
+   priv spec in the future.
+
+   dret is defined in the debug spec, so it should be checked in the future,
+   too.  */
+
+static bfd_boolean
+riscv_is_priv_insn (insn_t insn)
+{
+  return (((insn ^ MATCH_SRET) & MASK_SRET) == 0
+         || ((insn ^ MATCH_MRET) & MASK_MRET) == 0
+         || ((insn ^ MATCH_SFENCE_VMA) & MASK_SFENCE_VMA) == 0
+         || ((insn ^ MATCH_WFI) & MASK_WFI) == 0
+  /* The sfence.vm is dropped in the v1.10 priv specs, but we still need to
+     check it here to keep the compatible.  Maybe we should issue warning
+     if sfence.vm is used, but the priv spec newer than v1.10 is chosen.
+     We already have a similar check for CSR, but not yet for instructions.
+     It would be good if we could check the spec versions both for CSR and
+     instructions, but not here.  */
+         || ((insn ^ MATCH_SFENCE_VM) & MASK_SFENCE_VM) == 0);
+}
+
 /* This routine assembles an instruction into its binary format.  As a
    side effect, it sets the global variable imm_reloc to the type of
    relocation to do if one of the operands is an address expression.  */
 
 static const char *
 riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
-         bfd_reloc_code_real_type *imm_reloc, struct hash_control *hash)
+         bfd_reloc_code_real_type *imm_reloc, htab_t hash)
 {
   char *s;
   const char *args;
@@ -1558,7 +1892,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
   bfd_boolean insn_with_csr = FALSE;
 
   /* Parse the name of the instruction.  Terminate the string if whitespace
-     is found so that hash_find only sees the name part of the string.  */
+     is found so that str_hash_find only sees the name part of the string.  */
   for (s = str; *s != '\0'; ++s)
     if (ISSPACE (*s))
       {
@@ -1567,7 +1901,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
        break;
       }
 
-  insn = (struct riscv_opcode *) hash_find (hash, str);
+  insn = (struct riscv_opcode *) str_hash_find (hash, str);
 
   argsStart = s;
   for ( ; insn && insn->name && strcmp (insn->name, str) == 0; insn++)
@@ -1603,6 +1937,9 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                      && !riscv_opts.rvc)
                    break;
 
+                 if (riscv_is_priv_insn (ip->insn_opcode))
+                   explicit_priv_attr = TRUE;
+
                  /* Check if we write a read-only CSR by the CSR
                     instruction.  */
                  if (insn_with_csr
@@ -1683,18 +2020,18 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                case '<':
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_IMM (imm_expr->X_add_number)
                      || imm_expr->X_add_number <= 0
-                     || imm_expr->X_add_number >= 32)
+                     || imm_expr->X_add_number >= 32
+                     || !VALID_RVC_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case '8':
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_UIMM8 (imm_expr->X_add_number)
                      || imm_expr->X_add_number < 0
-                     || imm_expr->X_add_number >= 256)
+                     || imm_expr->X_add_number >= 256
+                     || !VALID_RVC_UIMM8 ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_UIMM8 (imm_expr->X_add_number);
                  goto rvc_imm_done;
@@ -1702,7 +2039,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || imm_expr->X_add_number == 0
-                     || !VALID_RVC_SIMM3 (imm_expr->X_add_number))
+                     || !VALID_RVC_SIMM3 ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_SIMM3 (imm_expr->X_add_number);
                  goto rvc_imm_done;
@@ -1710,7 +2047,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || imm_expr->X_add_number == 0
-                     || !VALID_RVC_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
@@ -1719,7 +2056,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_LW_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_LW_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_LW_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
@@ -1728,7 +2065,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_LD_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_LD_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_LD_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
@@ -1737,7 +2074,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_LWSP_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_LWSP_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |=
                    ENCODE_RVC_LWSP_IMM (imm_expr->X_add_number);
@@ -1747,7 +2084,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_LDSP_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_LDSP_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |=
                    ENCODE_RVC_LDSP_IMM (imm_expr->X_add_number);
@@ -1758,15 +2095,15 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                      /* C.addiw, c.li, and c.andi allow zero immediate.
                         C.addi allows zero immediate as hint.  Otherwise this
                         is same as 'j'.  */
-                     || !VALID_RVC_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'K':
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_ADDI4SPN_IMM (imm_expr->X_add_number)
-                     || imm_expr->X_add_number == 0)
+                     || imm_expr->X_add_number == 0
+                     || !VALID_RVC_ADDI4SPN_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |=
                    ENCODE_RVC_ADDI4SPN_IMM (imm_expr->X_add_number);
@@ -1774,8 +2111,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                case 'L':
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_ADDI16SP_IMM (imm_expr->X_add_number)
-                     || imm_expr->X_add_number == 0)
+                     || imm_expr->X_add_number == 0
+                     || !VALID_RVC_ADDI16SP_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |=
                    ENCODE_RVC_ADDI16SP_IMM (imm_expr->X_add_number);
@@ -1785,7 +2122,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_SWSP_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_SWSP_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |=
                    ENCODE_RVC_SWSP_IMM (imm_expr->X_add_number);
@@ -1795,7 +2132,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
-                     || !VALID_RVC_SDSP_IMM (imm_expr->X_add_number))
+                     || !VALID_RVC_SDSP_IMM ((valueT) imm_expr->X_add_number))
                    break;
                  ip->insn_opcode |=
                    ENCODE_RVC_SDSP_IMM (imm_expr->X_add_number);
@@ -1967,6 +2304,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 
            case 'E':           /* Control register.  */
              insn_with_csr = TRUE;
+             explicit_priv_attr = TRUE;
              if (reg_lookup (&s, RCLASS_CSR, &regno))
                INSERT_OPERAND (CSR, *ip, regno);
              else
@@ -2305,9 +2643,18 @@ md_assemble (char *str)
   expressionS imm_expr;
   bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
 
-  const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
+  /* The arch and priv attributes should be set before assembling.  */
+  if (!start_assemble)
+    {
+      start_assemble = TRUE;
+      riscv_set_abi_by_arch ();
 
-  start_assemble = TRUE;
+      /* Set the default_priv_spec according to the priv attributes.  */
+      if (!riscv_set_default_priv_spec (NULL))
+       return;
+    }
+
+  const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
 
   if (error)
     {
@@ -2330,7 +2677,10 @@ md_atof (int type, char *litP, int *sizeP)
 void
 md_number_to_chars (char *buf, valueT val, int n)
 {
-  number_to_chars_littleendian (buf, val, n);
+  if (target_big_endian)
+    number_to_chars_bigendian (buf, val, n);
+  else
+    number_to_chars_littleendian (buf, val, n);
 }
 
 const char *md_shortopts = "O::g::G:";
@@ -2347,6 +2697,10 @@ enum options
   OPTION_NO_ARCH_ATTR,
   OPTION_CSR_CHECK,
   OPTION_NO_CSR_CHECK,
+  OPTION_MISA_SPEC,
+  OPTION_MPRIV_SPEC,
+  OPTION_BIG_ENDIAN,
+  OPTION_LITTLE_ENDIAN,
   OPTION_END_OF_ENUM
 };
 
@@ -2363,35 +2717,24 @@ struct option md_longopts[] =
   {"mno-arch-attr", no_argument, NULL, OPTION_NO_ARCH_ATTR},
   {"mcsr-check", no_argument, NULL, OPTION_CSR_CHECK},
   {"mno-csr-check", no_argument, NULL, OPTION_NO_CSR_CHECK},
+  {"misa-spec", required_argument, NULL, OPTION_MISA_SPEC},
+  {"mpriv-spec", required_argument, NULL, OPTION_MPRIV_SPEC},
+  {"mbig-endian", no_argument, NULL, OPTION_BIG_ENDIAN},
+  {"mlittle-endian", no_argument, NULL, OPTION_LITTLE_ENDIAN},
 
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
 
-enum float_abi {
-  FLOAT_ABI_DEFAULT = -1,
-  FLOAT_ABI_SOFT,
-  FLOAT_ABI_SINGLE,
-  FLOAT_ABI_DOUBLE,
-  FLOAT_ABI_QUAD
-};
-static enum float_abi float_abi = FLOAT_ABI_DEFAULT;
-
-static void
-riscv_set_abi (unsigned new_xlen, enum float_abi new_float_abi, bfd_boolean rve)
-{
-  abi_xlen = new_xlen;
-  float_abi = new_float_abi;
-  rve_abi = rve;
-}
-
 int
 md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
     case OPTION_MARCH:
-      riscv_set_arch (arg);
+      /* riscv_after_parse_args will call riscv_set_arch to parse
+        the architecture.  */
+      default_arch_with_ext = arg;
       break;
 
     case OPTION_NO_PIC:
@@ -2423,6 +2766,7 @@ md_parse_option (int c, const char *arg)
        riscv_set_abi (64, FLOAT_ABI_QUAD, FALSE);
       else
        return 0;
+      explicit_mabi = TRUE;
       break;
 
     case OPTION_RELAX:
@@ -2449,6 +2793,20 @@ md_parse_option (int c, const char *arg)
       riscv_opts.csr_check = FALSE;
       break;
 
+    case OPTION_MISA_SPEC:
+      return riscv_set_default_isa_spec (arg);
+
+    case OPTION_MPRIV_SPEC:
+      return riscv_set_default_priv_spec (arg);
+
+    case OPTION_BIG_ENDIAN:
+      target_big_endian = 1;
+      break;
+
+    case OPTION_LITTLE_ENDIAN:
+      target_big_endian = 0;
+      break;
+
     default:
       return 0;
     }
@@ -2459,6 +2817,10 @@ md_parse_option (int c, const char *arg)
 void
 riscv_after_parse_args (void)
 {
+  /* The --with-arch is optional for now, so we have to set the xlen
+     according to the default_arch, which is set by the --targte, first.
+     Then, we use the xlen to set the default_arch_with_ext if the
+     -march and --with-arch are not set.  */
   if (xlen == 0)
     {
       if (strcmp (default_arch, "riscv32") == 0)
@@ -2468,9 +2830,19 @@ riscv_after_parse_args (void)
       else
        as_bad ("unknown default architecture `%s'", default_arch);
     }
+  if (default_arch_with_ext == NULL)
+    default_arch_with_ext = xlen == 64 ? "rv64g" : "rv32g";
+
+  /* Initialize the hash table for extensions with default version.  */
+  ext_version_hash = init_ext_version_hash (riscv_ext_version_table);
 
-  if (riscv_subsets.head == NULL)
-    riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
+  /* If the -misa-spec isn't set, then we set the default ISA spec according
+     to DEFAULT_RISCV_ISA_SPEC.  */
+  if (default_isa_spec == ISA_SPEC_CLASS_NONE)
+    riscv_set_default_isa_spec (DEFAULT_RISCV_ISA_SPEC);
+
+  /* Set the architecture according to -march or or --with-arch.  */
+  riscv_set_arch (default_arch_with_ext);
 
   /* Add the RVC extension, regardless of -march, to support .option rvc.  */
   riscv_set_rvc (FALSE);
@@ -2482,35 +2854,10 @@ riscv_after_parse_args (void)
   if (riscv_subset_supports ("e"))
     riscv_set_rve (TRUE);
 
-  /* Infer ABI from ISA if not specified on command line.  */
-  if (abi_xlen == 0)
-    abi_xlen = xlen;
-  else if (abi_xlen > xlen)
-    as_bad ("can't have %d-bit ABI on %d-bit ISA", abi_xlen, xlen);
-  else if (abi_xlen < xlen)
-    as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen);
-
-  if (float_abi == FLOAT_ABI_DEFAULT)
-    {
-      riscv_subset_t *subset;
-
-      /* Assume soft-float unless D extension is present.  */
-      float_abi = FLOAT_ABI_SOFT;
-
-      for (subset = riscv_subsets.head; subset != NULL; subset = subset->next)
-       {
-         if (strcasecmp (subset->name, "D") == 0)
-           float_abi = FLOAT_ABI_DOUBLE;
-         if (strcasecmp (subset->name, "Q") == 0)
-           float_abi = FLOAT_ABI_QUAD;
-       }
-    }
-
-  if (rve_abi)
-    elf_flags |= EF_RISCV_RVE;
-
-  /* Insert float_abi into the EF_RISCV_FLOAT_ABI field of elf_flags.  */
-  elf_flags |= float_abi * (EF_RISCV_FLOAT_ABI & ~(EF_RISCV_FLOAT_ABI << 1));
+  /* If the -mpriv-spec isn't set, then we set the default privilege spec
+     according to DEFAULT_PRIV_SPEC.  */
+  if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
+    riscv_set_default_priv_spec (DEFAULT_RISCV_PRIV_SPEC);
 
   /* If the CIE to be produced has not been overridden on the command line,
      then produce version 3 by default.  This allows us to use the full
@@ -2769,6 +3116,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
       fixP->fx_next->fx_addsy = fixP->fx_next->fx_subsy = NULL;
       fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_RELAX;
+      fixP->fx_next->fx_size = 0;
     }
 }
 
@@ -2779,7 +3127,11 @@ void
 riscv_pre_output_hook (void)
 {
   const frchainS *frch;
-  const asection *s;
+  segT s;
+
+  /* Save the current segment info.  */
+  segT seg = now_seg;
+  subsegT subseg = now_subseg;
 
   for (s = stdoutput->sections; s; s = s->next)
     for (frch = seg_info (s)->frchainP; frch; frch = frch->frch_next)
@@ -2799,11 +3151,18 @@ riscv_pre_output_hook (void)
                exp.X_add_number = 0;
                exp.X_op_symbol = symval->X_op_symbol;
 
+               /* We must set the segment before creating a frag after all
+                  frag chains have been chained together.  */
+               subseg_set (s, frch->frch_subseg);
+
                fix_new_exp (frag, (int) frag->fr_offset, 1, &exp, 0,
                             BFD_RELOC_RISCV_CFA);
              }
          }
       }
+
+  /* Restore the original segment info.  */
+  subseg_set (seg, subseg);
 }
 
 
@@ -2929,13 +3288,13 @@ riscv_make_nops (char *buf, bfd_vma bytes)
   /* Use at most one 2-byte NOP.  */
   if ((bytes - i) % 4 == 2)
     {
-      md_number_to_chars (buf + i, RVC_NOP, 2);
+      number_to_chars_littleendian (buf + i, RVC_NOP, 2);
       i += 2;
     }
 
   /* Fill the remainder with 4-byte NOPs.  */
   for ( ; i < bytes; i += 4)
-    md_number_to_chars (buf + i, RISCV_NOP, 4);
+    number_to_chars_littleendian (buf + i, RISCV_NOP, 4);
 }
 
 /* Called from md_do_align.  Used to create an alignment frag in a
@@ -3139,14 +3498,14 @@ md_convert_frag_branch (fragS *fragp)
       insn = bfd_getl32 (buf);
       insn ^= MATCH_BEQ ^ MATCH_BNE;
       insn |= ENCODE_SBTYPE_IMM (8);
-      md_number_to_chars ((char *) buf, insn, 4);
+      bfd_putl32 (insn, buf);
       buf += 4;
 
     jump:
       /* Jump to the target.  */
       fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
                          4, &exp, FALSE, BFD_RELOC_RISCV_JMP);
-      md_number_to_chars ((char *) buf, MATCH_JAL, 4);
+      bfd_putl32 (MATCH_JAL, buf);
       buf += 4;
       break;
 
@@ -3188,14 +3547,16 @@ md_show_usage (FILE *stream)
 {
   fprintf (stream, _("\
 RISC-V options:\n\
-  -fpic          generate position-independent code\n\
-  -fno-pic       don't generate position-independent code (default)\n\
-  -march=ISA     set the RISC-V architecture\n\
-  -mabi=ABI      set the RISC-V ABI\n\
-  -mrelax        enable relax (default)\n\
-  -mno-relax     disable relax\n\
-  -march-attr    generate RISC-V arch attribute\n\
-  -mno-arch-attr don't generate RISC-V arch attribute\n\
+  -fpic                       generate position-independent code\n\
+  -fno-pic                    don't generate position-independent code (default)\n\
+  -march=ISA                  set the RISC-V architecture\n\
+  -misa-spec=ISAspec          set the RISC-V ISA spec (2.2, 20190608, 20191213)\n\
+  -mpriv-spec=PRIVspec        set the RISC-V privilege spec (1.9, 1.9.1, 1.10, 1.11)\n\
+  -mabi=ABI                   set the RISC-V ABI\n\
+  -mrelax                     enable relax (default)\n\
+  -mno-relax                  disable relax\n\
+  -march-attr                 generate RISC-V arch attribute\n\
+  -mno-arch-attr              don't generate RISC-V arch attribute\n\
 "));
 }
 
@@ -3228,6 +3589,7 @@ tc_riscv_regname_to_dw2regnum (char *regname)
 void
 riscv_elf_final_processing (void)
 {
+  riscv_set_abi_by_arch ();
   elf_elfheader (stdoutput)->e_flags |= elf_flags;
 }
 
@@ -3283,26 +3645,75 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-/* Update arch attributes.  */
+/* Update arch and priv attributes.  If we don't set the corresponding ELF
+   attributes, then try to output the default ones.  */
 
 static void
-riscv_write_out_arch_attr (void)
+riscv_write_out_attrs (void)
 {
-  const char *arch_str = riscv_arch_str (xlen, &riscv_subsets);
+  const char *arch_str, *priv_str, *p;
+  /* versions[0] is major, versions[1] is minor,
+     and versions[3] is revision.  */
+  unsigned versions[3] = {0}, number = 0;
+  unsigned int i;
 
+  /* Re-write arch attribute to normalize the arch string.  */
+  arch_str = riscv_arch_str (xlen, &riscv_subsets);
   bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str);
-
   xfree ((void *)arch_str);
+
+  /* For the file without any instruction, we don't set the default_priv_spec
+     according to the priv attributes since the md_assemble isn't called.
+     Call riscv_set_default_priv_spec here for the above case, although
+     it seems strange.  */
+  if (!start_assemble
+      && !riscv_set_default_priv_spec (NULL))
+    return;
+
+  /* If we already have set elf priv attributes, then no need to do anything,
+     assembler will generate them according to what you set.  Otherwise, don't
+     generate or update them when no CSR and priv instructions are used.
+     Generate the priv attributes according to default_priv_spec, which can be
+     set by -mpriv-spec and --with-priv-spec, and be updated by the original
+     priv attribute sets.  */
+  if (!explicit_priv_attr)
+    return;
+
+  /* Re-write priv attributes by default_priv_spec.  */
+  priv_str = riscv_get_priv_spec_name (default_priv_spec);
+  p = priv_str;
+  for (i = 0; *p; ++p)
+    {
+      if (*p == '.' && i < 3)
+       {
+         versions[i++] = number;
+         number = 0;
+       }
+      else if (ISDIGIT (*p))
+       number = (number * 10) + (*p - '0');
+      else
+       {
+         as_bad (_("internal: bad RISC-V priv spec string (%s)"), priv_str);
+         return;
+       }
+    }
+  versions[i] = number;
+
+  /* Set the priv attributes.  */
+  bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec, versions[0]);
+  bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec_minor, versions[1]);
+  bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec_revision, versions[2]);
 }
 
-/* Add the default contents for the .riscv.attributes section.  */
+/* Add the default contents for the .riscv.attributes section.  If any
+   ELF attribute or -march-attr options is set, call riscv_write_out_attrs
+   to update the arch and priv attributes.  */
 
 static void
 riscv_set_public_attributes (void)
 {
-  if (riscv_opts.arch_attr || explicit_arch_attr)
-    /* Re-write arch attribute to normalize the arch string.  */
-    riscv_write_out_arch_attr ();
+  if (riscv_opts.arch_attr || explicit_attr)
+    riscv_write_out_attrs ();
 }
 
 /* Called after all assembly has been done.  */
@@ -3356,13 +3767,14 @@ static void
 s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
 {
   int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
+  unsigned old_xlen;
+  obj_attribute *attr;
 
-  if (tag == Tag_RISCV_arch)
+  explicit_attr = TRUE;
+  switch (tag)
     {
-      unsigned old_xlen = xlen;
-
-      explicit_arch_attr = TRUE;
-      obj_attribute *attr;
+    case Tag_RISCV_arch:
+      old_xlen = xlen;
       attr = elf_known_obj_attributes_proc (stdoutput);
       if (!start_assemble)
        riscv_set_arch (attr[Tag_RISCV_arch].s);
@@ -3378,6 +3790,17 @@ s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
          if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
            as_warn (_("Could not set architecture and machine"));
        }
+      break;
+
+    case Tag_RISCV_priv_spec:
+    case Tag_RISCV_priv_spec_minor:
+    case Tag_RISCV_priv_spec_revision:
+      if (start_assemble)
+       as_fatal (_(".attribute priv spec must set before any instructions"));
+      break;
+
+    default:
+      break;
     }
 }