From 638b527801d44bfc49d14469c59ed3a1a941b1bb Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Thu, 11 Aug 2022 12:13:04 +0900 Subject: [PATCH] RISC-V: Mapping symbols with ISA string on disassembler The mapping symbols with ISA string is proposed to deal with so called "ifunc issue". It enables disassembling a certain range of the code with a different architecture than the rest, even if conflicting. This is useful when there's "optimized" implementation is available but dynamically switched only if a certain extension is available. This commit implements the disassembler support to parse mapping symbols with ISA string. [1] Proposal: Extend .option directive for control enabled extensions on specific code region, https://github.com/riscv-non-isa/riscv-asm-manual/pull/67 [2] Proposal: Add mapping symbol, https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/196 This commit is based on Nelson Chu's proposal "RISC-V: Output mapping symbols with ISA string once .option arch is used." but heavily modified to reflect the intent of Kito's original proposal. It is also made smarter so that it no longer requires MAP_INSN_ARCH. gas/ChangeLog: * testsuite/gas/riscv/option-arch-01a.d: Reflect the disassembler support of mapping symbols with ISA string. opcodes/ChangeLog: * riscv-dis.c (initial_default_arch) Default architecture string if no ELF attributes are available. (default_arch): A copy of the default architecture string. (is_arch_mapping): New variable to keep track of whether the current architecture is deviced from a mapping symbol. (riscv_disassemble_insn): Update FPR names when a mapping symbol with ISA string is encountered. (riscv_get_map_state): Support mapping symbols with ISA string. Use `is_arch_mapping' to stop repeatedly parsing the default architecture. (riscv_get_disassembler): Safer architecture string handling. Copy the string to switch to the default while disassembling. --- gas/testsuite/gas/riscv/option-arch-01a.d | 2 +- opcodes/riscv-dis.c | 44 ++++++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/gas/testsuite/gas/riscv/option-arch-01a.d b/gas/testsuite/gas/riscv/option-arch-01a.d index aed4ca8e4d9..b9c260c9949 100644 --- a/gas/testsuite/gas/riscv/option-arch-01a.d +++ b/gas/testsuite/gas/riscv/option-arch-01a.d @@ -10,5 +10,5 @@ Disassembly of section .text: 0+000 <.text>: [ ]+[0-9a-f]+:[ ]+952e[ ]+add[ ]+a0,a0,a1 [ ]+[0-9a-f]+:[ ]+00b50533[ ]+add[ ]+a0,a0,a1 -[ ]+[0-9a-f]+:[ ]+00302573[ ]+csrr[ ]+a0,fcsr +[ ]+[0-9a-f]+:[ ]+00302573[ ]+frcsr[ ]+a0 #... diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index 7ff477278bb..7fb3d32bd47 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -32,6 +32,16 @@ #include #include +/* Default architecture string (if not available). */ +static const char *initial_default_arch = "rv64gc"; + +/* Default architecture string + (as specified by the ELF attributes or `initial_default_arch'). */ +static const char *default_arch = NULL; + +/* True if the architecture is set from a mapping symbol. */ +static bool is_arch_mapping = false; + 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; @@ -638,8 +648,12 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info) } /* If arch has ZFINX flags, use gpr for disassemble. */ - if(riscv_subset_supports (&riscv_rps_dis, "zfinx")) + if (riscv_subset_supports (&riscv_rps_dis, "zfinx")) riscv_fpr_names = riscv_gpr_names; + else + riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi + ? riscv_fpr_names_abi + : riscv_fpr_names_numeric; for (; op->name; op++) { @@ -750,8 +764,23 @@ riscv_get_map_state (int n, return false; name = bfd_asymbol_name(info->symtab[n]); - if (startswith (name, "$x")) + if (startswith (name, "$xrv")) + { *state = MAP_INSN; + riscv_release_subset_list (&riscv_subsets); + riscv_parse_subset (&riscv_rps_dis, name + 2); + is_arch_mapping = true; + } + else if (strcmp (name, "$x") == 0) + { + *state = MAP_INSN; + if (is_arch_mapping) + { + riscv_release_subset_list (&riscv_subsets); + riscv_parse_subset (&riscv_rps_dis, default_arch); + is_arch_mapping = false; + } + } else if (strcmp (name, "$d") == 0) *state = MAP_DATA; else @@ -1000,7 +1029,7 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info) disassembler_ftype riscv_get_disassembler (bfd *abfd) { - const char *default_arch = "rv64gc"; + const char *default_arch_next = initial_default_arch; if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour) { @@ -1015,12 +1044,19 @@ riscv_get_disassembler (bfd *abfd) attr[Tag_b].i, attr[Tag_c].i, &default_priv_spec); - default_arch = attr[Tag_RISCV_arch].s; + default_arch_next = attr[Tag_RISCV_arch].s; + /* For ELF files with (somehow) no architecture string + in the attributes, use the default value. */ + if (!default_arch_next) + default_arch_next = initial_default_arch; } } + free ((void *) default_arch); + default_arch = xstrdup (default_arch_next); riscv_release_subset_list (&riscv_subsets); riscv_parse_subset (&riscv_rps_dis, default_arch); + is_arch_mapping = false; return print_insn_riscv; }