diff options
31 files changed, 807 insertions, 28 deletions
diff --git a/bfd/cpu-riscv.c b/bfd/cpu-riscv.c index 025e94a..813f2c3 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 cafaca2..ed5ee7e 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 85a99f3..a10384c 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 582c9dc..4d33768 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -20304,7 +20304,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 4c957f7..e0037a5 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 7714394..45b24eb 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 b81c016..1e1f40c 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 c6ffb0f..c8c26dc 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 cf515aa..80a289c 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 3107af9..944ab45 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 460667e..bb6b063 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -561,6 +561,157 @@ 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 not in the right + mapping state */ + 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 + fragment. */ + 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 +2918,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) @@ -3421,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; } @@ -3440,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) @@ -3448,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; } @@ -3464,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) { @@ -3720,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); @@ -3810,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 1de1384..d035eed 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 0000000..0002098 --- /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 0000000..32e0027 --- /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 0000000..e84b3d6 --- /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 0000000..f8306d0 --- /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 0000000..333f12c --- /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 0000000..1ed6c08 --- /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 0000000..a099eac --- /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 0000000..d3663b6 --- /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 0000000..f4f6726 --- /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 0000000..c597495 --- /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 0000000..1ae9653 --- /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 0000000..9735498 --- /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 0000000..916f732 --- /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 0000000..ad88888 --- /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 0000000..d552a7f --- /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 0000000..824a898 --- /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 7407b49..19edf13 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 fdf3df4..a8f4741 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 fe8dfb8..30b42ef 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,42 @@ 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 + && (info->flags & DISASSEMBLE_DATA) == 0) + { + 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 +851,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 |