]> 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 c575c0753ffc42f22246f493a9fe7d1a40948d12..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.
@@ -91,6 +91,14 @@ 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")
@@ -210,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
@@ -227,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");
@@ -253,7 +279,8 @@ init_ext_version_hash (const struct riscv_ext_version *table)
   while (table[i].name)
     {
       const char *name = table[i].name;
-      str_hash_insert (hash, name, (void *) &table[i]);
+      if (str_hash_insert (hash, name, &table[i], 0) != NULL)
+       as_fatal (_("duplicate %s"), name);
 
       i++;
       while (table[i].name
@@ -266,28 +293,26 @@ init_ext_version_hash (const struct riscv_ext_version *table)
 
 static void
 riscv_get_default_ext_version (const char *name,
-                              unsigned int *major_version,
-                              unsigned int *minor_version)
+                              int *major_version,
+                              int *minor_version)
 {
   struct riscv_ext_version *ext;
 
-  *major_version = 0;
-  *minor_version = 0;
-
   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)
+        && ext->name
+        && strcmp (ext->name, name) == 0)
     {
-      if (ext->isa_spec_class == default_isa_spec)
-       {
-         *major_version = ext->major_version;
-         *minor_version = ext->minor_version;
-         return;
-       }
+      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++;
     }
 }
@@ -299,7 +324,7 @@ 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;
 
@@ -310,6 +335,50 @@ riscv_set_arch (const char *s)
   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 htab_t op_hash = NULL;
 
@@ -343,10 +412,10 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 /* Indicate we are already assemble any instructions or not.  */
 static bfd_boolean start_assemble = FALSE;
 
-/* Indicate ELF attributes are explictly set.  */
+/* Indicate ELF attributes are explicitly set.  */
 static bfd_boolean explicit_attr = FALSE;
 
-/* Indicate CSR or priv instructions are explictly used.  */
+/* 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.  */
@@ -387,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.  */
@@ -416,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
@@ -558,7 +630,8 @@ init_opcode_names_hash (void)
   const struct opcode_name_t *opcode;
 
   for (opcode = &opcode_name_list[0]; opcode->name != NULL; ++opcode)
-    str_hash_insert (opcode_names_hash, opcode->name, (void *)opcode);
+    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,
@@ -614,7 +687,8 @@ static void
 hash_reg_name (enum reg_class class, const char *name, unsigned n)
 {
   void *hash = ENCODE_REG_HASH (class, n);
-  str_hash_insert (reg_names_hash, name, hash);
+  if (str_hash_insert (reg_names_hash, name, hash, 0) != NULL)
+    as_fatal (_("duplicate %s"), name);
 }
 
 static void
@@ -665,7 +739,7 @@ riscv_init_csr_hash (const char *name,
      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, (void *) entry);
+    str_hash_insert (csr_extra_hash, name, entry, 0);
   else
     pre_entry->next = entry;
 }
@@ -998,7 +1072,8 @@ init_opcode_hash (const struct riscv_opcode *opcodes,
   while (opcodes[i].name)
     {
       const char *name = opcodes[i].name;
-      str_hash_insert (hash, name, (void *) &opcodes[i]);
+      if (str_hash_insert (hash, name, &opcodes[i], 0) != NULL)
+       as_fatal (_("duplicate %s"), name);
 
       do
        {
@@ -1102,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,
@@ -1129,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)
@@ -1266,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.  */
@@ -1307,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.  */
@@ -1362,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)
@@ -1483,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;
@@ -1901,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;
@@ -1920,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;
@@ -1928,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;
@@ -1937,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;
@@ -1946,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;
@@ -1955,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);
@@ -1965,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);
@@ -1976,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);
@@ -1992,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);
@@ -2003,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);
@@ -2013,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);
@@ -2528,6 +2647,7 @@ md_assemble (char *str)
   if (!start_assemble)
     {
       start_assemble = TRUE;
+      riscv_set_abi_by_arch ();
 
       /* Set the default_priv_spec according to the priv attributes.  */
       if (!riscv_set_default_priv_spec (NULL))
@@ -2557,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:";
@@ -2576,6 +2699,8 @@ enum options
   OPTION_NO_CSR_CHECK,
   OPTION_MISA_SPEC,
   OPTION_MPRIV_SPEC,
+  OPTION_BIG_ENDIAN,
+  OPTION_LITTLE_ENDIAN,
   OPTION_END_OF_ENUM
 };
 
@@ -2594,28 +2719,13 @@ struct option md_longopts[] =
   {"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)
 {
@@ -2656,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:
@@ -2688,6 +2799,14 @@ md_parse_option (int c, const char *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;
     }
@@ -2740,36 +2859,6 @@ riscv_after_parse_args (void)
   if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
     riscv_set_default_priv_spec (DEFAULT_RISCV_PRIV_SPEC);
 
-  /* 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 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
      range of registers in a .cfi_return_column directive.  */
@@ -3027,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;
     }
 }
 
@@ -3198,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
@@ -3408,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;
 
@@ -3499,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;
 }