Re: [PATCH v2 2/3] RISC-V: PR27916, Support mapping symbols.

Palmer Dabbelt
2021-07-15T15:18:21Z

On Fri, 09 Jul 2021 00:28:24 PDT (-0700), nelson.chu@sifive.com wrote:
> Similar to ARM/AARCH64, we add mapping symbols in the symbol table,
> to mark the start addresses of data and instructions. The $d means
> data, the $x means instruction, and the $a means code alignment.
> Then the disassembler uses these symbols to decide whether we should
> dump data or instruction.
>
> For example,
> $ cat tmp.s
> .text
> .option norelax
> .option norvc
> .fill 2, 4, 0x1001 # $d for 8 bytes fill data.
> .byte 1 # $d1
> .word 0 # $d4
> .align 3 # $a1 for align.byte, $a for align.nop.
> nop # $x
> .fill 5, 2, 0x2002 # $d for 10 bytes fill data.
> nop # $x
> .data
> .word 0x1 # No need to add mapping symbols.
> .word 0x2
>
> $ riscv64-unknown-elf-as tmp.s -o tmp.o
> $ riscv64-unknown-elf-objdump -D tmp.o
>
> Disassembly of section .text:
>
> 0000000000000000 <.text>:
> 0: 00001001 .word 0x00001001
> 4: 00001001 .word 0x00001001
> 8: 01 .byte 0x01
> 9: 00000000 .word 0x00000000
> d: 00 align.byte
> e: 0001 align.nop
> 10: 00000013 nop
> 14: 10001000 .word 0x20022002
> 18: 10001000 .word 0x20022002
> 1c: 1000 .short 0x2002
> 1e: 00000013 nop
> 22: 0001 align.nop
> 24: 00000013 align.nop
>
> Disassembly of section .data:
>
> 0000000000000000 <.data>:
> 0: 00000001 .word 0x00000001
> 4: 00000002 .word 0x00000002
>
> Disassembly of section .riscv.attributes:
>
> 0000000000000000 <.riscv.attributes>:
> 0: 00002d41 .word 0x00002d41
> ... skip ...
>
> There are too many issues we can discuss from the above example,
> so I just pick some of them that I think are important to mention.
>
> * The documentation for -D says that on ARM platforms -D should
> disassemble instructions. Therefore, they dump data by searching
> mapping symbols only when the DISASSEMBLE_DATA is set. That causes
> the mapping symbols are useless for -D. I am not sure if any riscv
> document had mentioned this, so I prefer to keep them useful, but
> only for text sections. Otherwise, dump other sections as datas.
>
> * If the data are written by cons_worker, then we add mapping symbols
> with the data size, to show more detials. For example,
>
> .text
> .byte 1
> .word 0
>
> The $d1 is added for .byte, and $d4 is added for .word, so that
> we can show the code that is closer to the user's original code,
> rather than the data with 5 bytes size.
>
> * Add the align.<insn> prefix if the instructions are used for
> alignment and marked with $a/$a1. One of the benefits is that,
> we can distinguish c.nop and align.nop, when the rvc is disabled.
> The c.nop is illegal, but the align.nop is legal.
>
> Besides, we may dump .align.unimp at the end of sections when relax
> is enabled, this is expected. Since the tail section alignments are
> not handled in the riscv_frag_align_code, and it cannot be filled with
> nops in the riscv_handle_align either.
>
> The elf/linux toolchain regressions all passed. Besides, I also
> disable the mapping symbols internally, but use the new objudmp, the
> regressions passed, too. Therefore, the new objudmp should dump
> the objects corretly, even if they don't have any mapping symbols.
>
> ChangeLog:
>
> bfd/
>
> pr 27916
> * cpu-riscv.c (riscv_elf_is_mapping_symbols): Define mapping symbols.
> * cpu-riscv.h: extern riscv_elf_is_mapping_symbols.
> * elfnn-riscv.c (riscv_maybe_function_sym): Do not choose mapping
> symbols as a function name.
> (riscv_elf_is_target_special_symbol): Add mapping symbols.
>
> binutils/
>
> pr 27916
> * readelf (get_symbol_for_build_attribute): Filter data mapping
> symbols with size.
> * testsuite/binutils-all/readelf.s: Updated.
> * testsuite/binutils-all/readelf.s-64: Likewise.
> * testsuite/binutils-all/readelf.s-64-unused: Likewise.
> * testsuite/binutils-all/readelf.ss: Likewise.
> * testsuite/binutils-all/readelf.ss-64: Likewise.
> * testsuite/binutils-all/readelf.ss-64-unused: Likewise.
>
> gas/
>
> pr 27916
> config/tc-riscv.c (make_mapping_symbol): Create a new mapping symbol.
> (riscv_mapping_state): Decide whether to create mapping symbol for
> frag_now. Only add the mapping symbols to text sections.
> (riscv_add_odd_padding_symbol): Add the odd bytes of paddings for
> riscv_handle_align.
> (riscv_check_mapping_symbols): Remove any excess mapping symbols.
> (md_assemble): Marked as MAP_INSN.
> (riscv_frag_align_code): Marked as MAP_ALIGN.
> (riscv_init_frag): Add mapping symbols for frag, it usually called
> by frag_var. Marked as MAP_DATA for rs_align and rs_fill, and
> marked as alignment MAP_ALIGN for rs_align_code.
> (s_riscv_insn): Marked as MAP_INSN.
> (riscv_adjust_symtab): Call riscv_check_mapping_symbols.
> * config/tc-riscv.h (md_cons_align): Defined to riscv_mapping_state
> with MAP_DATA_CONS[0|1|2|3].
> (TC_SEGMENT_INFO_TYPE): Record mapping state for each segment.
> (TC_FRAG_TYPE): Record the first and last mapping symbols for the
> fragments. The first mapping symbol must be placed at the start
> of the fragment.
> (TC_FRAG_INIT): Defined to riscv_init_frag.
> * testsuite/gas/riscv/mapping-01.s: New testcase.
> * testsuite/gas/riscv/mapping-01a.d: Likewise.
> * testsuite/gas/riscv/mapping-01b.d: Likewise.
> * testsuite/gas/riscv/mapping-02.s: Likewise.
> * testsuite/gas/riscv/mapping-02a.d: Likewise.
> * testsuite/gas/riscv/mapping-02b.d: Likewise.
> * testsuite/gas/riscv/mapping-03.s: Likewise.
> * testsuite/gas/riscv/mapping-03a.d: Likewise.
> * testsuite/gas/riscv/mapping-03b.d: Likewise.
> * testsuite/gas/riscv/mapping-04.s: Likewise.
> * testsuite/gas/riscv/mapping-04a.d: Likewise.
> * testsuite/gas/riscv/mapping-04b.d: Likewise.
> * testsuite/gas/riscv/mapping-norelax-04a.d: Likewise.
> * testsuite/gas/riscv/mapping-norelax-04b.d: Likewise.
> * testsuite/gas/riscv/no-relax-align.d: Updated.
> * testsuite/gas/riscv/no-relax-align-2.d: Likewise.
>
> include/
>
> pr 27916
> * opcode/riscv.h (enum riscv_seg_mstate): Added.
>
> opcodes/
>
> pr 27916
> * riscv-dis.c (last_map_symbol, last_stop_offset, last_section,
> last_map_state): Added to dump sections with mapping symbols.
> (riscv_get_map_state): Get the mapping state from the symbol.
> (riscv_search_mapping_symbol): Check the sorted symbol table, and
> then find the suitable mapping symbol.
> (riscv_data_length): Decide which data size we should print.
> (riscv_disassemble_data): Dump the data contents.
> (riscv_disassemble_insn): Dump align.<insn> for MAP_ALIGN.
> (print_insn_riscv): Handle the mapping symbols.
> (riscv_symbol_is_valid): Marked mapping symbols as invalid.
> ---
> bfd/cpu-riscv.c | 10 +
> bfd/cpu-riscv.h | 3 +
> bfd/elfnn-riscv.c | 25 +-
> binutils/readelf.c | 8 +-
> binutils/testsuite/binutils-all/readelf.s-64 | 5 +-
> .../binutils-all/readelf.s-64-unused | 5 +-
> binutils/testsuite/binutils-all/readelf.ss | 2 +
> binutils/testsuite/binutils-all/readelf.ss-64 | 7 +-
> .../binutils-all/readelf.ss-64-unused | 7 +-
> .../testsuite/binutils-all/readelf.ss-unused | 2 +
> gas/config/tc-riscv.c | 223 ++++++++++++-
> gas/config/tc-riscv.h | 32 ++
> gas/testsuite/gas/riscv/mapping-01.s | 18 +
> gas/testsuite/gas/riscv/mapping-01a.d | 17 +
> gas/testsuite/gas/riscv/mapping-01b.d | 21 ++
> gas/testsuite/gas/riscv/mapping-02.s | 13 +
> gas/testsuite/gas/riscv/mapping-02a.d | 15 +
> gas/testsuite/gas/riscv/mapping-02b.d | 16 +
> gas/testsuite/gas/riscv/mapping-03.s | 10 +
> gas/testsuite/gas/riscv/mapping-03a.d | 16 +
> gas/testsuite/gas/riscv/mapping-03b.d | 16 +
> gas/testsuite/gas/riscv/mapping-04.s | 11 +
> gas/testsuite/gas/riscv/mapping-04a.d | 21 ++
> gas/testsuite/gas/riscv/mapping-04b.d | 24 ++
> gas/testsuite/gas/riscv/mapping-norelax-04a.d | 23 ++
> gas/testsuite/gas/riscv/mapping-norelax-04b.d | 25 ++
> gas/testsuite/gas/riscv/no-relax-align-2.d | 19 +-
> gas/testsuite/gas/riscv/no-relax-align.d | 4 +-
> include/opcode/riscv.h | 13 +
> opcodes/riscv-dis.c | 313 +++++++++++++++++-
> 30 files changed, 885 insertions(+), 39 deletions(-)
> create mode 100644 gas/testsuite/gas/riscv/mapping-01.s
> create mode 100644 gas/testsuite/gas/riscv/mapping-01a.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-01b.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-02.s
> create mode 100644 gas/testsuite/gas/riscv/mapping-02a.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-02b.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-03.s
> create mode 100644 gas/testsuite/gas/riscv/mapping-03a.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-03b.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-04.s
> create mode 100644 gas/testsuite/gas/riscv/mapping-04a.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-04b.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-norelax-04a.d
> create mode 100644 gas/testsuite/gas/riscv/mapping-norelax-04b.d
>
> diff --git a/bfd/cpu-riscv.c b/bfd/cpu-riscv.c
> index 025e94afd34..dae76e7fdcc 100644
> --- a/bfd/cpu-riscv.c
> +++ b/bfd/cpu-riscv.c
> @@ -140,3 +140,13 @@ riscv_get_priv_spec_class_from_numbers (unsigned int major,
> RISCV_GET_PRIV_SPEC_CLASS (buf, class_t);
> *class = class_t;
> }
> +
> +/* Define mapping symbols for riscv. */
> +
> +bool
> +riscv_elf_is_mapping_symbols (const char *name)
> +{
> + return (!strncmp (name, "$d", 2)
> + || !strncmp (name, "$x", 2)
> + || !strncmp (name, "$a", 2));
> +}

I can't quite figure this one out: this will treat something like
"$aWHATEVER" as a mapping symbol, does that cause binutils to crash
somewhere? All I'm seeing it do is mark these as hidden symbols, which
I guess is OK (we've kind of set the "anything with $ is inernal
precedent").

Either way,

Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>

> diff --git a/bfd/cpu-riscv.h b/bfd/cpu-riscv.h
> index cafaca23be0..ed5ee7e60d5 100644
> --- a/bfd/cpu-riscv.h
> +++ b/bfd/cpu-riscv.h
> @@ -79,3 +79,6 @@ riscv_get_priv_spec_class_from_numbers (unsigned int,
> unsigned int,
> unsigned int,
> enum riscv_spec_class *);
> +
> +extern bool
> +riscv_elf_is_mapping_symbols (const char *);
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 85a99f3d610..a10384cd4d3 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -5150,14 +5150,32 @@ riscv_elf_obj_attrs_arg_type (int tag)
> return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
> }
>
> -/* PR27584, Omit local and empty symbols since they usually generated
> - for pcrel relocations. */
> +/* Do not choose mapping symbols as a function name. */
> +
> +static bfd_size_type
> +riscv_maybe_function_sym (const asymbol *sym,
> + asection *sec,
> + bfd_vma *code_off)
> +{
> + if (sym->flags & BSF_LOCAL
> + && riscv_elf_is_mapping_symbols (sym->name))
> + return 0;
> +
> + return _bfd_elf_maybe_function_sym (sym, sec, code_off);
> +}
> +
> +/* Treat the following cases as target special symbols, they are
> + usually omitted. */
>
> static bool
> riscv_elf_is_target_special_symbol (bfd *abfd, asymbol *sym)
> {
> + /* PR27584, local and empty symbols. Since they are usually
> + generated for pcrel relocations. */
> return (!strcmp (sym->name, "")
> - || _bfd_elf_is_local_label_name (abfd, sym->name));
> + || _bfd_elf_is_local_label_name (abfd, sym->name)
> + /* PR27916, mapping symbols. */
> + || riscv_elf_is_mapping_symbols (sym->name));
> }
>
> static int
> @@ -5245,6 +5263,7 @@ riscv_elf_modify_segment_map (bfd *abfd,
> #define elf_backend_grok_psinfo riscv_elf_grok_psinfo
> #define elf_backend_object_p riscv_elf_object_p
> #define elf_backend_write_core_note riscv_write_core_note
> +#define elf_backend_maybe_function_sym riscv_maybe_function_sym
> #define elf_info_to_howto_rel NULL
> #define elf_info_to_howto riscv_info_to_howto_rela
> #define bfd_elfNN_bfd_relax_section _bfd_riscv_relax_section
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index 24ff069edf4..7560e0f6a51 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -20283,10 +20283,14 @@ get_symbol_for_build_attribute (Filedata *filedata,
> continue;
>
> /* The AArch64 and ARM architectures define mapping symbols
> - (eg $d, $x, $t) which we want to ignore. */
> + (eg $d, $x, $t) which we want to ignore. Besides, riscv
> + may defines data mapping symbols with size (eg $d1, $d2,
> + $d4, $d8), which we also want to ignore. */
> if (ba_cache.strtab[sym->st_name] == '$'
> && ba_cache.strtab[sym->st_name + 1] != 0
> - && ba_cache.strtab[sym->st_name + 2] == 0)
> + && (ba_cache.strtab[sym->st_name + 2] == 0
> + || (ba_cache.strtab[sym->st_name + 2] != 0
> + && ba_cache.strtab[sym->st_name + 3] == 0)))
> continue;
>
> if (is_open_attr)
> diff --git a/binutils/testsuite/binutils-all/readelf.s-64 b/binutils/testsuite/binutils-all/readelf.s-64
> index 4c957f7a938..0b1bafee537 100644
> --- a/binutils/testsuite/binutils-all/readelf.s-64
> +++ b/binutils/testsuite/binutils-all/readelf.s-64
> @@ -19,8 +19,9 @@ Section Headers:
> +\[ .\] .symtab +SYMTAB +0000000000000000 +0+.*
> # aarch64-elf targets have one more data symbol.
> # x86 targets may have .note.gnu.property.
> -# riscv targets have .riscv.attributes.
> - +0+.* +0000000000000018 +(6|7) +(3|4) +8
> +# riscv targets have five more symbols, one is .riscv.attributes,
> +# others are mapping data symbols.
> + +0+.* +0000000000000018 +(6|7) +(3|4|8) +8
> +\[ .\] .strtab +STRTAB +0000000000000000 +0+.*
> +0+.* +0000000000000000 .* +0 +0 +1
> +\[ .\] .shstrtab +STRTAB +0000000000000000 +[0-9a-f]+
> diff --git a/binutils/testsuite/binutils-all/readelf.s-64-unused b/binutils/testsuite/binutils-all/readelf.s-64-unused
> index 771439411a0..542bbb70064 100644
> --- a/binutils/testsuite/binutils-all/readelf.s-64-unused
> +++ b/binutils/testsuite/binutils-all/readelf.s-64-unused
> @@ -19,8 +19,9 @@ Section Headers:
> +\[ .\] .symtab +SYMTAB +0000000000000000 +0+.*
> # aarch64-elf targets have one more data symbol.
> # x86 targets may have .note.gnu.property.
> -# riscv targets have .riscv.attributes.
> - +0+.* +0000000000000018 +(6|7) +(6|7) +8
> +# riscv targets have five more symbols, one is .riscv.attributes,
> +# others are mapping data symbols.
> + +0+.* +0000000000000018 +(6|7) +(6|7|11) +8
> +\[ .\] .strtab +STRTAB +0000000000000000 +0+.*
> +0+.* +0000000000000000 .* +0 +0 +1
> +\[ .\] .shstrtab +STRTAB +0000000000000000 +[0-9a-f]+
> diff --git a/binutils/testsuite/binutils-all/readelf.ss b/binutils/testsuite/binutils-all/readelf.ss
> index b81c016e9e7..5d96649c2a0 100644
> --- a/binutils/testsuite/binutils-all/readelf.ss
> +++ b/binutils/testsuite/binutils-all/readelf.ss
> @@ -5,8 +5,10 @@ Symbol table '.symtab' contains .* entries:
> +1: 00000000 +0 +NOTYPE +LOCAL +DEFAULT +1 static_text_symbol
> # ARM targets add the $d mapping symbol here...
> # NDS32 targets add the $d2 mapping symbol here...
> +# riscv targets add the $d4 mapping symbols here...
> #...
> +.: 00000000 +0 +NOTYPE +LOCAL +DEFAULT +[34] static_data_symbol
> +# ... or here ...
> # v850 targets include extra SECTION symbols here for the .call_table_data
> # and .call_table_text sections.
> # riscv targets add .riscv.attribute symbol here...
> diff --git a/binutils/testsuite/binutils-all/readelf.ss-64 b/binutils/testsuite/binutils-all/readelf.ss-64
> index c6ffb0fc523..105f1b88361 100644
> --- a/binutils/testsuite/binutils-all/readelf.ss-64
> +++ b/binutils/testsuite/binutils-all/readelf.ss-64
> @@ -4,13 +4,14 @@ Symbol table '.symtab' contains .* entries:
> +0: 0000000000000000 +0 +NOTYPE +LOCAL +DEFAULT +UND
> +1: 0000000000000000 +0 +NOTYPE +LOCAL +DEFAULT +1 static_text_symbol
> # aarch64-elf targets add the $d mapping symbol here...
> +# riscv targets add the $d4 mapping symbols here...
> #...
> +.: 0000000000000000 +0 +NOTYPE +LOCAL +DEFAULT +3 static_data_symbol
> # ... or here ...
> # riscv targets add .riscv.attribute symbol here...
> #...
> -.* +.: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +1 text_symbol
> - +.: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +UND external_symbol
> - +.: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +3 data_symbol
> +.* +[0-9]+: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +1 text_symbol
> + +[0-9]+: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +UND external_symbol
> + +[0-9]+: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +3 data_symbol
> +[0-9]+: 0000000000000004 +4 +(COMMON|OBJECT) +GLOBAL +DEFAULT +COM common_symbol
> #pass
> diff --git a/binutils/testsuite/binutils-all/readelf.ss-64-unused b/binutils/testsuite/binutils-all/readelf.ss-64-unused
> index cf515aa60d0..50fca025b31 100644
> --- a/binutils/testsuite/binutils-all/readelf.ss-64-unused
> +++ b/binutils/testsuite/binutils-all/readelf.ss-64-unused
> @@ -7,13 +7,14 @@ Symbol table '.symtab' contains .* entries:
> +3: 0000000000000000 +0 +SECTION +LOCAL +DEFAULT +4.*
> +4: 0000000000000000 +0 +NOTYPE +LOCAL +DEFAULT +1 static_text_symbol
> # aarch64-elf targets add the $d mapping symbol here...
> +# riscv targets add the $d4 mapping symbols here...
> #...
> +.: 0000000000000000 +0 +NOTYPE +LOCAL +DEFAULT +3 static_data_symbol
> # ... or here ...
> # riscv targets add .riscv.attribute symbol here...
> #...
> -.* +.: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +1 text_symbol
> - +.: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +UND external_symbol
> - +.: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +3 data_symbol
> +.* +[0-9]+: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +1 text_symbol
> + +[0-9]+: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +UND external_symbol
> + +[0-9]+: 0000000000000000 +0 +NOTYPE +GLOBAL +DEFAULT +3 data_symbol
> +[0-9]+: 0000000000000004 +4 +(COMMON|OBJECT) +GLOBAL +DEFAULT +COM common_symbol
> #pass
> diff --git a/binutils/testsuite/binutils-all/readelf.ss-unused b/binutils/testsuite/binutils-all/readelf.ss-unused
> index 3107af930eb..944ab45cc46 100644
> --- a/binutils/testsuite/binutils-all/readelf.ss-unused
> +++ b/binutils/testsuite/binutils-all/readelf.ss-unused
> @@ -8,8 +8,10 @@ Symbol table '.symtab' contains .* entries:
> +4: 00000000 +0 +NOTYPE +LOCAL +DEFAULT +1 static_text_symbol
> # ARM targets add the $d mapping symbol here...
> # NDS32 targets add the $d2 mapping symbol here...
> +# riscv targets add the $d4 mapping symbols here...
> #...
> +.: 00000000 +0 +NOTYPE +LOCAL +DEFAULT +[34] static_data_symbol
> +# ... or here ...
> # v850 targets include extra SECTION symbols here for the .call_table_data
> # and .call_table_text sections.
> #...
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index df37579c843..55c49471825 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -561,6 +561,179 @@ static bool explicit_priv_attr = false;
>
> static char *expr_end;
>
> +/* Create a new mapping symbol for the transition to STATE. */
> +
> +static void
> +make_mapping_symbol (enum riscv_seg_mstate state,
> + valueT value,
> + fragS *frag)
> +{
> + const char *name;
> + switch (state)
> + {
> + case MAP_DATA:
> + name = "$d";
> + break;
> + case MAP_DATA_CONS0:
> + name = "$d1";
> + break;
> + case MAP_DATA_CONS1:
> + name = "$d2";
> + break;
> + case MAP_DATA_CONS2:
> + name = "$d4";
> + break;
> + case MAP_DATA_CONS3:
> + name = "$d8";
> + break;
> + case MAP_INSN:
> + name = "$x";
> + break;
> + case MAP_ALIGN:
> + name = "$a";
> + break;
> + case MAP_ALIGN_ODD:
> + name = "$a1";
> + break;
> + default:
> + abort ();
> + }
> +
> + symbolS *symbol = symbol_new (name, now_seg, frag, value);
> + symbol_get_bfdsym (symbol)->flags |= (BSF_NO_FLAGS | BSF_LOCAL);
> +
> + /* If .fill or other data filling directive generates zero sized data,
> + or we are adding odd alignemnts, then the mapping symbol for the
> + following code will have the same value. */
> + if (value == 0)
> + {
> + if (frag->tc_frag_data.first_map_symbol != NULL)
> + {
> + know (S_GET_VALUE (frag->tc_frag_data.first_map_symbol)
> + == S_GET_VALUE (symbol));
> + /* Remove the old one. */
> + symbol_remove (frag->tc_frag_data.first_map_symbol,
> + &symbol_rootP, &symbol_lastP);
> + }
> + frag->tc_frag_data.first_map_symbol = symbol;
> + }
> + if (frag->tc_frag_data.last_map_symbol != NULL)
> + {
> + /* The mapping symbols should be added in offset order. */
> + know (S_GET_VALUE (frag->tc_frag_data.last_map_symbol)
> + <= S_GET_VALUE (symbol));
> + /* Remove the old one. */
> + if (S_GET_VALUE (frag->tc_frag_data.last_map_symbol)
> + == S_GET_VALUE (symbol))
> + symbol_remove (frag->tc_frag_data.last_map_symbol,
> + &symbol_rootP, &symbol_lastP);
> + }
> + frag->tc_frag_data.last_map_symbol = symbol;
> +}
> +
> +/* Set the mapping state for frag_now. */
> +
> +void
> +riscv_mapping_state (enum riscv_seg_mstate to_state,
> + int max_chars)
> +{
> + enum riscv_seg_mstate from_state =
> + seg_info (now_seg)->tc_segment_info_data.map_state;
> +
> + if (!SEG_NORMAL (now_seg)
> + /* For now I only add the mapping symbols to text sections.
> + Therefore, the dis-assembler only show the actual contents
> + distribution for text. Other sections will be shown as
> + data without the details. */
> + || !subseg_text_p (now_seg))
> + return;
> +
> + /* Keep inserting the MAP_DATA_CONS in text. Otherwise, the mapping
> + symbol should be emitted. */
> + if (from_state == to_state
> + && from_state != MAP_DATA_CONS0
> + && from_state != MAP_DATA_CONS1
> + && from_state != MAP_DATA_CONS2
> + && from_state != MAP_DATA_CONS3)
> + return;
> +
> + valueT value = (valueT) (frag_now_fix () - max_chars);
> + seg_info (now_seg)->tc_segment_info_data.map_state = to_state;
> + make_mapping_symbol (to_state, value, frag_now);
> +}
> +
> +/* Add the odd bytes of paddings for riscv_handle_align. */
> +
> +static void
> +riscv_add_odd_padding_symbol (fragS *frag)
> +{
> + /* If there was already a mapping symbol, it should be
> + removed in the make_mapping_symbol. */
> + make_mapping_symbol (MAP_ALIGN_ODD, frag->fr_fix, frag);
> + make_mapping_symbol (MAP_ALIGN, frag->fr_fix + 1, frag);
> +}
> +
> +/* Remove any excess mapping symbols generated for alignment frags in
> + SEC. We may have created a mapping symbol before a zero byte
> + alignment; remove it if there's a mapping symbol after the
> + alignment. */
> +
> +static void
> +riscv_check_mapping_symbols (bfd *abfd ATTRIBUTE_UNUSED,
> + asection *sec,
> + void *dummy ATTRIBUTE_UNUSED)
> +{
> + segment_info_type *seginfo = seg_info (sec);
> + fragS *fragp;
> +
> + if (seginfo == NULL || seginfo->frchainP == NULL)
> + return;
> +
> + for (fragp = seginfo->frchainP->frch_root;
> + fragp != NULL;
> + fragp = fragp->fr_next)
> + {
> + symbolS *last = fragp->tc_frag_data.last_map_symbol;
> + fragS *next = fragp->fr_next;
> +
> + if (last == NULL || next == NULL)
> + continue;
> +
> + /* Check the last mapping symbol if it is at the boundary of
> + fragmnet. */
> + if (S_GET_VALUE (last) < next->fr_address)
> + continue;
> + know (S_GET_VALUE (last) == next->fr_address);
> +
> + do
> + {
> + if (next->tc_frag_data.first_map_symbol != NULL)
> + {
> + /* The last mapping symbol overlaps with another one
> + which at the start of the next frag. */
> + symbol_remove (last, &symbol_rootP, &symbol_lastP);
> + break;
> + }
> +
> + if (next->fr_next == NULL)
> + {
> + /* The last mapping symbol is at the end of the section. */
> + know (next->fr_fix == 0 && next->fr_var == 0);
> + symbol_remove (last, &symbol_rootP, &symbol_lastP);
> + break;
> + }
> +
> + /* Since we may have empty frags without any mapping symbols,
> + keep looking until the non-empty frag. */
> + if (next->fr_address != next->fr_next->fr_address)
> + break;
> +
> + next = next->fr_next;
> + }
> + while (next != NULL);
> + }
> +}
> +
> /* The default target format to use. */
>
> const char *
> @@ -2767,6 +2940,8 @@ md_assemble (char *str)
> return;
> }
>
> + riscv_mapping_state (MAP_INSN, 0);
> +
> const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
>
> if (error)
> @@ -3422,6 +3597,8 @@ riscv_frag_align_code (int n)
> fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
> &ex, false, BFD_RELOC_RISCV_ALIGN);
>
> + riscv_mapping_state (MAP_ALIGN, worst_case_bytes);
> +
> return true;
> }
>
> @@ -3441,6 +3618,7 @@ riscv_handle_align (fragS *fragP)
> /* We have 4 byte uncompressed nops. */
> bfd_signed_vma size = 4;
> bfd_signed_vma excess = bytes % size;
> + bfd_boolean odd_padding = (excess % 2 == 1);
> char *p = fragP->fr_literal + fragP->fr_fix;
>
> if (bytes <= 0)
> @@ -3449,12 +3627,20 @@ riscv_handle_align (fragS *fragP)
> /* Insert zeros or compressed nops to get 4 byte alignment. */
> if (excess)
> {
> + if (odd_padding)
> + riscv_add_odd_padding_symbol (fragP);
> riscv_make_nops (p, excess);
> fragP->fr_fix += excess;
> p += excess;
> }
>
> - /* Insert variable number of 4 byte uncompressed nops. */
> + /* The frag will be changed to `rs_fill` later. The function
> + `write_contents` will try to fill the remaining spaces
> + according to the patterns we give. In this case, we give
> + a 4 byte uncompressed nop as the pattern, and set the size
> + of the pattern into `fr_var`. The nop will be output to the
> + file `fr_offset` times. However, `fr_offset` could be zero
> + if we don't need to pad the boundary finally. */
> riscv_make_nops (p, size);
> fragP->fr_var = size;
> }
> @@ -3465,6 +3651,30 @@ riscv_handle_align (fragS *fragP)
> }
> }
>
> +/* This usually called from frag_var. */
> +
> +void
> +riscv_init_frag (fragS * fragP, int max_chars)
> +{
> + /* Do not add mapping symbol to debug sections. */
> + if (bfd_section_flags (now_seg) & SEC_DEBUGGING)
> + return;
> +
> + switch (fragP->fr_type)
> + {
> + case rs_fill:
> + case rs_align:
> + case rs_align_test:
> + riscv_mapping_state (MAP_DATA, max_chars);
> + break;
> + case rs_align_code:
> + riscv_mapping_state (MAP_ALIGN, max_chars);
> + break;
> + default:
> + break;
> + }
> +}
> +
> int
> md_estimate_size_before_relax (fragS *fragp, asection *segtype)
> {
> @@ -3721,6 +3931,8 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED)
> save_c = *input_line_pointer;
> *input_line_pointer = '\0';
>
> + riscv_mapping_state (MAP_INSN, 0);
> +
> const char *error = riscv_ip (str, &insn, &imm_expr,
> &imm_reloc, insn_type_hash);
>
> @@ -3811,6 +4023,15 @@ riscv_md_end (void)
> riscv_set_public_attributes ();
> }
>
> +/* Adjust the symbol table. */
> +
> +void
> +riscv_adjust_symtab (void)
> +{
> + bfd_map_over_sections (stdoutput, riscv_check_mapping_symbols, (char *) 0);
> + elf_adjust_symtab ();
> +}
> +
> /* Given a symbolic attribute NAME, return the proper integer value.
> Returns -1 if the attribute is not known. */
>
> diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h
> index 1de138458d8..1702b25bc51 100644
> --- a/gas/config/tc-riscv.h
> +++ b/gas/config/tc-riscv.h
> @@ -128,4 +128,36 @@ extern void riscv_elf_final_processing (void);
> extern void riscv_md_end (void);
> extern int riscv_convert_symbolic_attribute (const char *);
>
> +/* Set mapping symbol states. */
> +#define md_cons_align(nbytes) \
> + switch (nbytes) \
> + { \
> + default: riscv_mapping_state (MAP_DATA, 0); break; \
> + case 1: riscv_mapping_state (MAP_DATA_CONS0, 0); break; \
> + case 2: riscv_mapping_state (MAP_DATA_CONS1, 0); break; \
> + case 4: riscv_mapping_state (MAP_DATA_CONS2, 0); break; \
> + case 8: riscv_mapping_state (MAP_DATA_CONS3, 0); break; \
> + }
> +void riscv_mapping_state (enum riscv_seg_mstate, int);
> +
> +/* Define target segment type. */
> +#define TC_SEGMENT_INFO_TYPE struct riscv_segment_info_type
> +struct riscv_segment_info_type
> +{
> + enum riscv_seg_mstate map_state;
> +};
> +
> +/* Define target fragment type. */
> +#define TC_FRAG_TYPE struct riscv_frag_type
> +struct riscv_frag_type
> +{
> + symbolS *first_map_symbol, *last_map_symbol;
> +};
> +
> +#define TC_FRAG_INIT(fragp, max_bytes) riscv_init_frag (fragp, max_bytes)
> +extern void riscv_init_frag (struct frag *, int);
> +
> +#define obj_adjust_symtab() riscv_adjust_symtab ()
> +extern void riscv_adjust_symtab (void);
> +
> #endif /* TC_RISCV */
> diff --git a/gas/testsuite/gas/riscv/mapping-01.s b/gas/testsuite/gas/riscv/mapping-01.s
> new file mode 100644
> index 00000000000..0a270454b1b
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-01.s
> @@ -0,0 +1,18 @@
> + .option norvc
> + .text
> + .global funcA
> +funcA:
> + nop
> + j funcB
> +
> + .global funcB
> +funcB:
> + nop
> + bne a0, a1, funcB
> +
> + .data
> + .word 0x123456
> +
> + .section .foo, "ax"
> +foo:
> + nop
> diff --git a/gas/testsuite/gas/riscv/mapping-01a.d b/gas/testsuite/gas/riscv/mapping-01a.d
> new file mode 100644
> index 00000000000..32e0027a13d
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-01a.d
> @@ -0,0 +1,17 @@
> +#as:
> +#source: mapping-01.s
> +#objdump: --syms --special-syms
> +
> +.*file format.*riscv.*
> +
> +SYMBOL TABLE:
> +0+00 l d .text 0+00 .text
> +0+00 l d .data 0+00 .data
> +0+00 l d .bss 0+00 .bss
> +0+00 l .text 0+00 \$x
> +0+00 l d .foo 0+00 .foo
> +0+00 l .foo 0+00 foo
> +0+00 l .foo 0+00 \$x
> +0+00 l d .riscv.attributes 0+00 .riscv.attributes
> +0+00 g .text 0+00 funcA
> +0+08 g .text 0+00 funcB
> diff --git a/gas/testsuite/gas/riscv/mapping-01b.d b/gas/testsuite/gas/riscv/mapping-01b.d
> new file mode 100644
> index 00000000000..723bd5951cb
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-01b.d
> @@ -0,0 +1,21 @@
> +#as:
> +#source: mapping-01.s
> +#objdump: -d
> +
> +.*:[ ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <funcA>:
> +[ ]+0:[ ]+00000013[ ]+nop
> +[ ]+4:[ ]+0040006f[ ]+j[ ]+8 <funcB>
> +
> +0+008 <funcB>:
> +[ ]+8:[ ]+00000013[ ]+nop
> +[ ]+c:[ ]+feb51ee3[ ]+bne[ ]+a0,a1,8 <funcB>
> +
> +Disassembly of section .foo:
> +
> +0+000 <foo>:
> +[ ]+0:[ ]+00000013[ ]+nop
> diff --git a/gas/testsuite/gas/riscv/mapping-02.s b/gas/testsuite/gas/riscv/mapping-02.s
> new file mode 100644
> index 00000000000..d3de6dedac8
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-02.s
> @@ -0,0 +1,13 @@
> + .option norvc
> + .text
> + .global main
> + .type main, %function
> +main:
> + nop
> +foo:
> + nop
> + nop
> + .size main, .-main
> + .ident ""
> +
> + nop
> diff --git a/gas/testsuite/gas/riscv/mapping-02a.d b/gas/testsuite/gas/riscv/mapping-02a.d
> new file mode 100644
> index 00000000000..d0cb460e08e
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-02a.d
> @@ -0,0 +1,15 @@
> +#as:
> +#source: mapping-02.s
> +#objdump: --syms --special-syms
> +
> +.*file format.*riscv.*
> +
> +SYMBOL TABLE:
> +0+00 l d .text 0+00 .text
> +0+00 l d .data 0+00 .data
> +0+00 l d .bss 0+00 .bss
> +0+00 l .text 0+00 \$x
> +0+04 l .text 0+00 foo
> +0+00 l d .comment 0+00 .comment
> +0+00 l d .riscv.attributes 0+00 .riscv.attributes
> +0+00 g F .text 0+0c main
> diff --git a/gas/testsuite/gas/riscv/mapping-02b.d b/gas/testsuite/gas/riscv/mapping-02b.d
> new file mode 100644
> index 00000000000..3e875600a9c
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-02b.d
> @@ -0,0 +1,16 @@
> +#as:
> +#source: mapping-02.s
> +#objdump: -d
> +
> +.*:[ ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 :
> +[ ]+0:[ ]+00000013[ ]+nop
> +
> +0+004 <foo>:
> +[ ]+4:[ ]+00000013[ ]+nop
> +[ ]+8:[ ]+00000013[ ]+nop
> +[ ]+c:[ ]+00000013[ ]+nop
> diff --git a/gas/testsuite/gas/riscv/mapping-03.s b/gas/testsuite/gas/riscv/mapping-03.s
> new file mode 100644
> index 00000000000..49964f20288
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-03.s
> @@ -0,0 +1,10 @@
> + .option norvc
> + .text
> + .word 0
> + nop
> + .data
> + .word 0
> + .text
> + nop
> + .short 0
> + nop
> diff --git a/gas/testsuite/gas/riscv/mapping-03a.d b/gas/testsuite/gas/riscv/mapping-03a.d
> new file mode 100644
> index 00000000000..8567820b941
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-03a.d
> @@ -0,0 +1,16 @@
> +#as:
> +#source: mapping-03.s
> +#objdump: --syms --special-syms
> +
> +.*file format.*riscv.*
> +
> +SYMBOL TABLE:
> +0+00 l d .text 0+00 .text
> +0+00 l d .data 0+00 .data
> +0+00 l d .bss 0+00 .bss
> +0+00 l .text 0+00 \$d4
> +0+04 l .text 0+00 \$x
> +0+0c l .text 0+00 \$d2
> +0+0e l .text 0+00 \$x
> +0+12 l .text 0+00 \$a
> +0+00 l d .riscv.attributes 0+00 .riscv.attributes
> diff --git a/gas/testsuite/gas/riscv/mapping-03b.d b/gas/testsuite/gas/riscv/mapping-03b.d
> new file mode 100644
> index 00000000000..ed87fcf33d2
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-03b.d
> @@ -0,0 +1,16 @@
> +#as:
> +#source: mapping-03.s
> +#objdump: -d
> +
> +.*:[ ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <.text>:
> +[ ]+0:[ ]+00000000[ ]+.word[ ]+0x00000000
> +[ ]+4:[ ]+00000013[ ]+nop
> +[ ]+8:[ ]+00000013[ ]+nop
> +[ ]+c:[ ]+0000[ ]+.short[ ]+0x0000
> +[ ]+e:[ ]+00000013[ ]+nop
> +#...
> diff --git a/gas/testsuite/gas/riscv/mapping-04.s b/gas/testsuite/gas/riscv/mapping-04.s
> new file mode 100644
> index 00000000000..36bfac11050
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-04.s
> @@ -0,0 +1,11 @@
> + .option norvc
> + .text
> + nop
> + .long 0
> + .align 4
> + .word 0x12345678
> + nop
> + .byte 1
> + .long 0
> + .align 4
> + .word 0x12345678
> diff --git a/gas/testsuite/gas/riscv/mapping-04a.d b/gas/testsuite/gas/riscv/mapping-04a.d
> new file mode 100644
> index 00000000000..a3bb31a98b4
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-04a.d
> @@ -0,0 +1,21 @@
> +#as:
> +#source: mapping-04.s
> +#objdump: --syms --special-syms
> +
> +.*file format.*riscv.*
> +
> +SYMBOL TABLE:
> +0+00 l d .text 0+00 .text
> +0+00 l d .data 0+00 .data
> +0+00 l d .bss 0+00 .bss
> +0+00 l .text 0+00 \$x
> +0+04 l .text 0+00 \$d4
> +0+08 l .text 0+00 \$a
> +0+14 l .text 0+00 \$d4
> +0+18 l .text 0+00 \$x
> +0+1c l .text 0+00 \$d1
> +0+1d l .text 0+00 \$d4
> +0+21 l .text 0+00 \$a
> +0+2d l .text 0+00 \$d4
> +0+31 l .text 0+00 \$a
> +0+00 l d .riscv.attributes 0+00 .riscv.attributes
> diff --git a/gas/testsuite/gas/riscv/mapping-04b.d b/gas/testsuite/gas/riscv/mapping-04b.d
> new file mode 100644
> index 00000000000..d27b98db2ae
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-04b.d
> @@ -0,0 +1,24 @@
> +#as:
> +#source: mapping-04.s
> +#objdump: -d
> +
> +.*:[ ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <.text>:
> +[ ]+0:[ ]+00000013[ ]+nop
> +[ ]+4:[ ]+00000000[ ]+.word[ ]+0x00000000
> +[ ]+8:[ ]+00000013[ ]+align.nop
> +[ ]+c:[ ]+00000013[ ]+align.nop
> +[ ]+10:[ ]+00000013[ ]+align.nop
> +[ ]+14:[ ]+12345678[ ]+.word[ ]+0x12345678
> +[ ]+18:[ ]+00000013[ ]+nop
> +[ ]+1c:[ ]+01[ ]+.byte[ ]+0x01
> +[ ]+1d:[ ]+00000000[ ]+.word[ ]+0x00000000
> +[ ]+21:[ ]+00000013[ ]+align.nop
> +[ ]+25:[ ]+00000013[ ]+align.nop
> +[ ]+29:[ ]+00000013[ ]+align.nop
> +[ ]+2d:[ ]+12345678[ ]+.word[ ]+0x12345678
> +#...
> diff --git a/gas/testsuite/gas/riscv/mapping-norelax-04a.d b/gas/testsuite/gas/riscv/mapping-norelax-04a.d
> new file mode 100644
> index 00000000000..785b9d9f922
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-norelax-04a.d
> @@ -0,0 +1,23 @@
> +#as: -mno-relax
> +#source: mapping-04.s
> +#objdump: --syms --special-syms
> +
> +.*file format.*riscv.*
> +
> +SYMBOL TABLE:
> +0+00 l d .text 0+00 .text
> +0+00 l d .data 0+00 .data
> +0+00 l d .bss 0+00 .bss
> +0+00 l .text 0+00 \$x
> +0+04 l .text 0+00 \$d4
> +0+08 l .text 0+00 \$a
> +0+10 l .text 0+00 \$d4
> +0+14 l .text 0+00 \$x
> +0+18 l .text 0+00 \$d1
> +0+19 l .text 0+00 \$d4
> +0+20 l .text 0+00 \$d4
> +0+24 l .text 0+00 \$a
> +0+1d l .text 0+00 \$a1
> +0+1e l .text 0+00 \$a
> +# Maybe section symbol for .riscv.attributes
> +#...
> diff --git a/gas/testsuite/gas/riscv/mapping-norelax-04b.d b/gas/testsuite/gas/riscv/mapping-norelax-04b.d
> new file mode 100644
> index 00000000000..8765c6cd129
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/mapping-norelax-04b.d
> @@ -0,0 +1,25 @@
> +#as: -mno-relax
> +#source: mapping-04.s
> +#objdump: -d
> +
> +.*:[ ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <.text>:
> +[ ]+0:[ ]+00000013[ ]+nop
> +[ ]+4:[ ]+00000000[ ]+.word[ ]+0x00000000
> +[ ]+8:[ ]+00000013[ ]+align.nop
> +[ ]+c:[ ]+00000013[ ]+align.nop
> +[ ]+10:[ ]+12345678[ ]+.word[ ]+0x12345678
> +[ ]+14:[ ]+00000013[ ]+nop
> +[ ]+18:[ ]+01[ ]+.byte[ ]+0x01
> +[ ]+19:[ ]+00000000[ ]+.word[ ]+0x00000000
> +[ ]+1d:[ ]+00[ ]+align.byte
> +[ ]+1e:[ ]+0001[ ]+align.nop
> +[ ]+20:[ ]+12345678[ ]+.word[ ]+0x12345678
> +[ ]+24:[ ]+00000013[ ]+align.nop
> +[ ]+28:[ ]+00000013[ ]+align.nop
> +[ ]+2c:[ ]+00000013[ ]+align.nop
> +#...
> diff --git a/gas/testsuite/gas/riscv/no-relax-align-2.d b/gas/testsuite/gas/riscv/no-relax-align-2.d
> index 7407b495a8f..3c4323cc186 100644
> --- a/gas/testsuite/gas/riscv/no-relax-align-2.d
> +++ b/gas/testsuite/gas/riscv/no-relax-align-2.d
> @@ -7,13 +7,14 @@
> Disassembly of section .text:
>
> 0+000 <.text>:
> -[ ]+0:[ ]+0000[ ]+unimp
> -[ ]+2:[ ]+0001[ ]+nop
> -[ ]+4:[ ]+00000013[ ]+nop
> -[ ]+8:[ ]+00000013[ ]+nop
> -[ ]+c:[ ]+00000013[ ]+nop
> +[ ]+0:[ ]+00[ ]+.byte[ ]+0x00
> +[ ]+1:[ ]+00[ ]+align.byte
> +[ ]+2:[ ]+0001[ ]+align.nop
> +[ ]+4:[ ]+00000013[ ]+align.nop
> +[ ]+8:[ ]+00000013[ ]+align.nop
> +[ ]+c:[ ]+00000013[ ]+align.nop
> [ ]+10:[ ]+0001[ ]+nop
> -[ ]+12:[ ]+0001[ ]+nop
> -[ ]+14:[ ]+00000013[ ]+nop
> -[ ]+18:[ ]+00000013[ ]+nop
> -[ ]+1c:[ ]+00000013[ ]+nop
> +[ ]+12:[ ]+0001[ ]+align.nop
> +[ ]+14:[ ]+00000013[ ]+align.nop
> +[ ]+18:[ ]+00000013[ ]+align.nop
> +[ ]+1c:[ ]+00000013[ ]+align.nop
> diff --git a/gas/testsuite/gas/riscv/no-relax-align.d b/gas/testsuite/gas/riscv/no-relax-align.d
> index ced07d3c830..960db2a58bc 100644
> --- a/gas/testsuite/gas/riscv/no-relax-align.d
> +++ b/gas/testsuite/gas/riscv/no-relax-align.d
> @@ -9,5 +9,5 @@ Disassembly of section .text:
> 0+000 <.text>:
> [ ]+0:[ ]+00000013[ ]+nop
> [ ]+4:[ ]+00000013[ ]+nop
> -[ ]+8:[ ]+00000013[ ]+nop
> -[ ]+c:[ ]+00000013[ ]+nop
> +[ ]+8:[ ]+00000013[ ]+align.nop
> +[ ]+c:[ ]+00000013[ ]+align.nop
> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> index fdf3df4f5c1..3cea9e93c96 100644
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -425,6 +425,19 @@ enum
> M_NUM_MACROS
> };
>
> +/* The mapping symbol states. */
> +enum riscv_seg_mstate
> +{
> + MAP_NONE = 0, /* Must be zero, for seginfo in new sections. */
> + MAP_DATA, /* The rs_fill and rs_align. */
> + MAP_DATA_CONS0, /* Added for cons_worker, with the data size. */
> + MAP_DATA_CONS1,
> + MAP_DATA_CONS2,
> + MAP_DATA_CONS3,
> + MAP_INSN, /* Instructions. */
> + MAP_ALIGN, /* The rs_align_code, added nops. */
> + MAP_ALIGN_ODD, /* The rs_align_code, added odd byte. */
> +};
>
> extern const char * const riscv_gpr_names_numeric[NGPR];
> extern const char * const riscv_gpr_names_abi[NGPR];
> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
> index fe8dfb88d90..b41cad8f4aa 100644
> --- a/opcodes/riscv-dis.c
> +++ b/opcodes/riscv-dis.c
> @@ -41,6 +41,12 @@ struct riscv_private_data
> bfd_vma hi_addr[OP_MASK_RD + 1];
> };
>
> +/* Used for mapping symbols. */
> +static int last_map_symbol = -1;
> +static bfd_vma last_stop_offset = 0;
> +static asection *last_section = NULL;
> +enum riscv_seg_mstate last_map_state;
> +
> static const char * const *riscv_gpr_names;
> static const char * const *riscv_fpr_names;
>
> @@ -507,6 +513,27 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
> if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
> continue;
>
> + /* Add the "align." prefix if it is used for alignment.
> +
> + Consider the following case,
> + .text
> + .byte 0
> + nop
> +
> + 0000000000000000 <.text>:
> + 0: 00 .byte 0x00
> + 1: 00000013 nop
> + 5: 0000 align.unimp
> + ...
> +
> + The tail section alignments are not handled in the
> + riscv_frag_align_code, and since the relax is enable,
> + it cannot be filled with nops in the riscv_handle_align
> + either. Therefore, we may get align.unimp at the end
> + of the sections, I think this is expected. */
> + if (last_map_state == MAP_ALIGN)
> + (*info->fprintf_func) (info->stream, "align.");
> +
> /* It's a match. */
> (*info->fprintf_func) (info->stream, "%s", op->name);
> print_insn_args (op->args, word, memaddr, info);
> @@ -556,13 +583,238 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
> return insnlen;
> }
>
> +/* Return true if we find the suitable mapping symbol,
> + and also update the STATE. Otherwise, return false. */
> +
> +static bool
> +riscv_get_map_state (int n,
> + enum riscv_seg_mstate *state,
> + struct disassemble_info *info)
> +{
> + const char *name;
> +
> + /* If the symbol is in a different section, ignore it. */
> + if (info->section != NULL
> + && info->section != info->symtab[n]->section)
> + return false;
> +
> + name = bfd_asymbol_name(info->symtab[n]);
> + if (strcmp (name, "$x") == 0)
> + *state = MAP_INSN;
> + else if (strcmp (name, "$d") == 0)
> + *state = MAP_DATA;
> + else if (strcmp (name, "$d1") == 0)
> + *state = MAP_DATA_CONS0;
> + else if (strcmp (name, "$d2") == 0)
> + *state = MAP_DATA_CONS1;
> + else if (strcmp (name, "$d4") == 0)
> + *state = MAP_DATA_CONS2;
> + else if (strcmp (name, "$d8") == 0)
> + *state = MAP_DATA_CONS3;
> + else if (strcmp (name, "$a") == 0)
> + *state = MAP_ALIGN;
> + else if (strcmp (name, "$a1") == 0)
> + *state = MAP_ALIGN_ODD;
> + else
> + return false;
> +
> + return true;
> +}
> +
> +/* Check the sorted symbol table (sorted by the symbol value), find the
> + suitable mapping symbols. */
> +
> +static enum riscv_seg_mstate
> +riscv_search_mapping_symbol (bfd_vma memaddr,
> + struct disassemble_info *info)
> +{
> + enum riscv_seg_mstate mstate;
> + bool from_last_map_symbol;
> + bool found = false;
> + int symbol = -1;
> + int n;
> +
> + /* Decide whether to print the data or instruction by default, in case
> + we can not find the corresponding mapping symbols. */
> + mstate = MAP_DATA;
> + if ((info->section
> + && info->section->flags & SEC_CODE)
> + || !info->section)
> + mstate = MAP_INSN;
> +
> + if (info->symtab_size == 0
> + || bfd_asymbol_flavour (*info->symtab) != bfd_target_elf_flavour)
> + return mstate;
> +
> + /* Reset the last_map_symbol if we start to dump a new section. */
> + if (memaddr <= 0)
> + last_map_symbol = -1;
> +
> + /* If the last stop offset is different from the current one, then
> + don't use the last_map_symbol to search. We usually reset the
> + info->stop_offset when handling a new section. */
> + from_last_map_symbol = (last_map_symbol >= 0
> + && info->stop_offset == last_stop_offset);
> +
> + /* Start scanning at the start of the function, or wherever
> + we finished last time. */
> + n = info->symtab_pos + 1;
> + if (from_last_map_symbol && n >= last_map_symbol)
> + n = last_map_symbol;
> +
> + /* Find the suitable mapping symbol to dump. */
> + for (; n < info->symtab_size; n++)
> + {
> + bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
> + /* We have searched all possible symbols in the range. */
> + if (addr > memaddr)
> + break;
> + if (riscv_get_map_state (n, &mstate, info))
> + {
> + symbol = n;
> + found = true;
> + /* Do not stop searching, in case there are some mapping
> + symbols have the same value, but have different names.
> + Use the last one. */
> + }
> + }
> +
> + /* We can not find the suitable mapping symbol above. Therefore, we
> + look forwards and try to find it again, but don't go pass the start
> + of the section. Otherwise a data section without mapping symbols
> + can pick up a text mapping symbol of a preceeding section. */
> + if (!found)
> + {
> + n = info->symtab_pos;
> + if (from_last_map_symbol && n >= last_map_symbol)
> + n = last_map_symbol;
> +
> + for (; n >= 0; n--)
> + {
> + bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
> + /* We have searched all possible symbols in the range. */
> + if (addr < (info->section ? info->section->vma : 0))
> + break;
> + /* Stop searching once we find the closed mapping symbol. */
> + if (riscv_get_map_state (n, &mstate, info))
> + {
> + symbol = n;
> + found = true;
> + break;
> + }
> + }
> + }
> +
> + /* Save the information for next use. */
> + last_map_symbol = symbol;
> + last_stop_offset = info->stop_offset;
> + last_section = info->section;
> +
> + return mstate;
> +}
> +
> +/* Decide which data size we should print. */
> +
> +static bfd_vma
> +riscv_data_length (bfd_vma memaddr,
> + enum riscv_seg_mstate mstate,
> + disassemble_info *info)
> +{
> + bfd_vma length;
> + bool found = false;
> +
> + switch (mstate)
> + {
> + case MAP_DATA: length = 0; break;
> + case MAP_DATA_CONS0: length = 1; break;
> + case MAP_DATA_CONS1: length = 2; break;
> + case MAP_DATA_CONS2: length = 4; break;
> + case MAP_DATA_CONS3: length = 8; break;
> + default: abort ();
> + }
> + if (length > 0)
> + return length;
> +
> + length = 4;
> + if (info->symtab_size != 0
> + && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour
> + && last_map_symbol >= 0)
> + {
> + int n;
> + enum riscv_seg_mstate m = MAP_NONE;
> + for (n = last_map_symbol + 1; n < info->symtab_size; n++)
> + {
> + bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
> + if (addr > memaddr
> + && riscv_get_map_state (n, &m, info))
> + {
> + if (addr - memaddr < length)
> + length = addr - memaddr;
> + found = true;
> + break;
> + }
> + }
> + }
> + if (!found)
> + {
> + /* Do not set the length which exceeds the section size. */
> + bfd_vma offset = info->section->vma + info->section->size;
> + offset -= memaddr;
> + length = (offset < length) ? offset : length;
> + }
> + length = length == 3 ? 2 : length;
> + return length;
> +}
> +
> +/* Dump the data contents. */
> +
> +static int
> +riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED,
> + insn_t data,
> + disassemble_info *info)
> +{
> + info->display_endian = info->endian;
> +
> + switch (info->bytes_per_chunk)
> + {
> + case 1:
> + info->bytes_per_line = 6;
> + if (last_map_state == MAP_ALIGN_ODD)
> + (*info->fprintf_func) (info->stream, "align.byte");
> + else
> + (*info->fprintf_func) (info->stream, ".byte\t0x%02llx",
> + (unsigned long long) data);
> + break;
> + case 2:
> + info->bytes_per_line = 8;
> + (*info->fprintf_func) (info->stream, ".short\t0x%04llx",
> + (unsigned long long) data);
> + break;
> + case 4:
> + info->bytes_per_line = 8;
> + (*info->fprintf_func) (info->stream, ".word\t0x%08llx",
> + (unsigned long long) data);
> + break;
> + case 8:
> + info->bytes_per_line = 8;
> + (*info->fprintf_func) (info->stream, ".dword\t0x%016llx",
> + (unsigned long long) data);
> + break;
> + default:
> + abort ();
> + }
> + return info->bytes_per_chunk;
> +}
> +
> int
> print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
> {
> - bfd_byte packet[2];
> + bfd_byte packet[8];
> insn_t insn = 0;
> - bfd_vma n;
> + bfd_vma dump_size;
> int status;
> + enum riscv_seg_mstate mstate;
> + int (*riscv_disassembler) (bfd_vma, insn_t, struct disassemble_info *);
>
> if (info->disassembler_options != NULL)
> {
> @@ -573,23 +825,59 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
> else if (riscv_gpr_names == NULL)
> set_default_riscv_dis_options ();
>
> - /* Instructions are a sequence of 2-byte packets in little-endian order. */
> - for (n = 0; n < sizeof (insn) && n < riscv_insn_length (insn); n += 2)
> + mstate = riscv_search_mapping_symbol (memaddr, info);
> + /* Save the last mapping state. */
> + last_map_state = mstate;
> +
> + /* Set the size to dump. */
> + if (mstate == MAP_DATA
> + || mstate == MAP_DATA_CONS0
> + || mstate == MAP_DATA_CONS1
> + || mstate == MAP_DATA_CONS2
> + || mstate == MAP_DATA_CONS3)
> {
> - status = (*info->read_memory_func) (memaddr + n, packet, 2, info);
> + /* The documentation for -D says that on Arm platforms -D should
> + disassemble instructions. Therefore, they dump data by searching
> + mapping symbols only when the DISASSEMBLE_DATA is set. That causes
> + the mapping symbols are useless for -D. I am not sure if any riscv
> + document had mentioned this, so I prefer to keep them useful, but
> + only for text sections. If we decide not only to support mapping
> + symbols for text sections, then the riscv_mapping_state in the
> + gas/config/tc-riscv.c should be updated. */
> + dump_size = riscv_data_length (memaddr, mstate, info);
> + info->bytes_per_chunk = dump_size;
> + riscv_disassembler = riscv_disassemble_data;
> + }
> + else if (mstate == MAP_ALIGN_ODD)
> + {
> + dump_size = 1;
> + info->bytes_per_chunk = dump_size;
> + riscv_disassembler = riscv_disassemble_data;
> + }
> + else
> + {
> + /* Get the first 2-bytes to check the lenghth of instruction. */
> + status = (*info->read_memory_func) (memaddr, packet, 2, info);
> if (status != 0)
> {
> - /* Don't fail just because we fell off the end. */
> - if (n > 0)
> - break;
> (*info->memory_error_func) (status, memaddr, info);
> - return status;
> + return 1;
> }
> + insn = (insn_t) bfd_getl16 (packet);
> + dump_size = riscv_insn_length (insn);
> + riscv_disassembler = riscv_disassemble_insn;
> + }
>
> - insn |= ((insn_t) bfd_getl16 (packet)) << (8 * n);
> + /* Fetch the instruction to dump. */
> + status = (*info->read_memory_func) (memaddr, packet, dump_size, info);
> + if (status != 0)
> + {
> + (*info->memory_error_func) (status, memaddr, info);
> + return 1;
> }
> + insn = (insn_t) bfd_get_bits (packet, dump_size * 8, false);
>
> - return riscv_disassemble_insn (memaddr, insn, info);
> + return (*riscv_disassembler) (memaddr, insn, info);
> }
>
> disassembler_ftype
> @@ -631,7 +919,8 @@ riscv_symbol_is_valid (asymbol * sym,
>
> name = bfd_asymbol_name (sym);
>
> - return (strcmp (name, RISCV_FAKE_LABEL_NAME) != 0);
> + return (strcmp (name, RISCV_FAKE_LABEL_NAME) != 0
> + && !riscv_elf_is_mapping_symbols (name));
> }
>
> void