RISC-V: Dump objects according to the elf architecture attribute.

Message ID 1636374166-12326-1-git-send-email-nelson.chu@sifive.com
State New
Headers show
Series
  • RISC-V: Dump objects according to the elf architecture attribute.
Related show

Commit Message

Nelson Chu Nov. 8, 2021, 12:22 p.m.
For now we should always generate the elf architecture attribute both for
elf and linux toolchains, so that we could dump the objects correctly
according to the generated architecture string.  This patch resolves the
problem that we probably dump an object with c.nop instructions, but
in fact the c extension isn't allowed.  Consider the following case,

nelson@LAPTOP-QFSGI1F2:~/test$ cat temp.s
.option norvc
.option norelax
.text
add     a0, a0, a0
.byte   0x1
.balign 16
nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-as temp.s -o temp.o
nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-objdump -d temp.o

temp.o:     file format elf32-littleriscv

Disassembly of section .text:

00000000 <.text>:
   0:   00a50533                add     a0,a0,a0
   4:   01                      .byte   0x01
   5:   00                      .byte   0x00
   6:   0001                    nop
   8:   00000013                nop
   c:   00000013                nop
nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-readelf -A temp.o
Attribute Section: riscv
File Attributes
  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0"

The c.nop at address 0x6 is generated for alignment, but since the rvc isn't
allowed for this object, dump it as a c.nop instruction looks wrong.  After
applying this patch, I get the following result,

nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-objdump -d temp.o

temp.o:     file format elf32-littleriscv

Disassembly of section .text:

00000000 <.text>:
   0:   00a50533                add     a0,a0,a0
   4:   01                      .byte   0x01
   5:   00                      .byte   0x00
   6:   0001                    .2byte  0x1
   8:   00000013                nop
   c:   00000013                nop

For the current objdump, we dump data to .byte/.short/.word/.dword, and
dump the unknown or unsupported instructions to .2byte/.4byte/.8byte, which
respectively are 2, 4 and 8 bytes instructions.  Therefore, we shouldn't
dump the 0x0001 as a c.nop instruction in the above case, we should dump
it to .2byte 0x1 as a unknown instruction, since the rvc is disabled.

However, consider that some people may use the new objdump to dump the
old objects, which don't have any elf attributes, we also have a
default architecture string.  The default string can be set in the
bfd/elfxx-riscv.c:riscv_set_default_arch.

nelson@LAPTOP-QFSGI1F2:~/test$ cat temp.s
.option rvc
nop
nop
nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-as -mno-arch-attr temp.s -o temp.o
nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-objdump -d temp.o

temp.o:     file format elf32-littleriscv

Disassembly of section .text:

00000000 <.text>:
   0:   0001                    .2byte  0x1
   2:   0001                    .2byte  0x1

Since we are used to set default architecture string to rv64g without rvc,
the nops are dumped to .2byte.  This is not the same as before.  So maybe
we should set the default architecture string to rv64gc?

This patch pass the riscv-gnu-toolchain gcc/binutils regressions for
rv32emc-elf, rv32gc-linux, rv32i-elf, rv64gc-elf and rv64gc-linux
toolchains.  Also, tested by --enable-targets=all and can build
riscv-gdb successfully.

bfd/
	* elfnn-riscv.c (riscv_merge_arch_attr_info): Tidy the
	codes for riscv_parse_subset_t setting.
	* elfxx-riscv.c (riscv_get_default_ext_version): Updated.
	(riscv_subset_supports): Moved from gas/config/tc-riscv.c.
	(riscv_multi_subset_supports): Likewise.
	* elfxx-riscv.h: Added extern for riscv_subset_supports and
	riscv_multi_subset_supports.
gas/
	* config/tc-riscv.c (riscv_subset_supports): Moved to
	bfd/elfxx-riscv.c.
	(riscv_multi_subset_supports): Likewise.
	(riscv_rps_as): Defined for architectrue parser.
	(riscv_set_arch): Updated.
	(riscv_set_abi_by_arch): Likewise.
	(riscv_csr_address): Likewise.
	(reg_lookup_internal): Likewise.
	(riscv_ip): Likewise.
	(s_riscv_option): Updated.
	* testsuite/gas/riscv/mapping-04b.d: Updated.
	* testsuite/gas/riscv/mapping-norelax-03b.d: Likewise.
	* testsuite/gas/riscv/mapping-norelax-04b.d: Likewise.
opcodes/
	* riscv-dis.c: Include elfxx-riscv.h since we need the
	architecture parser.  Also removed the cpu-riscv.h, it
	is already included in elfxx-riscv.h.
	(default_isa_spec): Defined since the parser need this
	to set the default architecture string.
	(xlen): Moved out from riscv_disassemble_insn as a global
	variable, it is more convenient to initialize riscv_rps_dis.
	(riscv_subsets): Defined to recoed the supported
	extensions.
	(riscv_rps_dis): Defined for architectrue parser.
	(riscv_disassemble_insn): Call riscv_multi_subset_supports
	to make sure if the instructions are valid or not.
	(print_insn_riscv): Initialize the riscv_subsets by parsing
	the elf architectrue attribute.  Otherwise, let
	bfd/elfxx-riscv.c:riscv_set_default_arch to set the default
	string.
---
 bfd/elfnn-riscv.c                             |  27 ++-----
 bfd/elfxx-riscv.c                             |  69 +++++++++++++++-
 bfd/elfxx-riscv.h                             |   8 +-
 gas/config/tc-riscv.c                         | 110 ++++++--------------------
 gas/testsuite/gas/riscv/mapping-04b.d         |   4 +-
 gas/testsuite/gas/riscv/mapping-norelax-03b.d |   2 +-
 gas/testsuite/gas/riscv/mapping-norelax-04b.d |   4 +-
 opcodes/riscv-dis.c                           |  32 ++++++--
 8 files changed, 133 insertions(+), 123 deletions(-)

-- 
2.7.4

Comments

Nelson Chu Nov. 11, 2021, 9:16 a.m. | #1
Committed, but set the default architecture string to rv64gc when
dis-assembling objects, to keep the original behavior.

Thanks
Nelson

On Mon, Nov 8, 2021 at 8:22 PM Nelson Chu <nelson.chu@sifive.com> wrote:
>

> For now we should always generate the elf architecture attribute both for

> elf and linux toolchains, so that we could dump the objects correctly

> according to the generated architecture string.  This patch resolves the

> problem that we probably dump an object with c.nop instructions, but

> in fact the c extension isn't allowed.  Consider the following case,

>

> nelson@LAPTOP-QFSGI1F2:~/test$ cat temp.s

> .option norvc

> .option norelax

> .text

> add     a0, a0, a0

> .byte   0x1

> .balign 16

> nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-as temp.s -o temp.o

> nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-objdump -d temp.o

>

> temp.o:     file format elf32-littleriscv

>

> Disassembly of section .text:

>

> 00000000 <.text>:

>    0:   00a50533                add     a0,a0,a0

>    4:   01                      .byte   0x01

>    5:   00                      .byte   0x00

>    6:   0001                    nop

>    8:   00000013                nop

>    c:   00000013                nop

> nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-readelf -A temp.o

> Attribute Section: riscv

> File Attributes

>   Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0"

>

> The c.nop at address 0x6 is generated for alignment, but since the rvc isn't

> allowed for this object, dump it as a c.nop instruction looks wrong.  After

> applying this patch, I get the following result,

>

> nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-objdump -d temp.o

>

> temp.o:     file format elf32-littleriscv

>

> Disassembly of section .text:

>

> 00000000 <.text>:

>    0:   00a50533                add     a0,a0,a0

>    4:   01                      .byte   0x01

>    5:   00                      .byte   0x00

>    6:   0001                    .2byte  0x1

>    8:   00000013                nop

>    c:   00000013                nop

>

> For the current objdump, we dump data to .byte/.short/.word/.dword, and

> dump the unknown or unsupported instructions to .2byte/.4byte/.8byte, which

> respectively are 2, 4 and 8 bytes instructions.  Therefore, we shouldn't

> dump the 0x0001 as a c.nop instruction in the above case, we should dump

> it to .2byte 0x1 as a unknown instruction, since the rvc is disabled.

>

> However, consider that some people may use the new objdump to dump the

> old objects, which don't have any elf attributes, we also have a

> default architecture string.  The default string can be set in the

> bfd/elfxx-riscv.c:riscv_set_default_arch.

>

> nelson@LAPTOP-QFSGI1F2:~/test$ cat temp.s

> .option rvc

> nop

> nop

> nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-as -mno-arch-attr temp.s -o temp.o

> nelson@LAPTOP-QFSGI1F2:~/test$ ~/binutils-dev/build-elf32-upstream/build-install/bin/riscv32-unknown-elf-objdump -d temp.o

>

> temp.o:     file format elf32-littleriscv

>

> Disassembly of section .text:

>

> 00000000 <.text>:

>    0:   0001                    .2byte  0x1

>    2:   0001                    .2byte  0x1

>

> Since we are used to set default architecture string to rv64g without rvc,

> the nops are dumped to .2byte.  This is not the same as before.  So maybe

> we should set the default architecture string to rv64gc?

>

> This patch pass the riscv-gnu-toolchain gcc/binutils regressions for

> rv32emc-elf, rv32gc-linux, rv32i-elf, rv64gc-elf and rv64gc-linux

> toolchains.  Also, tested by --enable-targets=all and can build

> riscv-gdb successfully.

>

> bfd/

>         * elfnn-riscv.c (riscv_merge_arch_attr_info): Tidy the

>         codes for riscv_parse_subset_t setting.

>         * elfxx-riscv.c (riscv_get_default_ext_version): Updated.

>         (riscv_subset_supports): Moved from gas/config/tc-riscv.c.

>         (riscv_multi_subset_supports): Likewise.

>         * elfxx-riscv.h: Added extern for riscv_subset_supports and

>         riscv_multi_subset_supports.

> gas/

>         * config/tc-riscv.c (riscv_subset_supports): Moved to

>         bfd/elfxx-riscv.c.

>         (riscv_multi_subset_supports): Likewise.

>         (riscv_rps_as): Defined for architectrue parser.

>         (riscv_set_arch): Updated.

>         (riscv_set_abi_by_arch): Likewise.

>         (riscv_csr_address): Likewise.

>         (reg_lookup_internal): Likewise.

>         (riscv_ip): Likewise.

>         (s_riscv_option): Updated.

>         * testsuite/gas/riscv/mapping-04b.d: Updated.

>         * testsuite/gas/riscv/mapping-norelax-03b.d: Likewise.

>         * testsuite/gas/riscv/mapping-norelax-04b.d: Likewise.

> opcodes/

>         * riscv-dis.c: Include elfxx-riscv.h since we need the

>         architecture parser.  Also removed the cpu-riscv.h, it

>         is already included in elfxx-riscv.h.

>         (default_isa_spec): Defined since the parser need this

>         to set the default architecture string.

>         (xlen): Moved out from riscv_disassemble_insn as a global

>         variable, it is more convenient to initialize riscv_rps_dis.

>         (riscv_subsets): Defined to recoed the supported

>         extensions.

>         (riscv_rps_dis): Defined for architectrue parser.

>         (riscv_disassemble_insn): Call riscv_multi_subset_supports

>         to make sure if the instructions are valid or not.

>         (print_insn_riscv): Initialize the riscv_subsets by parsing

>         the elf architectrue attribute.  Otherwise, let

>         bfd/elfxx-riscv.c:riscv_set_default_arch to set the default

>         string.

> ---

>  bfd/elfnn-riscv.c                             |  27 ++-----

>  bfd/elfxx-riscv.c                             |  69 +++++++++++++++-

>  bfd/elfxx-riscv.h                             |   8 +-

>  gas/config/tc-riscv.c                         | 110 ++++++--------------------

>  gas/testsuite/gas/riscv/mapping-04b.d         |   4 +-

>  gas/testsuite/gas/riscv/mapping-norelax-03b.d |   2 +-

>  gas/testsuite/gas/riscv/mapping-norelax-04b.d |   4 +-

>  opcodes/riscv-dis.c                           |  32 ++++++--

>  8 files changed, 133 insertions(+), 123 deletions(-)

>

> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c

> index 2bae1e9..36cbf1e 100644

> --- a/bfd/elfnn-riscv.c

> +++ b/bfd/elfnn-riscv.c

> @@ -3574,37 +3574,22 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)

>    merged_subsets.head = NULL;

>    merged_subsets.tail = NULL;

>

> -  riscv_parse_subset_t rpe_in;

> -  riscv_parse_subset_t rpe_out;

> -

> -  /* Only assembler needs to check the default version of ISA, so just set

> -     the rpe_in.get_default_version and rpe_out.get_default_version to NULL.  */

> -  rpe_in.subset_list = &in_subsets;

> -  rpe_in.error_handler = _bfd_error_handler;

> -  rpe_in.xlen = &xlen_in;

> -  rpe_in.isa_spec = ISA_SPEC_CLASS_NONE;

> -  rpe_in.check_unknown_prefixed_ext = false;

> -

> -  rpe_out.subset_list = &out_subsets;

> -  rpe_out.error_handler = _bfd_error_handler;

> -  rpe_out.xlen = &xlen_out;

> -  rpe_out.isa_spec = ISA_SPEC_CLASS_NONE;

> -  rpe_out.check_unknown_prefixed_ext = false;

> +  riscv_parse_subset_t riscv_rps_ld_in =

> +    {&in_subsets, _bfd_error_handler, &xlen_in, NULL, false};

> +  riscv_parse_subset_t riscv_rps_ld_out =

> +    {&out_subsets, _bfd_error_handler, &xlen_out, NULL, false};

>

>    if (in_arch == NULL && out_arch == NULL)

>      return NULL;

> -

>    if (in_arch == NULL && out_arch != NULL)

>      return out_arch;

> -

>    if (in_arch != NULL && out_arch == NULL)

>      return in_arch;

>

>    /* Parse subset from ISA string.  */

> -  if (!riscv_parse_subset (&rpe_in, in_arch))

> +  if (!riscv_parse_subset (&riscv_rps_ld_in, in_arch))

>      return NULL;

> -

> -  if (!riscv_parse_subset (&rpe_out, out_arch))

> +  if (!riscv_parse_subset (&riscv_rps_ld_out, out_arch))

>      return NULL;

>

>    /* Checking XLEN.  */

> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c

> index 65bb1ca..3ffbaad 100644

> --- a/bfd/elfxx-riscv.c

> +++ b/bfd/elfxx-riscv.c

> @@ -1418,12 +1418,14 @@ riscv_add_subset (riscv_subset_list_t *subset_list,

>  /* Get the default versions from the riscv_supported_*ext tables.  */

>

>  static void

> -riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,

> +riscv_get_default_ext_version (enum riscv_spec_class *default_isa_spec,

>                                const char *name,

>                                int *major_version,

>                                int *minor_version)

>  {

> -  if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)

> +  if (name == NULL

> +      || default_isa_spec == NULL

> +      || *default_isa_spec == ISA_SPEC_CLASS_NONE)

>      return;

>

>    struct riscv_supported_ext *table = NULL;

> @@ -1445,7 +1447,7 @@ riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,

>      {

>        if (strcmp (table[i].name, name) == 0

>           && (table[i].isa_spec_class == ISA_SPEC_CLASS_DRAFT

> -             || table[i].isa_spec_class == default_isa_spec))

> +             || table[i].isa_spec_class == *default_isa_spec))

>         {

>           *major_version = table[i].major_version;

>           *minor_version = table[i].minor_version;

> @@ -2095,3 +2097,64 @@ riscv_update_subset (riscv_parse_subset_t *rps,

>    riscv_parse_add_implicit_subsets (rps);

>    return riscv_parse_check_conflicts (rps);

>  }

> +

> +/* Check if the FEATURE subset is supported or not in the subset list.

> +   Return true if it is supported; Otherwise, return false.  */

> +

> +bool

> +riscv_subset_supports (riscv_parse_subset_t *rps,

> +                      const char *feature)

> +{

> +  struct riscv_subset_t *subset;

> +  return riscv_lookup_subset (rps->subset_list, feature, &subset);

> +}

> +

> +/* Each instuction is belonged to an instruction class INSN_CLASS_*.

> +   Call riscv_subset_supports to make sure if the instuction is valid.  */

> +

> +bool

> +riscv_multi_subset_supports (riscv_parse_subset_t *rps,

> +                            enum riscv_insn_class insn_class)

> +{

> +  switch (insn_class)

> +    {

> +    case INSN_CLASS_I:

> +      return riscv_subset_supports (rps, "i");

> +    case INSN_CLASS_ZICSR:

> +      return riscv_subset_supports (rps, "zicsr");

> +    case INSN_CLASS_ZIFENCEI:

> +      return riscv_subset_supports (rps, "zifencei");

> +    case INSN_CLASS_ZIHINTPAUSE:

> +      return riscv_subset_supports (rps, "zihintpause");

> +    case INSN_CLASS_M:

> +      return riscv_subset_supports (rps, "m");

> +    case INSN_CLASS_A:

> +      return riscv_subset_supports (rps, "a");

> +    case INSN_CLASS_F:

> +      return riscv_subset_supports (rps, "f");

> +    case INSN_CLASS_D:

> +      return riscv_subset_supports (rps, "d");

> +    case INSN_CLASS_Q:

> +      return riscv_subset_supports (rps, "q");

> +    case INSN_CLASS_C:

> +      return riscv_subset_supports (rps, "c");

> +    case INSN_CLASS_F_AND_C:

> +      return (riscv_subset_supports (rps, "f")

> +             && riscv_subset_supports (rps, "c"));

> +    case INSN_CLASS_D_AND_C:

> +      return (riscv_subset_supports (rps, "d")

> +             && riscv_subset_supports (rps, "c"));

> +    case INSN_CLASS_ZBA:

> +      return riscv_subset_supports (rps, "zba");

> +    case INSN_CLASS_ZBB:

> +      return riscv_subset_supports (rps, "zbb");

> +    case INSN_CLASS_ZBC:

> +      return riscv_subset_supports (rps, "zbc");

> +    case INSN_CLASS_ZBS:

> +      return riscv_subset_supports (rps, "zbs");

> +    default:

> +      rps->error_handler

> +        (_("internal: unreachable INSN_CLASS_*"));

> +      return false;

> +    }

> +}

> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h

> index 17620fd..8de9adc 100644

> --- a/bfd/elfxx-riscv.h

> +++ b/bfd/elfxx-riscv.h

> @@ -72,7 +72,7 @@ typedef struct

>    void (*error_handler) (const char *,

>                          ...) ATTRIBUTE_PRINTF_1;

>    unsigned *xlen;

> -  enum riscv_spec_class isa_spec;

> +  enum riscv_spec_class *isa_spec;

>    bool check_unknown_prefixed_ext;

>  } riscv_parse_subset_t;

>

> @@ -95,6 +95,12 @@ riscv_compare_subsets (const char *, const char *);

>  extern bool

>  riscv_update_subset (riscv_parse_subset_t *, const char *, bool);

>

> +extern bool

> +riscv_subset_supports (riscv_parse_subset_t *, const char *);

> +

> +extern bool

> +riscv_multi_subset_supports (riscv_parse_subset_t *, enum riscv_insn_class);

> +

>  extern void

>  bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);

>  extern void

> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c

> index 90d960a..8cea72a 100644

> --- a/gas/config/tc-riscv.c

> +++ b/gas/config/tc-riscv.c

> @@ -234,77 +234,20 @@ riscv_set_rvc (bool rvc_value)

>     -march option, the elf architecture attributes, and the --with-arch

>     configure option.  */

>  static riscv_subset_list_t riscv_subsets;

> -

> -/* Check if the FEATURE subset is supported or not in the subset list.

> -   Return true if it is supported; Otherwise, return false.  */

> -

> -static bool

> -riscv_subset_supports (const char *feature)

> -{

> -  struct riscv_subset_t *subset;

> -  return riscv_lookup_subset (&riscv_subsets, feature, &subset);

> -}

> -

> -/* Each instuction is belonged to an instruction class INSN_CLASS_*.

> -   Call riscv_subset_supports to make sure if the instuction is valid.  */

> -

> -static bool

> -riscv_multi_subset_supports (enum riscv_insn_class insn_class)

> +static riscv_parse_subset_t riscv_rps_as =

>  {

> -  switch (insn_class)

> -    {

> -    case INSN_CLASS_I:

> -      return riscv_subset_supports ("i");

> -    case INSN_CLASS_ZICSR:

> -      return riscv_subset_supports ("zicsr");

> -    case INSN_CLASS_ZIFENCEI:

> -      return riscv_subset_supports ("zifencei");

> -    case INSN_CLASS_ZIHINTPAUSE:

> -      return riscv_subset_supports ("zihintpause");

> -    case INSN_CLASS_M:

> -      return riscv_subset_supports ("m");

> -    case INSN_CLASS_A:

> -      return riscv_subset_supports ("a");

> -    case INSN_CLASS_F:

> -      return riscv_subset_supports ("f");

> -    case INSN_CLASS_D:

> -      return riscv_subset_supports ("d");

> -    case INSN_CLASS_Q:

> -      return riscv_subset_supports ("q");

> -    case INSN_CLASS_C:

> -      return riscv_subset_supports ("c");

> -    case INSN_CLASS_F_AND_C:

> -      return (riscv_subset_supports ("f")

> -             && riscv_subset_supports ("c"));

> -    case INSN_CLASS_D_AND_C:

> -      return (riscv_subset_supports ("d")

> -             && riscv_subset_supports ("c"));

> -    case INSN_CLASS_ZBA:

> -      return riscv_subset_supports ("zba");

> -    case INSN_CLASS_ZBB:

> -      return riscv_subset_supports ("zbb");

> -    case INSN_CLASS_ZBC:

> -      return riscv_subset_supports ("zbc");

> -    case INSN_CLASS_ZBS:

> -      return riscv_subset_supports ("zbs");

> -    default:

> -      as_fatal ("internal: unreachable");

> -      return false;

> -    }

> -}

> +  &riscv_subsets,      /* subset_list.  */

> +  as_bad,              /* error_handler.  */

> +  &xlen,               /* xlen.  */

> +  &default_isa_spec,   /* isa_spec.  */

> +  true,                        /* check_unknown_prefixed_ext.  */

> +};

>

>  /* Set which ISA and extensions are available.  */

>

>  static void

>  riscv_set_arch (const char *s)

>  {

> -  riscv_parse_subset_t rps;

> -  rps.subset_list = &riscv_subsets;

> -  rps.error_handler = as_bad;

> -  rps.xlen = &xlen;

> -  rps.isa_spec = default_isa_spec;

> -  rps.check_unknown_prefixed_ext = true;

> -

>    if (s != NULL && strcmp (s, "") == 0)

>      {

>        as_bad (_("the architecture string of -march and elf architecture "

> @@ -313,10 +256,10 @@ riscv_set_arch (const char *s)

>      }

>

>    riscv_release_subset_list (&riscv_subsets);

> -  riscv_parse_subset (&rps, s);

> +  riscv_parse_subset (&riscv_rps_as, s);

>

>    riscv_set_rvc (false);

> -  if (riscv_subset_supports ("c"))

> +  if (riscv_subset_supports (&riscv_rps_as, "c"))

>      riscv_set_rvc (true);

>  }

>

> @@ -341,11 +284,11 @@ riscv_set_abi_by_arch (void)

>  {

>    if (!explicit_mabi)

>      {

> -      if (riscv_subset_supports ("q"))

> +      if (riscv_subset_supports (&riscv_rps_as, "q"))

>         riscv_set_abi (xlen, FLOAT_ABI_QUAD, false);

> -      else if (riscv_subset_supports ("d"))

> +      else if (riscv_subset_supports (&riscv_rps_as, "d"))

>         riscv_set_abi (xlen, FLOAT_ABI_DOUBLE, false);

> -      else if (riscv_subset_supports ("e"))

> +      else if (riscv_subset_supports (&riscv_rps_as, "e"))

>         riscv_set_abi (xlen, FLOAT_ABI_SOFT, true);

>        else

>         riscv_set_abi (xlen, FLOAT_ABI_SOFT, false);

> @@ -358,19 +301,19 @@ riscv_set_abi_by_arch (void)

>        else if (abi_xlen < xlen)

>         as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen);

>

> -      if (riscv_subset_supports ("e") && !rve_abi)

> +      if (riscv_subset_supports (&riscv_rps_as, "e") && !rve_abi)

>         as_bad ("only the ilp32e ABI is supported for e extension");

>

>        if (float_abi == FLOAT_ABI_SINGLE

> -         && !riscv_subset_supports ("f"))

> +         && !riscv_subset_supports (&riscv_rps_as, "f"))

>         as_bad ("ilp32f/lp64f ABI can't be used when f extension "

>                 "isn't supported");

>        else if (float_abi == FLOAT_ABI_DOUBLE

> -              && !riscv_subset_supports ("d"))

> +              && !riscv_subset_supports (&riscv_rps_as, "d"))

>         as_bad ("ilp32d/lp64d ABI can't be used when d extension "

>                 "isn't supported");

>        else if (float_abi == FLOAT_ABI_QUAD

> -              && !riscv_subset_supports ("q"))

> +              && !riscv_subset_supports (&riscv_rps_as, "q"))

>         as_bad ("ilp32q/lp64q ABI can't be used when q extension "

>                 "isn't supported");

>      }

> @@ -923,13 +866,13 @@ riscv_csr_address (const char *csr_name,

>    switch (csr_class)

>      {

>      case CSR_CLASS_I:

> -      result = riscv_subset_supports ("i");

> +      result = riscv_subset_supports (&riscv_rps_as, "i");

>        break;

>      case CSR_CLASS_I_32:

> -      result = (xlen == 32 && riscv_subset_supports ("i"));

> +      result = (xlen == 32 && riscv_subset_supports (&riscv_rps_as, "i"));

>        break;

>      case CSR_CLASS_F:

> -      result = riscv_subset_supports ("f");

> +      result = riscv_subset_supports (&riscv_rps_as, "f");

>        need_check_version = false;

>        break;

>      case CSR_CLASS_DEBUG:

> @@ -995,7 +938,7 @@ reg_lookup_internal (const char *s, enum reg_class class)

>    if (r == NULL || DECODE_REG_CLASS (r) != class)

>      return -1;

>

> -  if (riscv_subset_supports ("e")

> +  if (riscv_subset_supports (&riscv_rps_as, "e")

>        && class == RCLASS_GPR

>        && DECODE_REG_NUM (r) > 15)

>      return -1;

> @@ -2061,7 +2004,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,

>        if ((insn->xlen_requirement != 0) && (xlen != insn->xlen_requirement))

>         continue;

>

> -      if (!riscv_multi_subset_supports (insn->insn_class))

> +      if (!riscv_multi_subset_supports (&riscv_rps_as, insn->insn_class))

>         continue;

>

>        create_insn (ip, insn);

> @@ -3364,21 +3307,14 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)

>    ch = *input_line_pointer;

>    *input_line_pointer = '\0';

>

> -  riscv_parse_subset_t rps;

> -  rps.subset_list = &riscv_subsets;

> -  rps.error_handler = as_bad;

> -  rps.xlen = &xlen;

> -  rps.isa_spec = default_isa_spec;

> -  rps.check_unknown_prefixed_ext = true;

> -

>    if (strcmp (name, "rvc") == 0)

>      {

> -      riscv_update_subset (&rps, "c", false);

> +      riscv_update_subset (&riscv_rps_as, "c", false);

>        riscv_set_rvc (true);

>      }

>    else if (strcmp (name, "norvc") == 0)

>      {

> -      riscv_update_subset (&rps, "c", true);

> +      riscv_update_subset (&riscv_rps_as, "c", true);

>        riscv_set_rvc (false);

>      }

>    else if (strcmp (name, "pic") == 0)

> diff --git a/gas/testsuite/gas/riscv/mapping-04b.d b/gas/testsuite/gas/riscv/mapping-04b.d

> index 9735498..54bd0af 100644

> --- a/gas/testsuite/gas/riscv/mapping-04b.d

> +++ b/gas/testsuite/gas/riscv/mapping-04b.d

> @@ -18,6 +18,6 @@ Disassembly of section .text:

>  [      ]+19:[  ]+20022002[     ]+.word[        ]+0x20022002

>  [      ]+1d:[  ]+2002[         ]+.short[       ]+0x2002

>  [      ]+1f:[  ]+00b585b3[     ]+add[  ]+a1,a1,a1

> -[      ]+23:[  ]+0000[         ]+unimp

> -[      ]+25:[  ]+0000[         ]+unimp

> +[      ]+23:[  ]+0000[         ]+.2byte[       ]+0x0

> +[      ]+25:[  ]+0000[         ]+.2byte[       ]+0x0

>  #...

> diff --git a/gas/testsuite/gas/riscv/mapping-norelax-03b.d b/gas/testsuite/gas/riscv/mapping-norelax-03b.d

> index ad88888..9e77735 100644

> --- a/gas/testsuite/gas/riscv/mapping-norelax-03b.d

> +++ b/gas/testsuite/gas/riscv/mapping-norelax-03b.d

> @@ -17,7 +17,7 @@ Disassembly of section .text:

>  [      ]+18:[  ]+00000302[     ]+.word[        ]+0x00000302

>  [      ]+1c:[  ]+00[   ]+.byte[        ]+0x00

>  [      ]+1d:[  ]+00[   ]+.byte[        ]+0x00

> -[      ]+1e:[  ]+0001[         ]+nop

> +[      ]+1e:[  ]+0001[         ]+.2byte[       ]+0x1

>  [      ]+20:[  ]+00000005[     ]+.word[        ]+0x00000005

>  [      ]+24:[  ]+00000013[     ]+nop

>  [      ]+28:[  ]+00000013[     ]+nop

> diff --git a/gas/testsuite/gas/riscv/mapping-norelax-04b.d b/gas/testsuite/gas/riscv/mapping-norelax-04b.d

> index 824a898..be668f2 100644

> --- a/gas/testsuite/gas/riscv/mapping-norelax-04b.d

> +++ b/gas/testsuite/gas/riscv/mapping-norelax-04b.d

> @@ -13,12 +13,12 @@ Disassembly of section .text:

>  [      ]+8:[   ]+00000001[     ]+.word[        ]+0x00000001

>  [      ]+c:[   ]+00[   ]+.byte[        ]+0x00

>  [      ]+d:[   ]+00[   ]+.byte[        ]+0x00

> -[      ]+e:[   ]+0001[         ]+nop

> +[      ]+e:[   ]+0001[         ]+.2byte[       ]+0x1

>  [      ]+10:[  ]+00a50533[     ]+add[  ]+a0,a0,a0

>  [      ]+14:[  ]+20022002[     ]+.word[        ]+0x20022002

>  [      ]+18:[  ]+20022002[     ]+.word[        ]+0x20022002

>  [      ]+1c:[  ]+2002[         ]+.short[       ]+0x2002

>  [      ]+1e:[  ]+00b585b3[     ]+add[  ]+a1,a1,a1

> -[      ]+22:[  ]+0001[         ]+nop

> +[      ]+22:[  ]+0001[         ]+.2byte[       ]+0x1

>  [      ]+24:[  ]+00000013[     ]+nop

>  #...

> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c

> index 1a09440..814c959 100644

> --- a/opcodes/riscv-dis.c

> +++ b/opcodes/riscv-dis.c

> @@ -27,13 +27,26 @@

>  #include "opintl.h"

>  #include "elf-bfd.h"

>  #include "elf/riscv.h"

> -#include "cpu-riscv.h"

> +#include "elfxx-riscv.h"

>

>  #include <stdint.h>

>  #include <ctype.h>

>

> +static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;

>  static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;

>

> +unsigned xlen = 0;

> +

> +static riscv_subset_list_t riscv_subsets;

> +static riscv_parse_subset_t riscv_rps_dis =

> +{

> +  &riscv_subsets,      /* subset_list.  */

> +  opcodes_error_handler,/* error_handler.  */

> +  &xlen,               /* xlen.  */

> +  &default_isa_spec,   /* isa_spec.  */

> +  false,               /* check_unknown_prefixed_ext.  */

> +};

> +

>  struct riscv_private_data

>  {

>    bfd_vma gp;

> @@ -502,8 +515,6 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)

>    op = riscv_hash[OP_HASH_IDX (word)];

>    if (op != NULL)

>      {

> -      unsigned xlen = 0;

> -

>        /* If XLEN is not known, get its value from the ELF class.  */

>        if (info->mach == bfd_mach_riscv64)

>         xlen = 64;

> @@ -527,6 +538,9 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)

>           if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))

>             continue;

>

> +         if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))

> +           continue;

> +

>           /* It's a match.  */

>           (*info->fprintf_func) (info->stream, "%s", op->name);

>           print_insn_args (op->args, word, memaddr, info);

> @@ -852,11 +866,13 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)

>  disassembler_ftype

>  riscv_get_disassembler (bfd *abfd)

>  {

> +  const char *default_arch = NULL;

> +

>    if (abfd)

>      {

>        const struct elf_backend_data *ebd = get_elf_backend_data (abfd);

>        if (ebd)

> -        {

> +       {

>           const char *sec_name = ebd->obj_attrs_section;

>           if (bfd_get_section_by_name (abfd, sec_name) != NULL)

>             {

> @@ -868,10 +884,14 @@ riscv_get_disassembler (bfd *abfd)

>                                                       attr[Tag_b].i,

>                                                       attr[Tag_c].i,

>                                                       &default_priv_spec);

> +             default_arch = attr[Tag_RISCV_arch].s;

>             }

> -        }

> +       }

>      }

> -   return print_insn_riscv;

> +

> +  riscv_release_subset_list (&riscv_subsets);

> +  riscv_parse_subset (&riscv_rps_dis, default_arch);

> +  return print_insn_riscv;

>  }

>

>  /* Prevent use of the fake labels that are generated as part of the DWARF

> --

> 2.7.4

>

Patch

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 2bae1e9..36cbf1e 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3574,37 +3574,22 @@  riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
   merged_subsets.head = NULL;
   merged_subsets.tail = NULL;
 
-  riscv_parse_subset_t rpe_in;
-  riscv_parse_subset_t rpe_out;
-
-  /* Only assembler needs to check the default version of ISA, so just set
-     the rpe_in.get_default_version and rpe_out.get_default_version to NULL.  */
-  rpe_in.subset_list = &in_subsets;
-  rpe_in.error_handler = _bfd_error_handler;
-  rpe_in.xlen = &xlen_in;
-  rpe_in.isa_spec = ISA_SPEC_CLASS_NONE;
-  rpe_in.check_unknown_prefixed_ext = false;
-
-  rpe_out.subset_list = &out_subsets;
-  rpe_out.error_handler = _bfd_error_handler;
-  rpe_out.xlen = &xlen_out;
-  rpe_out.isa_spec = ISA_SPEC_CLASS_NONE;
-  rpe_out.check_unknown_prefixed_ext = false;
+  riscv_parse_subset_t riscv_rps_ld_in =
+    {&in_subsets, _bfd_error_handler, &xlen_in, NULL, false};
+  riscv_parse_subset_t riscv_rps_ld_out =
+    {&out_subsets, _bfd_error_handler, &xlen_out, NULL, false};
 
   if (in_arch == NULL && out_arch == NULL)
     return NULL;
-
   if (in_arch == NULL && out_arch != NULL)
     return out_arch;
-
   if (in_arch != NULL && out_arch == NULL)
     return in_arch;
 
   /* Parse subset from ISA string.  */
-  if (!riscv_parse_subset (&rpe_in, in_arch))
+  if (!riscv_parse_subset (&riscv_rps_ld_in, in_arch))
     return NULL;
-
-  if (!riscv_parse_subset (&rpe_out, out_arch))
+  if (!riscv_parse_subset (&riscv_rps_ld_out, out_arch))
     return NULL;
 
   /* Checking XLEN.  */
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 65bb1ca..3ffbaad 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1418,12 +1418,14 @@  riscv_add_subset (riscv_subset_list_t *subset_list,
 /* Get the default versions from the riscv_supported_*ext tables.  */
 
 static void
-riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,
+riscv_get_default_ext_version (enum riscv_spec_class *default_isa_spec,
 			       const char *name,
 			       int *major_version,
 			       int *minor_version)
 {
-  if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
+  if (name == NULL
+      || default_isa_spec == NULL
+      || *default_isa_spec == ISA_SPEC_CLASS_NONE)
     return;
 
   struct riscv_supported_ext *table = NULL;
@@ -1445,7 +1447,7 @@  riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,
     {
       if (strcmp (table[i].name, name) == 0
 	  && (table[i].isa_spec_class == ISA_SPEC_CLASS_DRAFT
-	      || table[i].isa_spec_class == default_isa_spec))
+	      || table[i].isa_spec_class == *default_isa_spec))
 	{
 	  *major_version = table[i].major_version;
 	  *minor_version = table[i].minor_version;
@@ -2095,3 +2097,64 @@  riscv_update_subset (riscv_parse_subset_t *rps,
   riscv_parse_add_implicit_subsets (rps);
   return riscv_parse_check_conflicts (rps);
 }
+
+/* Check if the FEATURE subset is supported or not in the subset list.
+   Return true if it is supported; Otherwise, return false.  */
+
+bool
+riscv_subset_supports (riscv_parse_subset_t *rps,
+		       const char *feature)
+{
+  struct riscv_subset_t *subset;
+  return riscv_lookup_subset (rps->subset_list, feature, &subset);
+}
+
+/* Each instuction is belonged to an instruction class INSN_CLASS_*.
+   Call riscv_subset_supports to make sure if the instuction is valid.  */
+
+bool
+riscv_multi_subset_supports (riscv_parse_subset_t *rps,
+			     enum riscv_insn_class insn_class)
+{
+  switch (insn_class)
+    {
+    case INSN_CLASS_I:
+      return riscv_subset_supports (rps, "i");
+    case INSN_CLASS_ZICSR:
+      return riscv_subset_supports (rps, "zicsr");
+    case INSN_CLASS_ZIFENCEI:
+      return riscv_subset_supports (rps, "zifencei");
+    case INSN_CLASS_ZIHINTPAUSE:
+      return riscv_subset_supports (rps, "zihintpause");
+    case INSN_CLASS_M:
+      return riscv_subset_supports (rps, "m");
+    case INSN_CLASS_A:
+      return riscv_subset_supports (rps, "a");
+    case INSN_CLASS_F:
+      return riscv_subset_supports (rps, "f");
+    case INSN_CLASS_D:
+      return riscv_subset_supports (rps, "d");
+    case INSN_CLASS_Q:
+      return riscv_subset_supports (rps, "q");
+    case INSN_CLASS_C:
+      return riscv_subset_supports (rps, "c");
+    case INSN_CLASS_F_AND_C:
+      return (riscv_subset_supports (rps, "f")
+	      && riscv_subset_supports (rps, "c"));
+    case INSN_CLASS_D_AND_C:
+      return (riscv_subset_supports (rps, "d")
+	      && riscv_subset_supports (rps, "c"));
+    case INSN_CLASS_ZBA:
+      return riscv_subset_supports (rps, "zba");
+    case INSN_CLASS_ZBB:
+      return riscv_subset_supports (rps, "zbb");
+    case INSN_CLASS_ZBC:
+      return riscv_subset_supports (rps, "zbc");
+    case INSN_CLASS_ZBS:
+      return riscv_subset_supports (rps, "zbs");
+    default:
+      rps->error_handler
+        (_("internal: unreachable INSN_CLASS_*"));
+      return false;
+    }
+}
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 17620fd..8de9adc 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -72,7 +72,7 @@  typedef struct
   void (*error_handler) (const char *,
 			 ...) ATTRIBUTE_PRINTF_1;
   unsigned *xlen;
-  enum riscv_spec_class isa_spec;
+  enum riscv_spec_class *isa_spec;
   bool check_unknown_prefixed_ext;
 } riscv_parse_subset_t;
 
@@ -95,6 +95,12 @@  riscv_compare_subsets (const char *, const char *);
 extern bool
 riscv_update_subset (riscv_parse_subset_t *, const char *, bool);
 
+extern bool
+riscv_subset_supports (riscv_parse_subset_t *, const char *);
+
+extern bool
+riscv_multi_subset_supports (riscv_parse_subset_t *, enum riscv_insn_class);
+
 extern void
 bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
 extern void
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 90d960a..8cea72a 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -234,77 +234,20 @@  riscv_set_rvc (bool rvc_value)
    -march option, the elf architecture attributes, and the --with-arch
    configure option.  */
 static riscv_subset_list_t riscv_subsets;
-
-/* Check if the FEATURE subset is supported or not in the subset list.
-   Return true if it is supported; Otherwise, return false.  */
-
-static bool
-riscv_subset_supports (const char *feature)
-{
-  struct riscv_subset_t *subset;
-  return riscv_lookup_subset (&riscv_subsets, feature, &subset);
-}
-
-/* Each instuction is belonged to an instruction class INSN_CLASS_*.
-   Call riscv_subset_supports to make sure if the instuction is valid.  */
-
-static bool
-riscv_multi_subset_supports (enum riscv_insn_class insn_class)
+static riscv_parse_subset_t riscv_rps_as =
 {
-  switch (insn_class)
-    {
-    case INSN_CLASS_I:
-      return riscv_subset_supports ("i");
-    case INSN_CLASS_ZICSR:
-      return riscv_subset_supports ("zicsr");
-    case INSN_CLASS_ZIFENCEI:
-      return riscv_subset_supports ("zifencei");
-    case INSN_CLASS_ZIHINTPAUSE:
-      return riscv_subset_supports ("zihintpause");
-    case INSN_CLASS_M:
-      return riscv_subset_supports ("m");
-    case INSN_CLASS_A:
-      return riscv_subset_supports ("a");
-    case INSN_CLASS_F:
-      return riscv_subset_supports ("f");
-    case INSN_CLASS_D:
-      return riscv_subset_supports ("d");
-    case INSN_CLASS_Q:
-      return riscv_subset_supports ("q");
-    case INSN_CLASS_C:
-      return riscv_subset_supports ("c");
-    case INSN_CLASS_F_AND_C:
-      return (riscv_subset_supports ("f")
-	      && riscv_subset_supports ("c"));
-    case INSN_CLASS_D_AND_C:
-      return (riscv_subset_supports ("d")
-	      && riscv_subset_supports ("c"));
-    case INSN_CLASS_ZBA:
-      return riscv_subset_supports ("zba");
-    case INSN_CLASS_ZBB:
-      return riscv_subset_supports ("zbb");
-    case INSN_CLASS_ZBC:
-      return riscv_subset_supports ("zbc");
-    case INSN_CLASS_ZBS:
-      return riscv_subset_supports ("zbs");
-    default:
-      as_fatal ("internal: unreachable");
-      return false;
-    }
-}
+  &riscv_subsets,	/* subset_list.  */
+  as_bad,		/* error_handler.  */
+  &xlen,		/* xlen.  */
+  &default_isa_spec,	/* isa_spec.  */
+  true,			/* check_unknown_prefixed_ext.  */
+};
 
 /* Set which ISA and extensions are available.  */
 
 static void
 riscv_set_arch (const char *s)
 {
-  riscv_parse_subset_t rps;
-  rps.subset_list = &riscv_subsets;
-  rps.error_handler = as_bad;
-  rps.xlen = &xlen;
-  rps.isa_spec = default_isa_spec;
-  rps.check_unknown_prefixed_ext = true;
-
   if (s != NULL && strcmp (s, "") == 0)
     {
       as_bad (_("the architecture string of -march and elf architecture "
@@ -313,10 +256,10 @@  riscv_set_arch (const char *s)
     }
 
   riscv_release_subset_list (&riscv_subsets);
-  riscv_parse_subset (&rps, s);
+  riscv_parse_subset (&riscv_rps_as, s);
 
   riscv_set_rvc (false);
-  if (riscv_subset_supports ("c"))
+  if (riscv_subset_supports (&riscv_rps_as, "c"))
     riscv_set_rvc (true);
 }
 
@@ -341,11 +284,11 @@  riscv_set_abi_by_arch (void)
 {
   if (!explicit_mabi)
     {
-      if (riscv_subset_supports ("q"))
+      if (riscv_subset_supports (&riscv_rps_as, "q"))
 	riscv_set_abi (xlen, FLOAT_ABI_QUAD, false);
-      else if (riscv_subset_supports ("d"))
+      else if (riscv_subset_supports (&riscv_rps_as, "d"))
 	riscv_set_abi (xlen, FLOAT_ABI_DOUBLE, false);
-      else if (riscv_subset_supports ("e"))
+      else if (riscv_subset_supports (&riscv_rps_as, "e"))
 	riscv_set_abi (xlen, FLOAT_ABI_SOFT, true);
       else
 	riscv_set_abi (xlen, FLOAT_ABI_SOFT, false);
@@ -358,19 +301,19 @@  riscv_set_abi_by_arch (void)
       else if (abi_xlen < xlen)
 	as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen);
 
-      if (riscv_subset_supports ("e") && !rve_abi)
+      if (riscv_subset_supports (&riscv_rps_as, "e") && !rve_abi)
 	as_bad ("only the ilp32e ABI is supported for e extension");
 
       if (float_abi == FLOAT_ABI_SINGLE
-	  && !riscv_subset_supports ("f"))
+	  && !riscv_subset_supports (&riscv_rps_as, "f"))
 	as_bad ("ilp32f/lp64f ABI can't be used when f extension "
 		"isn't supported");
       else if (float_abi == FLOAT_ABI_DOUBLE
-	       && !riscv_subset_supports ("d"))
+	       && !riscv_subset_supports (&riscv_rps_as, "d"))
 	as_bad ("ilp32d/lp64d ABI can't be used when d extension "
 		"isn't supported");
       else if (float_abi == FLOAT_ABI_QUAD
-	       && !riscv_subset_supports ("q"))
+	       && !riscv_subset_supports (&riscv_rps_as, "q"))
 	as_bad ("ilp32q/lp64q ABI can't be used when q extension "
 		"isn't supported");
     }
@@ -923,13 +866,13 @@  riscv_csr_address (const char *csr_name,
   switch (csr_class)
     {
     case CSR_CLASS_I:
-      result = riscv_subset_supports ("i");
+      result = riscv_subset_supports (&riscv_rps_as, "i");
       break;
     case CSR_CLASS_I_32:
-      result = (xlen == 32 && riscv_subset_supports ("i"));
+      result = (xlen == 32 && riscv_subset_supports (&riscv_rps_as, "i"));
       break;
     case CSR_CLASS_F:
-      result = riscv_subset_supports ("f");
+      result = riscv_subset_supports (&riscv_rps_as, "f");
       need_check_version = false;
       break;
     case CSR_CLASS_DEBUG:
@@ -995,7 +938,7 @@  reg_lookup_internal (const char *s, enum reg_class class)
   if (r == NULL || DECODE_REG_CLASS (r) != class)
     return -1;
 
-  if (riscv_subset_supports ("e")
+  if (riscv_subset_supports (&riscv_rps_as, "e")
       && class == RCLASS_GPR
       && DECODE_REG_NUM (r) > 15)
     return -1;
@@ -2061,7 +2004,7 @@  riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
       if ((insn->xlen_requirement != 0) && (xlen != insn->xlen_requirement))
 	continue;
 
-      if (!riscv_multi_subset_supports (insn->insn_class))
+      if (!riscv_multi_subset_supports (&riscv_rps_as, insn->insn_class))
 	continue;
 
       create_insn (ip, insn);
@@ -3364,21 +3307,14 @@  s_riscv_option (int x ATTRIBUTE_UNUSED)
   ch = *input_line_pointer;
   *input_line_pointer = '\0';
 
-  riscv_parse_subset_t rps;
-  rps.subset_list = &riscv_subsets;
-  rps.error_handler = as_bad;
-  rps.xlen = &xlen;
-  rps.isa_spec = default_isa_spec;
-  rps.check_unknown_prefixed_ext = true;
-
   if (strcmp (name, "rvc") == 0)
     {
-      riscv_update_subset (&rps, "c", false);
+      riscv_update_subset (&riscv_rps_as, "c", false);
       riscv_set_rvc (true);
     }
   else if (strcmp (name, "norvc") == 0)
     {
-      riscv_update_subset (&rps, "c", true);
+      riscv_update_subset (&riscv_rps_as, "c", true);
       riscv_set_rvc (false);
     }
   else if (strcmp (name, "pic") == 0)
diff --git a/gas/testsuite/gas/riscv/mapping-04b.d b/gas/testsuite/gas/riscv/mapping-04b.d
index 9735498..54bd0af 100644
--- a/gas/testsuite/gas/riscv/mapping-04b.d
+++ b/gas/testsuite/gas/riscv/mapping-04b.d
@@ -18,6 +18,6 @@  Disassembly of section .text:
 [ 	]+19:[ 	]+20022002[ 	]+.word[ 	]+0x20022002
 [ 	]+1d:[ 	]+2002[ 	]+.short[ 	]+0x2002
 [ 	]+1f:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
-[ 	]+23:[ 	]+0000[ 	]+unimp
-[ 	]+25:[ 	]+0000[ 	]+unimp
+[ 	]+23:[ 	]+0000[ 	]+.2byte[ 	]+0x0
+[ 	]+25:[ 	]+0000[ 	]+.2byte[ 	]+0x0
 #...
diff --git a/gas/testsuite/gas/riscv/mapping-norelax-03b.d b/gas/testsuite/gas/riscv/mapping-norelax-03b.d
index ad88888..9e77735 100644
--- a/gas/testsuite/gas/riscv/mapping-norelax-03b.d
+++ b/gas/testsuite/gas/riscv/mapping-norelax-03b.d
@@ -17,7 +17,7 @@  Disassembly of section .text:
 [ 	]+18:[ 	]+00000302[ 	]+.word[ 	]+0x00000302
 [ 	]+1c:[ 	]+00[ 	]+.byte[ 	]+0x00
 [ 	]+1d:[ 	]+00[ 	]+.byte[ 	]+0x00
-[ 	]+1e:[ 	]+0001[ 	]+nop
+[ 	]+1e:[ 	]+0001[ 	]+.2byte[ 	]+0x1
 [ 	]+20:[ 	]+00000005[ 	]+.word[ 	]+0x00000005
 [ 	]+24:[ 	]+00000013[ 	]+nop
 [ 	]+28:[ 	]+00000013[ 	]+nop
diff --git a/gas/testsuite/gas/riscv/mapping-norelax-04b.d b/gas/testsuite/gas/riscv/mapping-norelax-04b.d
index 824a898..be668f2 100644
--- a/gas/testsuite/gas/riscv/mapping-norelax-04b.d
+++ b/gas/testsuite/gas/riscv/mapping-norelax-04b.d
@@ -13,12 +13,12 @@  Disassembly of section .text:
 [ 	]+8:[ 	]+00000001[ 	]+.word[ 	]+0x00000001
 [ 	]+c:[ 	]+00[ 	]+.byte[ 	]+0x00
 [ 	]+d:[ 	]+00[ 	]+.byte[ 	]+0x00
-[ 	]+e:[ 	]+0001[ 	]+nop
+[ 	]+e:[ 	]+0001[ 	]+.2byte[ 	]+0x1
 [ 	]+10:[ 	]+00a50533[ 	]+add[ 	]+a0,a0,a0
 [ 	]+14:[ 	]+20022002[ 	]+.word[ 	]+0x20022002
 [ 	]+18:[ 	]+20022002[ 	]+.word[ 	]+0x20022002
 [ 	]+1c:[ 	]+2002[ 	]+.short[ 	]+0x2002
 [ 	]+1e:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
-[ 	]+22:[ 	]+0001[ 	]+nop
+[ 	]+22:[ 	]+0001[ 	]+.2byte[ 	]+0x1
 [ 	]+24:[ 	]+00000013[ 	]+nop
 #...
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 1a09440..814c959 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -27,13 +27,26 @@ 
 #include "opintl.h"
 #include "elf-bfd.h"
 #include "elf/riscv.h"
-#include "cpu-riscv.h"
+#include "elfxx-riscv.h"
 
 #include <stdint.h>
 #include <ctype.h>
 
+static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;
 static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
 
+unsigned xlen = 0;
+
+static riscv_subset_list_t riscv_subsets;
+static riscv_parse_subset_t riscv_rps_dis =
+{
+  &riscv_subsets,	/* subset_list.  */
+  opcodes_error_handler,/* error_handler.  */
+  &xlen,		/* xlen.  */
+  &default_isa_spec,	/* isa_spec.  */
+  false,		/* check_unknown_prefixed_ext.  */
+};
+
 struct riscv_private_data
 {
   bfd_vma gp;
@@ -502,8 +515,6 @@  riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
   op = riscv_hash[OP_HASH_IDX (word)];
   if (op != NULL)
     {
-      unsigned xlen = 0;
-
       /* If XLEN is not known, get its value from the ELF class.  */
       if (info->mach == bfd_mach_riscv64)
 	xlen = 64;
@@ -527,6 +538,9 @@  riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
 	  if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
 	    continue;
 
+	  if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
+	    continue;
+
 	  /* It's a match.  */
 	  (*info->fprintf_func) (info->stream, "%s", op->name);
 	  print_insn_args (op->args, word, memaddr, info);
@@ -852,11 +866,13 @@  print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
 disassembler_ftype
 riscv_get_disassembler (bfd *abfd)
 {
+  const char *default_arch = NULL;
+
   if (abfd)
     {
       const struct elf_backend_data *ebd = get_elf_backend_data (abfd);
       if (ebd)
-        {
+	{
 	  const char *sec_name = ebd->obj_attrs_section;
 	  if (bfd_get_section_by_name (abfd, sec_name) != NULL)
 	    {
@@ -868,10 +884,14 @@  riscv_get_disassembler (bfd *abfd)
 						      attr[Tag_b].i,
 						      attr[Tag_c].i,
 						      &default_priv_spec);
+	      default_arch = attr[Tag_RISCV_arch].s;
 	    }
-        }
+	}
     }
-   return print_insn_riscv;
+
+  riscv_release_subset_list (&riscv_subsets);
+  riscv_parse_subset (&riscv_rps_dis, default_arch);
+  return print_insn_riscv;
 }
 
 /* Prevent use of the fake labels that are generated as part of the DWARF