[PATCH v3 1/2] RISC-V: PR27916, Support mapping symbols.

Nelson Chu nelson.chu@sifive.com
Tue Jul 13 10:09:38 GMT 2021


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, and the $x means instruction.  Then the disassembler uses these
symbols to decide whether we should dump data or instruction.

Consider the mapping-04 test case,
$ cat tmp.s
  .text
  .option norelax
  .option norvc
  .fill 2, 4, 0x1001
  .byte 1
  .word 0
  .balign 8
  add a0, a0, a0
  .fill 5, 2, 0x2002
  add a1, a1, a1
  .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  # Marked $d, .fill directive.
   4:   00001001         .word   0x00001001
   8:   00000001         .word   0x00000001  # .byte + part of .word.
   c:   00               .byte   0x00        # remaining .word.
   d:   00               .byte   0x00        # Marked $d, odd byte of alignment.
   e:   0001             nop                 # Marked $x, nops for alignment.
  10:   00a50533         add     a0,a0,a0
  14:   20022002         .word   0x20022002  # Marked $d, .fill directive.
  18:   20022002         .word   0x20022002
  1c:   2002             .short  0x2002
  1e:   00b585b3         add     a1,a1,a1    # Marked $x.
  22:   0001             nop                 # Section tail alignment.
  24:   00000013         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 ...

* Use $d and $x to mark the distribution of data and instructions.
  Alignments of code are recognized as instructions, since we usually
  fill nops for them.

* If the alignment have odd bytes, then we cannot just fill the nops
  into the spaces.  We always fill an odd byte 0x00 at the start of
  the spaces.  Therefore, add a $d mapping symbol for the odd byte,
  to tell disassembler that it isn't an instruction.  The behavior
  is same as Arm and Aarch64.

* 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.

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
	* 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 mapping symbols for the
	riscv_handle_align, which have odd bytes spaces.
	(riscv_check_mapping_symbols): Remove any excess mapping symbols.
	(md_assemble): Marked as MAP_INSN.
	(riscv_frag_align_code): Marked as MAP_INSN.
	(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 MAP_INSN 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.
	(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_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.
	(print_insn_riscv): Handle the mapping symbols.
	(riscv_symbol_is_valid): Marked mapping symbols as invalid.
---
 bfd/cpu-riscv.c                               |   9 +
 bfd/cpu-riscv.h                               |   3 +
 bfd/elfnn-riscv.c                             |  25 +-
 binutils/readelf.c                            |   2 +-
 binutils/testsuite/binutils-all/readelf.s-64  |   4 +-
 .../binutils-all/readelf.s-64-unused          |   4 +-
 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                         | 200 +++++++++++++-
 gas/config/tc-riscv.h                         |  24 ++
 gas/testsuite/gas/riscv/mapping-01.s          |  17 ++
 gas/testsuite/gas/riscv/mapping-01a.d         |  17 ++
 gas/testsuite/gas/riscv/mapping-01b.d         |  21 ++
 gas/testsuite/gas/riscv/mapping-02.s          |  12 +
 gas/testsuite/gas/riscv/mapping-02a.d         |  15 ++
 gas/testsuite/gas/riscv/mapping-02b.d         |  16 ++
 gas/testsuite/gas/riscv/mapping-03.s          |  11 +
 gas/testsuite/gas/riscv/mapping-03a.d         |  20 ++
 gas/testsuite/gas/riscv/mapping-03b.d         |  24 ++
 gas/testsuite/gas/riscv/mapping-04.s          |  13 +
 gas/testsuite/gas/riscv/mapping-04a.d         |  15 ++
 gas/testsuite/gas/riscv/mapping-04b.d         |  23 ++
 gas/testsuite/gas/riscv/mapping-norelax-03a.d |  21 ++
 gas/testsuite/gas/riscv/mapping-norelax-03b.d |  25 ++
 gas/testsuite/gas/riscv/mapping-norelax-04a.d |  16 ++
 gas/testsuite/gas/riscv/mapping-norelax-04b.d |  24 ++
 gas/testsuite/gas/riscv/no-relax-align-2.d    |   3 +-
 include/opcode/riscv.h                        |   7 +
 opcodes/riscv-dis.c                           | 252 +++++++++++++++++-
 31 files changed, 813 insertions(+), 28 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-03a.d
 create mode 100644 gas/testsuite/gas/riscv/mapping-norelax-03b.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..813f2c3df8d 100644
--- a/bfd/cpu-riscv.c
+++ b/bfd/cpu-riscv.c
@@ -140,3 +140,12 @@ 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));
+}
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 5682837ed7b..f0666f0e20b 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -20276,7 +20276,7 @@ get_symbol_for_build_attribute (Filedata *filedata,
 	if (ba_cache.strtab[sym->st_name] == 0)
 	  continue;
 
-	/* The AArch64 and ARM architectures define mapping symbols
+	/* The AArch64, ARM and RISC-V architectures define mapping symbols
 	   (eg $d, $x, $t) which we want to ignore.  */
 	if (ba_cache.strtab[sym->st_name] == '$'
 	    && ba_cache.strtab[sym->st_name + 1] != 0
diff --git a/binutils/testsuite/binutils-all/readelf.s-64 b/binutils/testsuite/binutils-all/readelf.s-64
index 4c957f7a938..e0037a56954 100644
--- a/binutils/testsuite/binutils-all/readelf.s-64
+++ b/binutils/testsuite/binutils-all/readelf.s-64
@@ -19,8 +19,8 @@ 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 two more symbols, data symbol and .riscv.attributes.
+ +0+.* +0000000000000018 +(6|7) +(3|4|5) +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..45b24eb22cb 100644
--- a/binutils/testsuite/binutils-all/readelf.s-64-unused
+++ b/binutils/testsuite/binutils-all/readelf.s-64-unused
@@ -19,8 +19,8 @@ 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 two more symbols, data symbol and .riscv.attributes.
+ +0+.* +0000000000000018 +(6|7) +(6|7|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.ss b/binutils/testsuite/binutils-all/readelf.ss
index b81c016e9e7..1e1f40c9831 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 $d mapping symbol 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..c8c26dc92be 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 $d mapping symbol 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..80a289c76a4 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 $d mapping symbol 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..18379d2bc9d 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -561,6 +561,156 @@ 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_INSN:
+      name = "$x";
+      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;
+
+  /* The mapping symbol should be emitted.  */
+  if (from_state == to_state)
+    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_DATA, frag->fr_fix, frag);
+  make_mapping_symbol (MAP_INSN, 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 +2917,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 +3574,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_INSN, worst_case_bytes);
+
   return true;
 }
 
@@ -3441,6 +3595,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 +3604,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 +3628,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_INSN, max_chars);
+      break;
+    default:
+      break;
+    }
+}
+
 int
 md_estimate_size_before_relax (fragS *fragp, asection *segtype)
 {
@@ -3721,6 +3908,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 +4000,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..d035eed8a93 100644
--- a/gas/config/tc-riscv.h
+++ b/gas/config/tc-riscv.h
@@ -128,4 +128,28 @@ 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) riscv_mapping_state (MAP_DATA, 0)
+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..000209886e2
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-01.s
@@ -0,0 +1,17 @@
+	.option norvc
+	.text
+	.global	funcA
+funcA:
+	add	a0, a0, a0
+	j	funcB
+	.global	funcB
+funcB:
+	add	a1, a1, a1
+	bne	a0, a1, funcB
+
+	.data
+	.word 0x123456
+
+	.section	.foo, "ax"
+foo:
+	add	a2, a2, a2
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..e84b3d608f5
--- /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:[ 	]+00a50533[ 	]+add[ 	]+a0,a0,a0
+[ 	]+4:[ 	]+0040006f[ 	]+j[ 	]+8 <funcB>
+
+0+008 <funcB>:
+[ 	]+8:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
+[ 	]+c:[ 	]+feb51ee3[ 	]+bne[ 	]+a0,a1,8 <funcB>
+
+Disassembly of section .foo:
+
+0+000 <foo>:
+[ 	]+0:[ 	]+00c60633[ 	]+add[ 	]+a2,a2,a2
diff --git a/gas/testsuite/gas/riscv/mapping-02.s b/gas/testsuite/gas/riscv/mapping-02.s
new file mode 100644
index 00000000000..f8306d0643e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-02.s
@@ -0,0 +1,12 @@
+	.option norvc
+	.text
+	.word	1
+	add	a0, a0, a0
+
+	.data
+	.word	2
+
+	.text
+	add	a1, a1, a1
+	.short	3
+	add	a2, a2, a2
diff --git a/gas/testsuite/gas/riscv/mapping-02a.d b/gas/testsuite/gas/riscv/mapping-02a.d
new file mode 100644
index 00000000000..333f12cd343
--- /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 \$d
+0+04 l       .text	0+00 \$x
+0+0c l       .text	0+00 \$d
+0+0e l       .text	0+00 \$x
+0+00 l    d  .riscv.attributes	0+00 .riscv.attributes
diff --git a/gas/testsuite/gas/riscv/mapping-02b.d b/gas/testsuite/gas/riscv/mapping-02b.d
new file mode 100644
index 00000000000..1ed6c081cf7
--- /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 <.text>:
+[ 	]+0:[ 	]+00000001[ 	]+.word[ 	]+0x00000001
+[ 	]+4:[ 	]+00a50533[ 	]+add[ 	]+a0,a0,a0
+[ 	]+8:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
+[ 	]+c:[ 	]+0003[ 	]+.short[ 	]+0x0003
+[ 	]+e:[ 	]+00c60633[ 	]+add[ 	]+a2,a2,a2
+#...
diff --git a/gas/testsuite/gas/riscv/mapping-03.s b/gas/testsuite/gas/riscv/mapping-03.s
new file mode 100644
index 00000000000..a099eacc7f7
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-03.s
@@ -0,0 +1,11 @@
+	.option norvc
+	.text
+	add	a0, a0, a0
+	.long	0
+	.balign	16
+	.word	1
+	add	a1, a1, a1
+	.byte	2
+	.long	3
+	.balign	16
+	.word	5
diff --git a/gas/testsuite/gas/riscv/mapping-03a.d b/gas/testsuite/gas/riscv/mapping-03a.d
new file mode 100644
index 00000000000..d3663b663aa
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-03a.d
@@ -0,0 +1,20 @@
+#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 \$x
+0+04 l       .text	0+00 \$d
+0+08 l       .text	0+00 \$x
+0+14 l       .text	0+00 \$d
+0+18 l       .text	0+00 \$x
+0+1c l       .text	0+00 \$d
+0+21 l       .text	0+00 \$x
+0+2d l       .text	0+00 \$d
+0+31 l       .text	0+00 \$x
+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..f4f67269981
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-03b.d
@@ -0,0 +1,24 @@
+#as:
+#source: mapping-03.s
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ 	]+0:[ 	]+00a50533[ 	]+add[ 	]+a0,a0,a0
+[ 	]+4:[ 	]+00000000[ 	]+.word[ 	]+0x00000000
+[ 	]+8:[ 	]+00000013[ 	]+nop
+[ 	]+c:[ 	]+00000013[ 	]+nop
+[ 	]+10:[ 	]+00000013[ 	]+nop
+[ 	]+14:[ 	]+00000001[ 	]+.word[ 	]+0x00000001
+[ 	]+18:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
+[ 	]+1c:[ 	]+00000302[ 	]+.word[ 	]+0x00000302
+[ 	]+20:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+21:[ 	]+00000013[ 	]+nop
+[ 	]+25:[ 	]+00000013[ 	]+nop
+[ 	]+29:[ 	]+00000013[ 	]+nop
+[ 	]+2d:[ 	]+00000005[ 	]+.word[ 	]+0x00000005
+#...
diff --git a/gas/testsuite/gas/riscv/mapping-04.s b/gas/testsuite/gas/riscv/mapping-04.s
new file mode 100644
index 00000000000..c597495b915
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-04.s
@@ -0,0 +1,13 @@
+	.text
+	.option	norvc
+	.fill	2, 4, 0x1001
+	.byte	1
+	.word	0
+	.balign	8
+	add	a0, a0, a0
+	.fill	5, 2, 0x2002
+	add	a1, a1, a1
+
+	.data
+	.word	0x1
+	.word	0x2
diff --git a/gas/testsuite/gas/riscv/mapping-04a.d b/gas/testsuite/gas/riscv/mapping-04a.d
new file mode 100644
index 00000000000..1ae9653212b
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-04a.d
@@ -0,0 +1,15 @@
+#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 \$d
+0+0d l       .text	0+00 \$x
+0+15 l       .text	0+00 \$d
+0+1f l       .text	0+00 \$x
+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..97354989e84
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-04b.d
@@ -0,0 +1,23 @@
+#as:
+#source: mapping-04.s
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ 	]+0:[ 	]+00001001[ 	]+.word[ 	]+0x00001001
+[ 	]+4:[ 	]+00001001[ 	]+.word[ 	]+0x00001001
+[ 	]+8:[ 	]+00000001[ 	]+.word[ 	]+0x00000001
+[ 	]+c:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+d:[ 	]+00000013[ 	]+nop
+[ 	]+11:[ 	]+00a50533[ 	]+add[ 	]+a0,a0,a0
+[ 	]+15:[ 	]+20022002[ 	]+.word[ 	]+0x20022002
+[ 	]+19:[ 	]+20022002[ 	]+.word[ 	]+0x20022002
+[ 	]+1d:[ 	]+2002[ 	]+.short[ 	]+0x2002
+[ 	]+1f:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
+[ 	]+23:[ 	]+0000[ 	]+unimp
+[ 	]+25:[ 	]+0000[ 	]+unimp
+#...
diff --git a/gas/testsuite/gas/riscv/mapping-norelax-03a.d b/gas/testsuite/gas/riscv/mapping-norelax-03a.d
new file mode 100644
index 00000000000..916f732b7f7
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-norelax-03a.d
@@ -0,0 +1,21 @@
+#as: -mno-relax
+#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 \$x
+0+04 l       .text	0+00 \$d
+0+08 l       .text	0+00 \$x
+0+10 l       .text	0+00 \$d
+0+14 l       .text	0+00 \$x
+0+18 l       .text	0+00 \$d
+0+20 l       .text	0+00 \$d
+0+24 l       .text	0+00 \$x
+0+1d l       .text	0+00 \$d
+0+1e l       .text	0+00 \$x
+0+00 l    d  .riscv.attributes	0+00 .riscv.attributes
diff --git a/gas/testsuite/gas/riscv/mapping-norelax-03b.d b/gas/testsuite/gas/riscv/mapping-norelax-03b.d
new file mode 100644
index 00000000000..ad88888d266
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-norelax-03b.d
@@ -0,0 +1,25 @@
+#as: -mno-relax
+#source: mapping-03.s
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ 	]+0:[ 	]+00a50533[ 	]+add[ 	]+a0,a0,a0
+[ 	]+4:[ 	]+00000000[ 	]+.word[ 	]+0x00000000
+[ 	]+8:[ 	]+00000013[ 	]+nop
+[ 	]+c:[ 	]+00000013[ 	]+nop
+[ 	]+10:[ 	]+00000001[ 	]+.word[ 	]+0x00000001
+[ 	]+14:[ 	]+00b585b3[ 	]+add[ 	]+a1,a1,a1
+[ 	]+18:[ 	]+00000302[ 	]+.word[ 	]+0x00000302
+[ 	]+1c:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+1d:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+1e:[ 	]+0001[ 	]+nop
+[ 	]+20:[ 	]+00000005[ 	]+.word[ 	]+0x00000005
+[ 	]+24:[ 	]+00000013[ 	]+nop
+[ 	]+28:[ 	]+00000013[ 	]+nop
+[ 	]+2c:[ 	]+00000013[ 	]+nop
+#...
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..d552a7f632a
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-norelax-04a.d
@@ -0,0 +1,16 @@
+#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 \$d
+0+14 l       .text	0+00 \$d
+0+1e l       .text	0+00 \$x
+0+0d l       .text	0+00 \$d
+0+0e l       .text	0+00 \$x
+0+00 l    d  .riscv.attributes	0+00 .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..824a898419f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/mapping-norelax-04b.d
@@ -0,0 +1,24 @@
+#as: -mno-relax
+#source: mapping-04.s
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ 	]+0:[ 	]+00001001[ 	]+.word[ 	]+0x00001001
+[ 	]+4:[ 	]+00001001[ 	]+.word[ 	]+0x00001001
+[ 	]+8:[ 	]+00000001[ 	]+.word[ 	]+0x00000001
+[ 	]+c:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+d:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+e:[ 	]+0001[ 	]+nop
+[ 	]+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
+[ 	]+24:[ 	]+00000013[ 	]+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..19edf137ba8 100644
--- a/gas/testsuite/gas/riscv/no-relax-align-2.d
+++ b/gas/testsuite/gas/riscv/no-relax-align-2.d
@@ -7,7 +7,8 @@
 Disassembly of section .text:
 
 0+000 <.text>:
-[ 	]+0:[ 	]+0000[ 	]+unimp
+[ 	]+0:[ 	]+00[ 	]+.byte[ 	]+0x00
+[ 	]+1:[ 	]+00[ 	]+.byte[ 	]+0x00
 [ 	]+2:[ 	]+0001[ 	]+nop
 [ 	]+4:[ 	]+00000013[ 	]+nop
 [ 	]+8:[ 	]+00000013[ 	]+nop
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index fdf3df4f5c1..a8f47419f75 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -425,6 +425,13 @@ 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,		/* Data.  */
+  MAP_INSN,		/* Instructions.  */
+};
 
 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..2df8edce608 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -41,6 +41,11 @@ 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;
+enum riscv_seg_mstate last_map_state;
+
 static const char * const *riscv_gpr_names;
 static const char * const *riscv_fpr_names;
 
@@ -556,13 +561,209 @@ 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
+    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;
+
+  return mstate;
+}
+
+/* Decide which data size we should print.  */
+
+static bfd_vma
+riscv_data_length (bfd_vma memaddr,
+		   disassemble_info *info)
+{
+  bfd_vma length;
+  bool found = false;
+
+  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;
+      (*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 +774,49 @@ 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)
+    {
+      /* 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, info);
+      info->bytes_per_chunk = dump_size;
+      riscv_disassembler = riscv_disassemble_data;
+    }
+  else
     {
-      status = (*info->read_memory_func) (memaddr + n, packet, 2, info);
+      /* 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 +858,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
-- 
2.30.2



More information about the Binutils mailing list