bfd: use https for bugzilla
[deliverable/binutils-gdb.git] / bfd / elfxx-riscv.c
index d92b2738f3d757cc7e1240fa5289b90bcfe40f09..f6a2509d521513a1d096ace5789d4795d34209b7 100644 (file)
@@ -1,5 +1,5 @@
 /* RISC-V-specific support for ELF.
-   Copyright (C) 2011-2018 Free Software Foundation, Inc.
+   Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
    Contributed by Andrew Waterman (andrew@sifive.com).
    Based on TILE-Gx and MIPS targets.
@@ -29,6 +29,7 @@
 #include "libiberty.h"
 #include "elfxx-riscv.h"
 #include "safe-ctype.h"
+#include "cpu-riscv.h"
 
 #define MINUS_ONE ((bfd_vma)0 - 1)
 
@@ -48,173 +49,173 @@ static reloc_howto_type howto_table[] =
         0,                             /* rightshift */
         3,                             /* size */
         0,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_NONE",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 32 bit relocation.  */
   HOWTO (R_RISCV_32,                   /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_32",                  /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 64 bit relocation.  */
   HOWTO (R_RISCV_64,                   /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_64",                  /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Relocation against a local symbol in a shared object.  */
   HOWTO (R_RISCV_RELATIVE,             /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_RELATIVE",            /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_COPY,                 /* type */
         0,                             /* rightshift */
         0,                             /* this one is variable size */
         0,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_COPY",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_JUMP_SLOT,            /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_JUMP_SLOT",           /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Dynamic TLS relocations.  */
   HOWTO (R_RISCV_TLS_DTPMOD32,         /* type */
         0,                             /* rightshift */
-        4,                             /* size */
+        2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_DTPMOD32",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_TLS_DTPMOD64,         /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_DTPMOD64",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_TLS_DTPREL32,         /* type */
         0,                             /* rightshift */
-        4,                             /* size */
+        2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_DTPREL32",        /* name */
-        TRUE,                          /* partial_inplace */
+        true,                          /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_TLS_DTPREL64,         /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_DTPREL64",        /* name */
-        TRUE,                          /* partial_inplace */
+        true,                          /* partial_inplace */
         0,                             /* src_mask */
         MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_TLS_TPREL32,          /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_TPREL32",         /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   HOWTO (R_RISCV_TLS_TPREL64,          /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_TPREL64",         /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Reserved for future relocs that the dynamic linker must understand.  */
   EMPTY_HOWTO (12),
@@ -227,638 +228,652 @@ static reloc_howto_type howto_table[] =
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_BRANCH",              /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        ENCODE_SBTYPE_IMM (-1U),       /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        ENCODE_BTYPE_IMM (-1U),        /* dst_mask */
+        true),                         /* pcrel_offset */
 
   /* 20-bit PC-relative jump offset.  */
   HOWTO (R_RISCV_JAL,                  /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_JAL",                 /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        ENCODE_UJTYPE_IMM (-1U),       /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        ENCODE_JTYPE_IMM (-1U),        /* dst_mask */
+        true),                         /* pcrel_offset */
 
   /* 32-bit PC-relative function call (AUIPC/JALR).  */
   HOWTO (R_RISCV_CALL,                 /* type */
         0,                             /* rightshift */
-        2,                             /* size */
+        4,                             /* size */
         64,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_CALL",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
                                        /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        true),                         /* pcrel_offset */
 
   /* Like R_RISCV_CALL, but not locally binding.  */
   HOWTO (R_RISCV_CALL_PLT,             /* type */
         0,                             /* rightshift */
-        2,                             /* size */
+        4,                             /* size */
         64,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_CALL_PLT",            /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
                                        /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        true),                         /* pcrel_offset */
 
   /* High 20 bits of 32-bit PC-relative GOT access.  */
   HOWTO (R_RISCV_GOT_HI20,             /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_GOT_HI20",            /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 20 bits of 32-bit PC-relative TLS IE GOT access.  */
   HOWTO (R_RISCV_TLS_GOT_HI20,         /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_GOT_HI20",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 20 bits of 32-bit PC-relative TLS GD GOT reference.  */
   HOWTO (R_RISCV_TLS_GD_HI20,          /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TLS_GD_HI20",         /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 20 bits of 32-bit PC-relative reference.  */
   HOWTO (R_RISCV_PCREL_HI20,           /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_PCREL_HI20",          /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        true),                         /* pcrel_offset */
 
   /* Low 12 bits of a 32-bit PC-relative load or add.  */
   HOWTO (R_RISCV_PCREL_LO12_I,         /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_PCREL_LO12_I",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Low 12 bits of a 32-bit PC-relative store.  */
   HOWTO (R_RISCV_PCREL_LO12_S,         /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_PCREL_LO12_S",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_STYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 20 bits of 32-bit absolute address.  */
   HOWTO (R_RISCV_HI20,                 /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_HI20",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 12 bits of 32-bit load or add.  */
   HOWTO (R_RISCV_LO12_I,               /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_LO12_I",              /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 12 bits of 32-bit store.  */
   HOWTO (R_RISCV_LO12_S,               /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_LO12_S",              /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_STYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* High 20 bits of TLS LE thread pointer offset.  */
   HOWTO (R_RISCV_TPREL_HI20,           /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TPREL_HI20",          /* name */
-        TRUE,                          /* partial_inplace */
+        true,                          /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Low 12 bits of TLS LE thread pointer offset for loads and adds.  */
   HOWTO (R_RISCV_TPREL_LO12_I,         /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TPREL_LO12_I",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Low 12 bits of TLS LE thread pointer offset for stores.  */
   HOWTO (R_RISCV_TPREL_LO12_S,         /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TPREL_LO12_S",        /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_STYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* TLS LE thread pointer usage.  May be relaxed.  */
   HOWTO (R_RISCV_TPREL_ADD,            /* type */
         0,                             /* rightshift */
-        2,                             /* size */
-        32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        3,                             /* size */
+        0,                             /* bitsize */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TPREL_ADD",           /* name */
-        TRUE,                          /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 8-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_ADD8,                 /* type */
         0,                             /* rightshift */
         0,                             /* size */
         8,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_ADD8",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xff,                          /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 16-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_ADD16,                        /* type */
         0,                             /* rightshift */
         1,                             /* size */
         16,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_ADD16",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffff,                        /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 32-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_ADD32,                        /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_ADD32",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 64-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_ADD64,                        /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_ADD64",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 8-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_SUB8,                 /* type */
         0,                             /* rightshift */
         0,                             /* size */
         8,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_SUB8",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xff,                          /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 16-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_SUB16,                        /* type */
         0,                             /* rightshift */
         1,                             /* size */
         16,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_SUB16",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffff,                        /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 32-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_SUB32,                        /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_SUB32",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 64-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_SUB64,                        /* type */
         0,                             /* rightshift */
         4,                             /* size */
         64,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_SUB64",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* GNU extension to record C++ vtable hierarchy */
   HOWTO (R_RISCV_GNU_VTINHERIT,                /* type */
         0,                             /* rightshift */
         4,                             /* size */
         0,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         NULL,                          /* special_function */
         "R_RISCV_GNU_VTINHERIT",       /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* GNU extension to record C++ vtable member usage */
   HOWTO (R_RISCV_GNU_VTENTRY,          /* type */
         0,                             /* rightshift */
         4,                             /* size */
         0,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
         "R_RISCV_GNU_VTENTRY",         /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* Indicates an alignment statement.  The addend field encodes how many
      bytes of NOPs follow the statement.  The desired alignment is the
      addend rounded up to the next power of two.  */
   HOWTO (R_RISCV_ALIGN,                        /* type */
         0,                             /* rightshift */
-        2,                             /* size */
+        3,                             /* size */
         0,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_ALIGN",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 8-bit PC-relative branch offset.  */
   HOWTO (R_RISCV_RVC_BRANCH,           /* type */
         0,                             /* rightshift */
-        2,                             /* size */
-        32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        1,                             /* size */
+        16,                            /* bitsize */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_RVC_BRANCH",          /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        ENCODE_RVC_B_IMM (-1U),        /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        ENCODE_CBTYPE_IMM (-1U),       /* dst_mask */
+        true),                         /* pcrel_offset */
 
   /* 11-bit PC-relative jump offset.  */
   HOWTO (R_RISCV_RVC_JUMP,             /* type */
         0,                             /* rightshift */
-        2,                             /* size */
-        32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        1,                             /* size */
+        16,                            /* bitsize */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_RVC_JUMP",            /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        ENCODE_RVC_J_IMM (-1U),        /* dst_mask */
-        TRUE),                         /* pcrel_offset */
+        ENCODE_CJTYPE_IMM (-1U),       /* dst_mask */
+        true),                         /* pcrel_offset */
 
   /* High 6 bits of 18-bit absolute address.  */
   HOWTO (R_RISCV_RVC_LUI,              /* type */
         0,                             /* rightshift */
-        2,                             /* size */
-        32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        1,                             /* size */
+        16,                            /* bitsize */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_RVC_LUI",             /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        ENCODE_RVC_IMM (-1U),          /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        ENCODE_CITYPE_IMM (-1U),       /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* GP-relative load.  */
   HOWTO (R_RISCV_GPREL_I,              /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_GPREL_I",             /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* GP-relative store.  */
   HOWTO (R_RISCV_GPREL_S,              /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_GPREL_S",             /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_STYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* TP-relative TLS LE load.  */
   HOWTO (R_RISCV_TPREL_I,              /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TPREL_I",             /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* TP-relative TLS LE store.  */
   HOWTO (R_RISCV_TPREL_S,              /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_TPREL_S",             /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         ENCODE_STYPE_IMM (-1U),        /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* The paired relocation may be relaxed.  */
   HOWTO (R_RISCV_RELAX,                        /* type */
         0,                             /* rightshift */
         3,                             /* size */
         0,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_RELAX",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0,                             /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 6-bit in-place addition, for local label subtraction.  */
   HOWTO (R_RISCV_SUB6,                 /* type */
         0,                             /* rightshift */
         0,                             /* size */
         8,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         riscv_elf_add_sub_reloc,       /* special_function */
         "R_RISCV_SUB6",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0x3f,                          /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 6-bit in-place setting, for local label subtraction.  */
   HOWTO (R_RISCV_SET6,                 /* type */
         0,                             /* rightshift */
         0,                             /* size */
         8,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_SET6",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
         0x3f,                          /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        false),                        /* pcrel_offset */
 
   /* 8-bit in-place setting, for local label subtraction.  */
   HOWTO (R_RISCV_SET8,                 /* type */
         0,                             /* rightshift */
         0,                             /* size */
         8,                             /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_SET8",                /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xff,                          /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 16-bit in-place setting, for local label subtraction.  */
   HOWTO (R_RISCV_SET16,                        /* type */
         0,                             /* rightshift */
         1,                             /* size */
         16,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_SET16",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffff,                        /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 32-bit in-place setting, for local label subtraction.  */
   HOWTO (R_RISCV_SET32,                        /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        FALSE,                         /* pc_relative */
+        false,                         /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_SET32",               /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 
   /* 32-bit PC relative.  */
   HOWTO (R_RISCV_32_PCREL,             /* type */
         0,                             /* rightshift */
         2,                             /* size */
         32,                            /* bitsize */
-        TRUE,                          /* pc_relative */
+        true,                          /* pc_relative */
         0,                             /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,         /* special_function */
         "R_RISCV_32_PCREL",            /* name */
-        FALSE,                         /* partial_inplace */
+        false,                         /* partial_inplace */
         0,                             /* src_mask */
-        MINUS_ONE,                     /* dst_mask */
-        FALSE),                        /* pcrel_offset */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
+
+  /* Relocation against a local ifunc symbol in a shared object.  */
+  HOWTO (R_RISCV_IRELATIVE,            /* type */
+        0,                             /* rightshift */
+        2,                             /* size */
+        32,                            /* bitsize */
+        false,                         /* pc_relative */
+        0,                             /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc,         /* special_function */
+        "R_RISCV_IRELATIVE",           /* name */
+        false,                         /* partial_inplace */
+        0,                             /* src_mask */
+        0xffffffff,                    /* dst_mask */
+        false),                        /* pcrel_offset */
 };
 
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
-
 struct elf_reloc_map
 {
   bfd_reloc_code_real_type bfd_val;
@@ -1011,41 +1026,241 @@ riscv_elf_add_sub_reloc (bfd *abfd,
   return bfd_reloc_ok;
 }
 
-/* Parsing subset version.
+#define RISCV_UNKNOWN_VERSION -1
+
+/* Array is used to compare the orders of all extensions quickly.
+
+   Zero value: Preserved keyword.
+   Negative value: Prefixed keyword (s, h, x, z).
+   Positive value: Standard extension.  */
+static int riscv_ext_order[26] = {0};
+
+/* Similar to the strcmp.  It returns an integer less than, equal to,
+   or greater than zero if `subset2` is found, respectively, to be less
+   than, to match, or be greater than `subset1`.  */
+
+int
+riscv_compare_subsets (const char *subset1, const char *subset2)
+{
+  int order1 = riscv_ext_order[(*subset1 - 'a')];
+  int order2 = riscv_ext_order[(*subset2 - 'a')];
+
+  /* Compare the standard extension first.  */
+  if (order1 > 0 && order2 > 0)
+    return order1 - order2;
+
+  if (order1 == order2 && order1 < 0)
+    {
+      /* Compare the standard addition z extensions.  */
+      if (*subset1 == 'z')
+       {
+         order1 = riscv_ext_order[(*++subset1 - 'a')];
+         order2 = riscv_ext_order[(*++subset2 - 'a')];
+         if (order1 != order2)
+           return order1 - order2;
+       }
+      return strcasecmp (++subset1, ++subset2);
+    }
+
+  return order2 - order1;
+}
+
+/* Find subset in the list.  Return TRUE and set `current` to the subset
+   if it is found.  Otherwise, return FALSE and set `current` to the place
+   where we should insert the subset.  However, return FALSE with the NULL
+   `current` means we should insert the subset at the head of subset list,
+   if needed.  */
+
+bool
+riscv_lookup_subset (const riscv_subset_list_t *subset_list,
+                    const char *subset,
+                    riscv_subset_t **current)
+{
+  riscv_subset_t *s, *pre_s = NULL;
+
+  for (s = subset_list->head;
+       s != NULL;
+       pre_s = s, s = s->next)
+    {
+      int cmp = riscv_compare_subsets (s->name, subset);
+      if (cmp == 0)
+       {
+         *current = s;
+         return true;
+       }
+      else if (cmp > 0)
+       break;
+    }
+  *current = pre_s;
+  return false;
+}
+
+/* Add extension from ISA string to the last of the subset list.  */
+
+void
+riscv_add_subset (riscv_subset_list_t *subset_list,
+                 const char *subset,
+                 int major,
+                 int minor)
+{
+  riscv_subset_t *s = xmalloc (sizeof *s);
+
+  if (subset_list->head == NULL)
+    subset_list->head = s;
+
+  s->name = xstrdup (subset);
+  s->major_version = major;
+  s->minor_version = minor;
+  s->next = NULL;
+
+  if (subset_list->tail != NULL)
+    subset_list->tail->next = s;
+  subset_list->tail = s;
+}
+
+/* Add the implicit extension to the subset list.  Search the
+   list first, and then find the right place to add.  */
+
+static void
+riscv_add_implicit_subset (riscv_subset_list_t *subset_list,
+                          const char *subset,
+                          int major,
+                          int minor)
+{
+  riscv_subset_t *current, *new;
+
+  if (riscv_lookup_subset (subset_list, subset, &current))
+    return;
+
+  new = xmalloc (sizeof *new);
+  new->name = xstrdup (subset);
+  new->major_version = major;
+  new->minor_version = minor;
+  new->next = NULL;
+
+  if (current != NULL)
+    {
+      new->next = current->next;
+      current->next = new;
+    }
+  else
+    {
+      new->next = subset_list->head;
+      subset_list->head = new;
+    }
+}
+
+/* These extensions are added to the subset list for special purposes,
+   with the explicit versions or the RISCV_UNKNOWN_VERSION versions.
+   Therefore, we won't output them to the output ISA string in the
+   riscv_arch_str1, if the versions are unknown.  */
+
+static bool
+riscv_ext_dont_care_version (const char *subset)
+{
+  if (strcmp (subset, "g") == 0
+      || strcmp (subset, "zicsr") == 0
+      || strcmp (subset, "zifencei") == 0)
+    return true;
+  return false;
+}
+
+/* We have to add all extensions from ISA string first, and then start to
+   add their implicit extensions.  The extensions from ISA string must be
+   set in order, so we can add them to the last of the subset list
+   directly, without searching.
+
+   Find the default versions for the extension before adding them to
+   the subset list, if their versions are RISCV_UNKNOWN_VERSION.
+   Afterwards, report errors if we can not find their default versions.  */
+
+static void
+riscv_parse_add_subset (riscv_parse_subset_t *rps,
+                       const char *subset,
+                       int major,
+                       int minor,
+                       bool implicit)
+{
+  int major_version = major;
+  int minor_version = minor;
+
+  if ((major_version == RISCV_UNKNOWN_VERSION
+       || minor_version == RISCV_UNKNOWN_VERSION)
+      && rps->get_default_version != NULL)
+    rps->get_default_version (subset, &major_version, &minor_version);
+
+  if (!riscv_ext_dont_care_version (subset)
+      && (major_version == RISCV_UNKNOWN_VERSION
+         || minor_version == RISCV_UNKNOWN_VERSION))
+    {
+      /* We only add the implicit extension if it is supported in the
+        chosen ISA spec.  */
+      if (implicit)
+       return;
+
+      if (subset[0] == 'x')
+       rps->error_handler
+         (_("x ISA extension `%s' must be set with the versions"),
+          subset);
+      else
+       rps->error_handler
+         (_("cannot find default versions of the ISA extension `%s'"),
+          subset);
+      return;
+    }
+
+  if (!implicit)
+    riscv_add_subset (rps->subset_list, subset,
+                     major_version, minor_version);
+  else
+    riscv_add_implicit_subset (rps->subset_list, subset,
+                              major_version, minor_version);
+}
+
+/* Release subset list.  */
+
+void
+riscv_release_subset_list (riscv_subset_list_t *subset_list)
+{
+   while (subset_list->head != NULL)
+    {
+      riscv_subset_t *next = subset_list->head->next;
+      free ((void *)subset_list->head->name);
+      free (subset_list->head);
+      subset_list->head = next;
+    }
+
+  subset_list->tail = NULL;
+}
+
+/* Parsing extension version.
 
    Return Value:
      Points to the end of version
 
    Arguments:
-     `rps`: Hooks and status for parsing subset.
-     `march`: Full arch string.
+     `rps`: Hooks and status for parsing extensions.
+     `march`: Full ISA string.
      `p`: Curent parsing position.
-     `major_version`: Parsing result of major version, using
-      default_major_version if version is not present in arch string.
-     `minor_version`: Parsing result of minor version, set to 0 if version is
-     not present in arch string, but set to `default_minor_version` if
-     `major_version` using default_major_version.
-     `default_major_version`: Default major version.
-     `default_minor_version`: Default minor version.
-     `std_ext_p`: True if parsing std extension.  */
+     `major_version`: Parsed major version.
+     `minor_version`: Parsed minor version.
+     `std_ext_p`: True if parsing standard extension.  */
 
 static const char *
 riscv_parsing_subset_version (riscv_parse_subset_t *rps,
                              const char *march,
                              const char *p,
-                             unsigned *major_version,
-                             unsigned *minor_version,
-                             unsigned default_major_version,
-                             unsigned default_minor_version,
-                             bfd_boolean std_ext_p)
+                             int *major_version,
+                             int *minor_version,
+                             bool std_ext_p)
 {
-  bfd_boolean major_p = TRUE;
-  unsigned version = 0;
-  unsigned major = 0;
-  unsigned minor = 0;
+  bool major_p = true;
+  int version = 0;
   char np;
 
-  for (;*p; ++p)
+  *major_version = 0;
+  *minor_version = 0;
+  for (; *p; ++p)
     {
       if (*p == 'p')
        {
@@ -1062,14 +1277,15 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,
                }
              else
                {
-                 rps->error_handler ("-march=%s: Expect number after `%dp'.",
-                                     march, version);
+                 rps->error_handler
+                   (_("-march=%s: expect number after `%dp'"),
+                    march, version);
                  return NULL;
                }
            }
 
-         major = version;
-         major_p = FALSE;
+         *major_version = version;
+         major_p = false;
          version = 0;
        }
       else if (ISDIGIT (*p))
@@ -1079,21 +1295,17 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,
     }
 
   if (major_p)
-    major = version;
+    *major_version = version;
   else
-    minor = version;
+    *minor_version = version;
 
-  if (major == 0 && minor == 0)
-    {
-      /* We don't found any version string, use default version.  */
-      *major_version = default_major_version;
-      *minor_version = default_minor_version;
-    }
-  else
+  /* We can not find any version in string.  */
+  if (*major_version == 0 && *minor_version == 0)
     {
-      *major_version = major;
-      *minor_version = minor;
+      *major_version = RISCV_UNKNOWN_VERSION;
+      *minor_version = RISCV_UNKNOWN_VERSION;
     }
+
   return p;
 }
 
@@ -1112,88 +1324,86 @@ riscv_supported_std_ext (void)
      Points to the end of extensions.
 
    Arguments:
-     `rps`: Hooks and status for parsing subset.
-     `march`: Full arch string.
+     `rps`: Hooks and status for parsing extensions.
+     `march`: Full ISA string.
      `p`: Curent parsing position.  */
 
 static const char *
 riscv_parse_std_ext (riscv_parse_subset_t *rps,
-                    const char *march, const char *p)
+                    const char *march,
+                    const char *p)
 {
   const char *all_std_exts = riscv_supported_std_ext ();
   const char *std_exts = all_std_exts;
-
-  unsigned major_version = 0;
-  unsigned minor_version = 0;
-  char std_ext = '\0';
+  int major_version;
+  int minor_version;
+  char subset[2] = {0, 0};
 
   /* First letter must start with i, e or g.  */
   switch (*p)
     {
       case 'i':
-       p++;
-       p = riscv_parsing_subset_version (
-             rps,
-             march,
-             p, &major_version, &minor_version,
-             /* default_major_version= */ 2,
-             /* default_minor_version= */ 0,
-             /* std_ext_p= */TRUE);
-       riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
+       p = riscv_parsing_subset_version (rps, march, ++p,
+                                         &major_version,
+                                         &minor_version, true);
+       riscv_parse_add_subset (rps, "i",
+                               major_version,
+                               minor_version, false);
        break;
 
       case 'e':
-       p++;
-       p = riscv_parsing_subset_version (
-             rps,
-             march,
-             p, &major_version, &minor_version,
-             /* default_major_version= */ 1,
-             /* default_minor_version= */ 9,
-             /* std_ext_p= */TRUE);
-
-       riscv_add_subset (rps->subset_list, "e", major_version, minor_version);
-       riscv_add_subset (rps->subset_list, "i", 2, 0);
+       p = riscv_parsing_subset_version (rps, march, ++p,
+                                         &major_version,
+                                         &minor_version, true);
+       riscv_parse_add_subset (rps, "e",
+                               major_version,
+                               minor_version, false);
+       /* i-ext must be enabled.  */
+       riscv_parse_add_subset (rps, "i",
+                               RISCV_UNKNOWN_VERSION,
+                               RISCV_UNKNOWN_VERSION, false);
 
        if (*rps->xlen > 32)
          {
-           rps->error_handler ("-march=%s: rv%de is not a valid base ISA",
-                               march, *rps->xlen);
+           rps->error_handler
+             (_("-march=%s: rv%de is not a valid base ISA"),
+              march, *rps->xlen);
            return NULL;
          }
-
        break;
 
       case 'g':
-       p++;
-       p = riscv_parsing_subset_version (
-             rps,
-             march,
-             p, &major_version, &minor_version,
-             /* default_major_version= */ 2,
-             /* default_minor_version= */ 0,
-             /* std_ext_p= */TRUE);
-       riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
-
+       p = riscv_parsing_subset_version (rps, march, ++p,
+                                         &major_version,
+                                         &minor_version, true);
+       /* i-ext must be enabled.  */
+       riscv_parse_add_subset (rps, "i",
+                               RISCV_UNKNOWN_VERSION,
+                               RISCV_UNKNOWN_VERSION, false);
+       /* g-ext is used to add the implicit extensions, but will
+          not be output to the ISA string.  */
+       riscv_parse_add_subset (rps, "g",
+                               major_version,
+                               minor_version, false);
        for ( ; *std_exts != 'q'; std_exts++)
          {
-           const char subset[] = {*std_exts, '\0'};
-           riscv_add_subset (
-             rps->subset_list, subset, major_version, minor_version);
+           subset[0] = *std_exts;
+           riscv_parse_add_subset (rps, subset,
+                                   RISCV_UNKNOWN_VERSION,
+                                   RISCV_UNKNOWN_VERSION, false);
          }
        break;
 
       default:
-       rps->error_handler (
-         "-march=%s: first ISA subset must be `e', `i' or `g'", march);
+       rps->error_handler
+         (_("-march=%s: first ISA extension must be `e', `i' or `g'"),
+          march);
        return NULL;
     }
 
-  while (*p)
+  while (p != NULL && *p != '\0')
     {
-      char subset[2] = {0, 0};
-
-      if (*p == 'x' || *p == 's')
+      if (*p == 'x' || *p == 's' || *p == 'h' || *p == 'z')
        break;
 
       if (*p == '_')
@@ -1202,63 +1412,91 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
          continue;
        }
 
-      std_ext = *p;
-
       /* Checking canonical order.  */
-      while (*std_exts && std_ext != *std_exts) std_exts++;
+      char std_ext = *p;
+      while (*std_exts && std_ext != *std_exts)
+       std_exts++;
 
       if (std_ext != *std_exts)
        {
          if (strchr (all_std_exts, std_ext) == NULL)
-           rps->error_handler (
-             "-march=%s: unsupported ISA subset `%c'", march, *p);
+           rps->error_handler
+             (_("-march=%s: unknown standard ISA extension `%c'"),
+              march, std_ext);
          else
-           rps->error_handler (
-             "-march=%s: ISA string is not in canonical order. `%c'",
-             march, *p);
+           rps->error_handler
+             (_("-march=%s: standard ISA extension `%c' is not "
+                "in canonical order"), march, std_ext);
          return NULL;
        }
 
       std_exts++;
+      subset[0] = std_ext;
+      p = riscv_parsing_subset_version (rps, march, ++p,
+                                       &major_version,
+                                       &minor_version, true);
+      riscv_parse_add_subset (rps, subset,
+                             major_version,
+                             minor_version, false);
+    }
 
-      p++;
-      p = riscv_parsing_subset_version (
-           rps,
-           march,
-           p, &major_version, &minor_version,
-           /* default_major_version= */ 2,
-           /* default_minor_version= */ 0,
-           /* std_ext_p= */TRUE);
+  return p;
+}
 
-      subset[0] = std_ext;
+/* Classify ARCH into one of riscv_isa_ext_class_t.  */
 
-      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
+riscv_isa_ext_class_t
+riscv_get_prefix_class (const char *arch)
+{
+  switch (*arch)
+    {
+    case 's': return RV_ISA_CLASS_S;
+    case 'h': return RV_ISA_CLASS_H;
+    case 'x': return RV_ISA_CLASS_X;
+    case 'z': return RV_ISA_CLASS_Z;
+    default: return RV_ISA_CLASS_UNKNOWN;
     }
-  return p;
 }
 
-/* Parsing function for non-standard and supervisor extensions.
+/* Structure describing parameters to use when parsing a particular
+   riscv_isa_ext_class_t.  One of these should be provided for each
+   possible class, except RV_ISA_CLASS_UNKNOWN.  */
+typedef struct riscv_parse_config
+{
+  /* Class of the extension. */
+  riscv_isa_ext_class_t class;
+
+  /* Prefix string for error printing and internal parser usage.  */
+  const char *prefix;
+
+  /* Predicate which is used for checking whether this is a "known"
+     extension. For 'x', it always returns true since they are by
+     definition non-standard and cannot be known.  */
+  bool (*ext_valid_p) (const char *);
+} riscv_parse_config_t;
+
+/* Parsing function for prefixed extensions.
 
    Return Value:
-     Points to the end of extensions.
+     Points to the end of extension.
 
    Arguments:
-     `rps`: Hooks and status for parsing subset.
-     `march`: Full arch string.
+     `rps`: Hooks and status for parsing extensions.
+     `march`: Full ISA string.
      `p`: Curent parsing position.
-     `ext_type`: What kind of extensions, 'x', 's' or 'sx'.
-     `ext_type_str`: Full name for kind of extension.  */
+     `config`: What class and predicate function to use for the
+     extension.  */
 
 static const char *
-riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
-                              const char *march,
-                              const char *p,
-                              const char *ext_type,
-                              const char *ext_type_str)
+riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
+                         const char *march,
+                         const char *p,
+                         const riscv_parse_config_t *config)
 {
-  unsigned major_version = 0;
-  unsigned minor_version = 0;
-  size_t ext_type_len = strlen (ext_type);
+  int major_version;
+  int minor_version;
+  const char *last_name;
+  riscv_isa_ext_class_t class;
 
   while (*p)
     {
@@ -1268,12 +1506,11 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
          continue;
        }
 
-      if (strncmp (p, ext_type, ext_type_len) != 0)
-       break;
-
-      /* It's non-standard supervisor extension if it prefix with sx.  */
-      if ((ext_type[0] == 's') && (ext_type_len == 1)
-         && (*(p + 1) == 'x'))
+      /* Assert that the current extension specifier matches our parsing
+        class.  */
+      class = riscv_get_prefix_class (p);
+      if (class != config->class
+         || class == RV_ISA_CLASS_UNKNOWN)
        break;
 
       char *subset = xstrdup (p);
@@ -1284,24 +1521,66 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
        ;
 
       end_of_version =
-       riscv_parsing_subset_version (
-         rps,
-         march,
-         q, &major_version, &minor_version,
-         /* default_major_version= */ 2,
-         /* default_minor_version= */ 0,
-         /* std_ext_p= */FALSE);
-
+       riscv_parsing_subset_version (rps, march, q,
+                                     &major_version,
+                                     &minor_version, false);
       *q = '\0';
 
-      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
-      free (subset);
+      if (end_of_version == NULL)
+       {
+         free (subset);
+         return NULL;
+       }
+
+      /* Check that the prefix extension is known.
+        For 'x', anything goes but it cannot simply be 'x'.
+        For 's', it must be known from a list and cannot simply be 's'.
+        For 'h', it must be known from a list and cannot simply be 'h'.
+        For 'z', it must be known from a list and cannot simply be 'z'.  */
+
+      /* Check that the extension name is well-formed.  */
+      if (!config->ext_valid_p (subset))
+       {
+         rps->error_handler
+           (_("-march=%s: unknown %s ISA extension `%s'"),
+            march, config->prefix, subset);
+         free (subset);
+         return NULL;
+       }
+
+      /* Check that the extension isn't duplicate.  */
+      last_name = rps->subset_list->tail->name;
+      if (!strcasecmp (last_name, subset))
+       {
+         rps->error_handler
+           (_("-march=%s: duplicate %s ISA extension `%s'"),
+            march, config->prefix, subset);
+         free (subset);
+         return NULL;
+       }
+
+      /* Check that the extension is in alphabetical order.  */
+      if (riscv_compare_subsets (last_name, subset) > 0)
+       {
+         rps->error_handler
+           (_("-march=%s: %s ISA extension `%s' is not in alphabetical "
+              "order.  It must come before `%s'"),
+            march, config->prefix, subset, last_name);
+         free (subset);
+         return NULL;
+       }
+
+      riscv_parse_add_subset (rps, subset,
+                             major_version,
+                             minor_version, false);
       p += end_of_version - subset;
+      free (subset);
 
       if (*p != '\0' && *p != '_')
        {
-         rps->error_handler ("-march=%s: %s must seperate with _",
-                             march, ext_type_str);
+         rps->error_handler
+           (_("-march=%s: %s ISA extension must separate with _"),
+            march, config->prefix);
          return NULL;
        }
     }
@@ -1309,178 +1588,383 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
   return p;
 }
 
-/* Function for parsing arch string.
+/* Lists of prefixed class extensions that binutils should know about.
+   Whether or not a particular entry is in these lists will dictate if
+   gas/ld will accept its presence in the architecture string.
+
+   Please add the extensions to the lists in lower case.  However, keep
+   these subsets in alphabetical order in these tables is recommended,
+   although there is no impact on the current implementation.  */
+
+static const char * const riscv_std_z_ext_strtab[] =
+{
+  "zba", "zbb", "zbc", "zicsr", "zifencei", "zihintpause", NULL
+};
+
+static const char * const riscv_std_s_ext_strtab[] =
+{
+  NULL
+};
+
+static const char * const riscv_std_h_ext_strtab[] =
+{
+  NULL
+};
+
+/* For the extension `ext`, search through the list of known extensions
+   `known_exts` for a match, and return TRUE if found.  */
+
+static bool
+riscv_multi_letter_ext_valid_p (const char *ext,
+                               const char *const *known_exts)
+{
+  size_t i;
+
+  for (i = 0; known_exts[i]; ++i)
+    if (!strcmp (ext, known_exts[i]))
+      return true;
+
+  return false;
+}
+
+/* Predicator function for x-prefixed extensions.
+   Anything goes, except the literal 'x'.  */
+
+static bool
+riscv_ext_x_valid_p (const char *arg)
+{
+  if (!strcasecmp (arg, "x"))
+    return false;
+
+  return true;
+}
+
+/* Predicator functions for z-prefixed extensions.
+   Only known z-extensions are permitted.  */
+
+static bool
+riscv_ext_z_valid_p (const char *arg)
+{
+  return riscv_multi_letter_ext_valid_p (arg, riscv_std_z_ext_strtab);
+}
+
+/* Predicator function for 's' prefixed extensions.
+   Only known s-extensions are permitted.  */
+
+static bool
+riscv_ext_s_valid_p (const char *arg)
+{
+  return riscv_multi_letter_ext_valid_p (arg, riscv_std_s_ext_strtab);
+}
+
+/* Predicator function for 'h' prefixed extensions.
+   Only known h-extensions are permitted.  */
+
+static bool
+riscv_ext_h_valid_p (const char *arg)
+{
+  return riscv_multi_letter_ext_valid_p (arg, riscv_std_h_ext_strtab);
+}
+
+/* Parsing order of the prefixed extensions that is specified by
+   the ISA spec.  */
+static const riscv_parse_config_t parse_config[] =
+{
+  {RV_ISA_CLASS_S, "s", riscv_ext_s_valid_p},
+  {RV_ISA_CLASS_H, "h", riscv_ext_h_valid_p},
+  {RV_ISA_CLASS_Z, "z", riscv_ext_z_valid_p},
+  {RV_ISA_CLASS_X, "x", riscv_ext_x_valid_p},
+  {RV_ISA_CLASS_UNKNOWN, NULL, NULL}
+};
+
+/* Init the riscv_ext_order array.  */
+
+static void
+riscv_init_ext_order (void)
+{
+  static bool inited = false;
+  const char *std_base_exts = "eig";
+  const char *std_remain_exts = riscv_supported_std_ext ();
+  const char *ext;
+  unsigned int i;
+  int order;
+
+  if (inited)
+    return;
+
+  /* The orders of all standard extensions are positive.  */
+  order = 1;
+
+  /* Init the standard base extensions first.  */
+  for (ext = std_base_exts; *ext; ext++)
+    riscv_ext_order[(*ext - 'a')] = order++;
+
+  /* Init the standard remaining extensions.  */
+  for (ext = std_remain_exts; *ext; ext++)
+    riscv_ext_order[(*ext - 'a')] = order++;
+
+  /* Init the order for prefixed keywords.  The orders are negative.  */
+  order = -1;
+  for (i = 0; parse_config[i].class != RV_ISA_CLASS_UNKNOWN; i++)
+    {
+      ext = parse_config[i].prefix;
+      riscv_ext_order[(*ext - 'a')] = order--;
+    }
+
+  inited = true;
+}
+
+/* Add the implicit extensions.  */
+
+static void
+riscv_parse_add_implicit_subsets (riscv_parse_subset_t *rps)
+{
+  riscv_subset_t *subset = NULL;
+
+  /* Add the zicsr and zifencei only when the i's version less than 2.1.  */
+  if ((riscv_lookup_subset (rps->subset_list, "i", &subset))
+      && (subset->major_version < 2
+         || (subset->major_version == 2
+             && subset->minor_version < 1)))
+    {
+      riscv_parse_add_subset (rps, "zicsr",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+      riscv_parse_add_subset (rps, "zifencei",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+    }
+
+  if ((riscv_lookup_subset (rps->subset_list, "q", &subset)))
+    {
+      riscv_parse_add_subset (rps, "d",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+      riscv_parse_add_subset (rps, "f",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+      riscv_parse_add_subset (rps, "zicsr",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+    }
+  else if ((riscv_lookup_subset (rps->subset_list, "d", &subset)))
+    {
+      riscv_parse_add_subset (rps, "f",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+      riscv_parse_add_subset (rps, "zicsr",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+    }
+  else if ((riscv_lookup_subset (rps->subset_list, "f", &subset)))
+    riscv_parse_add_subset (rps, "zicsr",
+                           RISCV_UNKNOWN_VERSION,
+                           RISCV_UNKNOWN_VERSION, true);
+
+  if ((riscv_lookup_subset (rps->subset_list, "g", &subset)))
+    {
+      riscv_parse_add_subset (rps, "zicsr",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+      riscv_parse_add_subset (rps, "zifencei",
+                             RISCV_UNKNOWN_VERSION,
+                             RISCV_UNKNOWN_VERSION, true);
+    }
+}
+
+/* Function for parsing ISA string.
 
    Return Value:
      Return TRUE on success.
 
    Arguments:
-     `rps`: Hooks and status for parsing subset.
-     `arch`: Arch string.  */
+     `rps`: Hooks and status for parsing extensions.
+     `arch`: Full ISA string.  */
 
-bfd_boolean
+bool
 riscv_parse_subset (riscv_parse_subset_t *rps,
                    const char *arch)
 {
-  const char *p = arch;
+  riscv_subset_t *subset = NULL;
+  const char *p;
+  size_t i;
+  bool no_conflict = true;
+
+  for (p = arch; *p != '\0'; p++)
+    {
+      if (ISUPPER (*p))
+       {
+         rps->error_handler
+           (_("-march=%s: ISA string cannot contain uppercase letters"),
+            arch);
+         return false;
+       }
+    }
 
-  if (strncmp (p, "rv32", 4) == 0)
+  p = arch;
+  if (startswith (p, "rv32"))
     {
       *rps->xlen = 32;
       p += 4;
     }
-  else if (strncmp (p, "rv64", 4) == 0)
+  else if (startswith (p, "rv64"))
     {
       *rps->xlen = 64;
       p += 4;
     }
   else
     {
-      rps->error_handler ("-march=%s: ISA string must begin with rv32 or rv64",
-                         arch);
-      return FALSE;
+      /* ISA string shouldn't be NULL or empty here.  However,
+        it might be empty only when we failed to merge the ISA
+        string in the riscv_merge_attributes.  We have already
+        issued the correct error message in another side, so do
+        not issue this error when the ISA string is empty.  */
+      if (strlen (arch))
+       rps->error_handler (
+         _("-march=%s: ISA string must begin with rv32 or rv64"),
+         arch);
+      return false;
     }
 
+  /* Init the riscv_ext_order array to compare the order of extensions
+     quickly.  */
+  riscv_init_ext_order ();
+
   /* Parsing standard extension.  */
   p = riscv_parse_std_ext (rps, arch, p);
 
   if (p == NULL)
-    return FALSE;
-
-  /* Parsing non-standard extension.  */
-  p = riscv_parse_sv_or_non_std_ext (
-       rps, arch, p, "x", "non-standard extension");
-
-  if (p == NULL)
-    return FALSE;
-
-  /* Parsing supervisor extension.  */
-  p = riscv_parse_sv_or_non_std_ext (
-       rps, arch, p, "s", "supervisor extension");
+    return false;
 
-  if (p == NULL)
-    return FALSE;
-
-  /* Parsing non-standard supervisor extension.  */
-  p = riscv_parse_sv_or_non_std_ext (
-       rps, arch, p, "sx", "non-standard supervisor extension");
+  /* Parse the different classes of extensions in the specified order.  */
+  for (i = 0; i < ARRAY_SIZE (parse_config); ++i)
+    {
+      p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]);
 
-  if (p == NULL)
-    return FALSE;
+      if (p == NULL)
+       return false;
+    }
 
   if (*p != '\0')
     {
-      rps->error_handler ("-march=%s: unexpected ISA string at end: %s",
+      rps->error_handler (_("-march=%s: unexpected ISA string at end: %s"),
                          arch, p);
-      return FALSE;
+      return false;
     }
 
-  if (riscv_lookup_subset (rps->subset_list, "e")
-      && riscv_lookup_subset (rps->subset_list, "f"))
-    {
-      rps->error_handler ("-march=%s: rv32e does not support the `f' extension",
-                         arch);
-      return FALSE;
-    }
-
-  if (riscv_lookup_subset (rps->subset_list, "d")
-      && !riscv_lookup_subset (rps->subset_list, "f"))
-    {
-      rps->error_handler ("-march=%s: `d' extension requires `f' extension",
-                         arch);
-      return FALSE;
-    }
+  /* Finally add implicit extensions according to the current
+     extensions.  */
+  riscv_parse_add_implicit_subsets (rps);
 
-  if (riscv_lookup_subset (rps->subset_list, "q")
-      && !riscv_lookup_subset (rps->subset_list, "d"))
+  /* Check the conflicts.  */
+  if (riscv_lookup_subset (rps->subset_list, "e", &subset)
+      && riscv_lookup_subset (rps->subset_list, "f", &subset))
     {
-      rps->error_handler ("-march=%s: `q' extension requires `d' extension",
-                         arch);
-      return FALSE;
+      rps->error_handler
+       (_("-march=%s: rv32e does not support the `f' extension"),
+        arch);
+      no_conflict = false;
     }
-
-  if (riscv_lookup_subset (rps->subset_list, "q") && *rps->xlen < 64)
+  if (riscv_lookup_subset (rps->subset_list, "q", &subset)
+      && *rps->xlen < 64)
     {
-      rps->error_handler ("-march=%s: rv32 does not support the `q' extension",
-                         arch);
-      return FALSE;
+      rps->error_handler
+       (_("-march=%s: rv32 does not support the `q' extension"),
+        arch);
+      no_conflict = false;
     }
-  return TRUE;
+  return no_conflict;
 }
 
-/* Add new subset to list.  */
+/* Return the number of digits for the input.  */
 
-void
-riscv_add_subset (riscv_subset_list_t *subset_list,
-                 const char *subset,
-                 int major, int minor)
+size_t
+riscv_estimate_digit (unsigned num)
 {
-  riscv_subset_t *s = xmalloc (sizeof *s);
+  size_t digit = 0;
+  if (num == 0)
+    return 1;
 
-  if (subset_list->head == NULL)
-    subset_list->head = s;
+  for (digit = 0; num ; num /= 10)
+    digit++;
 
-  s->name = xstrdup (subset);
-  s->major_version = major;
-  s->minor_version = minor;
-  s->next = NULL;
-
-  if (subset_list->tail != NULL)
-    subset_list->tail->next = s;
-
-  subset_list->tail = s;
+  return digit;
 }
 
-/* Find subset in list without version checking, return NULL if not found.  */
+/* Auxiliary function to estimate string length of subset list.  */
 
-riscv_subset_t *
-riscv_lookup_subset (const riscv_subset_list_t *subset_list,
-                    const char *subset)
+static size_t
+riscv_estimate_arch_strlen1 (const riscv_subset_t *subset)
 {
-  return riscv_lookup_subset_version (
-          subset_list, subset,
-          RISCV_DONT_CARE_VERSION,
-          RISCV_DONT_CARE_VERSION);
+  if (subset == NULL)
+    return 6; /* For rv32/rv64/rv128 and string terminator.  */
+
+  return riscv_estimate_arch_strlen1 (subset->next)
+        + strlen (subset->name)
+        + riscv_estimate_digit (subset->major_version)
+        + 1 /* For version seperator 'p'.  */
+        + riscv_estimate_digit (subset->minor_version)
+        + 1 /* For underscore.  */;
 }
 
-/* Find subset in list with version checking, return NULL if not found.  */
+/* Estimate the string length of this subset list.  */
 
-riscv_subset_t *
-riscv_lookup_subset_version (const riscv_subset_list_t *subset_list,
-                            const char *subset,
-                            int major, int minor)
+static size_t
+riscv_estimate_arch_strlen (const riscv_subset_list_t *subset_list)
 {
-  riscv_subset_t *s;
-
-  for (s = subset_list->head; s != NULL; s = s->next)
-    if (strcasecmp (s->name, subset) == 0)
-      {
-       if ((major != RISCV_DONT_CARE_VERSION)
-           && (s->major_version != major))
-         return NULL;
-
-       if ((minor != RISCV_DONT_CARE_VERSION)
-           && (s->minor_version != minor))
-         return NULL;
+  return riscv_estimate_arch_strlen1 (subset_list->head);
+}
 
-       return s;
-      }
+/* Auxiliary function to convert subset info to string.  */
 
-  return NULL;
+static void
+riscv_arch_str1 (riscv_subset_t *subset,
+                char *attr_str, char *buf, size_t bufsz)
+{
+  const char *underline = "_";
+  riscv_subset_t *subset_t = subset;
+
+  if (subset_t == NULL)
+    return;
+
+  /* No underline between rvXX and i/e.  */
+  if ((strcasecmp (subset_t->name, "i") == 0)
+      || (strcasecmp (subset_t->name, "e") == 0))
+    underline = "";
+
+  snprintf (buf, bufsz, "%s%s%dp%d",
+           underline,
+           subset_t->name,
+           subset_t->major_version,
+           subset_t->minor_version);
+
+  strncat (attr_str, buf, bufsz);
+
+  /* Skip 'i' extension after 'e', or skip extensions which
+     versions are unknown.  */
+  while (subset_t->next
+        && ((strcmp (subset_t->name, "e") == 0
+             && strcmp (subset_t->next->name, "i") == 0)
+            || subset_t->next->major_version == RISCV_UNKNOWN_VERSION
+            || subset_t->next->minor_version == RISCV_UNKNOWN_VERSION))
+    subset_t = subset_t->next;
+
+  riscv_arch_str1 (subset_t->next, attr_str, buf, bufsz);
 }
 
-/* Release subset list.  */
+/* Convert subset information into string with explicit versions.  */
 
-void
-riscv_release_subset_list (riscv_subset_list_t *subset_list)
+char *
+riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
 {
-   while (subset_list->head != NULL)
-    {
-      riscv_subset_t *next = subset_list->head->next;
-      free ((void *)subset_list->head->name);
-      free (subset_list->head);
-      subset_list->head = next;
-    }
+  size_t arch_str_len = riscv_estimate_arch_strlen (subset);
+  char *attr_str = xmalloc (arch_str_len);
+  char *buf = xmalloc (arch_str_len);
 
-  subset_list->tail = NULL;
+  snprintf (attr_str, arch_str_len, "rv%u", xlen);
+
+  riscv_arch_str1 (subset->head, attr_str, buf, arch_str_len);
+  free (buf);
+
+  return attr_str;
 }
This page took 0.056563 seconds and 4 git commands to generate.