diff options
author | Nelson Chu <nelson@rivosinc.com> | 2022-09-29 19:07:46 +0800 |
---|---|---|
committer | Nelson Chu <nelson@rivosinc.com> | 2022-10-28 11:11:23 +0800 |
commit | 40f1a1a4564b2e5822cf19a43a8c15154aa4c488 (patch) | |
tree | 35f083a2767845714fce545b2789d0b903fa41b5 /gas/config/tc-riscv.c | |
parent | 58b2ba6d888019278887286e3896ff7ffd12cb2f (diff) | |
download | gdb-40f1a1a4564b2e5822cf19a43a8c15154aa4c488.zip gdb-40f1a1a4564b2e5822cf19a43a8c15154aa4c488.tar.gz gdb-40f1a1a4564b2e5822cf19a43a8c15154aa4c488.tar.bz2 |
RISC-V: Output mapping symbols with ISA string.
RISC-V Psabi pr196,
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/196
bfd/
* elfxx-riscv.c (riscv_release_subset_list): Free arch_str if needed.
(riscv_copy_subset_list): Copy arch_str as well.
* elfxx-riscv.h (riscv_subset_list_t): Store arch_str for each subset list.
gas/
* config/tc-riscv.c (riscv_reset_subsets_list_arch_str): Update the
architecture string in the subset_list.
(riscv_set_arch): Call riscv_reset_subsets_list_arch_str after parsing new
architecture string.
(s_riscv_option): Likewise.
(need_arch_map_symbol): New boolean, used to indicate if .option
directives do affect instructions.
(make_mapping_symbol): New boolean parameter reset_seg_arch_str. Need to
generate $x+arch for MAP_INSN, and then store it into tc_segment_info_data
if reset_seg_arch_str is true.
(riscv_mapping_state): Decide if we need to add $x+arch for MAP_INSN. For
now, only add $x+arch if the architecture strings in subset list and segment
are different. Besides, always add $x+arch at the start of section, and do
not add $x+arch for code alignment, since rvc for alignment can be judged
from addend of R_RISCV_ALIGN.
(riscv_remove_mapping_symbol): If current and previous mapping symbol have
same value, then remove the current $x only if the previous is $x+arch;
Otherwise, always remove previous.
(riscv_add_odd_padding_symbol): Updated.
(riscv_check_mapping_symbols): Don't need to add any $x+arch if
need_arch_map_symbol is false, so changed them to $x.
(riscv_frag_align_code): Updated since riscv_mapping_state is changed.
(riscv_init_frag): Likewise.
(s_riscv_insn): Likewise.
(riscv_elf_final_processing): Call riscv_release_subset_list to release
subset_list of riscv_rps_as, rather than only release arch_str in the
riscv_write_out_attrs.
(riscv_write_out_attrs): No need to call riscv_arch_str, just get arch_str
from subset_list of riscv_rps_as.
* config/tc-riscv.h (riscv_segment_info_type): Record current $x+arch mapping
symbol of each segment.
* testsuite/gas/riscv/mapping-0*: Merged and replaced by mapping.s.
* testsuite/gas/riscv/mapping.s: New testcase, to test most of the cases in
one file.
* testsuite/gas/riscv/mapping-symbols.d: Likewise.
* testsuite/gas/riscv/mapping-dis.d: Likewise.
* testsuite/gas/riscv/mapping-non-arch.s: New testcase for the case that
does need any $x+arch.
* testsuite/gas/riscv/mapping-non-arch.d: Likewise.
* testsuite/gas/riscv/option-arch-01a.d: Updated.
opcodes/
* riscv-dis.c (riscv_disassemble_insn): Set riscv_fpr_names back to
riscv_fpr_names_abi or riscv_fpr_names_numeric when zfinx is disabled
for some specfic code region.
(riscv_get_map_state): Recognized mapping symbols $x+arch, and then reset
the architecture string once the ISA is different.
Diffstat (limited to 'gas/config/tc-riscv.c')
-rw-r--r-- | gas/config/tc-riscv.c | 162 |
1 files changed, 127 insertions, 35 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 22385d1..91cff7d 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -279,6 +279,17 @@ static riscv_parse_subset_t riscv_rps_as = true, /* check_unknown_prefixed_ext. */ }; +/* Update the architecture string in the subset_list. */ + +static void +riscv_reset_subsets_list_arch_str (void) +{ + riscv_subset_list_t *subsets = riscv_rps_as.subset_list; + if (subsets->arch_str != NULL) + free ((void *) subsets->arch_str); + subsets->arch_str = riscv_arch_str (xlen, subsets); +} + /* This structure is used to hold a stack of .option values. */ struct riscv_option_stack { @@ -306,9 +317,11 @@ riscv_set_arch (const char *s) riscv_rps_as.subset_list = XNEW (riscv_subset_list_t); riscv_rps_as.subset_list->head = NULL; riscv_rps_as.subset_list->tail = NULL; + riscv_rps_as.subset_list->arch_str = NULL; } riscv_release_subset_list (riscv_rps_as.subset_list); riscv_parse_subset (&riscv_rps_as, s); + riscv_reset_subsets_list_arch_str (); riscv_set_rvc (false); if (riscv_subset_supports (&riscv_rps_as, "c")) @@ -457,21 +470,37 @@ static char *expr_end; #define OPCODE_MATCHES(OPCODE, OP) \ (((OPCODE) & MASK_##OP) == MATCH_##OP) +/* Indicate if .option directives do affect instructions. Set to true means + we need to add $x+arch at somewhere; Otherwise just add $x for instructions + should be enough. */ +static bool need_arch_map_symbol = false; + /* Create a new mapping symbol for the transition to STATE. */ static void make_mapping_symbol (enum riscv_seg_mstate state, valueT value, - fragS *frag) + fragS *frag, + bool reset_seg_arch_str) { const char *name; + char *buff; switch (state) { case MAP_DATA: name = "$d"; break; case MAP_INSN: - name = "$x"; + if (reset_seg_arch_str) + { + const char *isa = riscv_rps_as.subset_list->arch_str; + size_t size = strlen (isa) + 3; /* "rv" + '\0' */ + buff = xmalloc (size); + snprintf (buff, size, "$x%s", isa); + name = buff; + } + else + name = "$x"; break; default: abort (); @@ -479,32 +508,38 @@ make_mapping_symbol (enum riscv_seg_mstate state, symbolS *symbol = symbol_new (name, now_seg, frag, value); symbol_get_bfdsym (symbol)->flags |= (BSF_NO_FLAGS | BSF_LOCAL); + if (reset_seg_arch_str) + { + /* Store current $x+arch into tc_segment_info. */ + seg_info (now_seg)->tc_segment_info_data.arch_map_symbol = symbol; + xfree ((void *) buff); + } /* 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. */ + then mapping symbol for the following code will have the same value. + + Please see gas/testsuite/gas/riscv/mapping.s: .text.zero.fill.first + and .text.zero.fill.last. */ + symbolS *first = frag->tc_frag_data.first_map_symbol; + symbolS *last = frag->tc_frag_data.last_map_symbol; if (value == 0) { - if (frag->tc_frag_data.first_map_symbol != NULL) + if (first != NULL) { - know (S_GET_VALUE (frag->tc_frag_data.first_map_symbol) - == S_GET_VALUE (symbol)); + know (S_GET_VALUE (first) == S_GET_VALUE (symbol) + && first == last); /* Remove the old one. */ - symbol_remove (frag->tc_frag_data.first_map_symbol, - &symbol_rootP, &symbol_lastP); + symbol_remove (first, &symbol_rootP, &symbol_lastP); } frag->tc_frag_data.first_map_symbol = symbol; } - if (frag->tc_frag_data.last_map_symbol != NULL) + else if (last != 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)); + know (S_GET_VALUE (last) <= 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); + if (S_GET_VALUE (last) == S_GET_VALUE (symbol)) + symbol_remove (last, &symbol_rootP, &symbol_lastP); } frag->tc_frag_data.last_map_symbol = symbol; } @@ -513,13 +548,15 @@ make_mapping_symbol (enum riscv_seg_mstate state, void riscv_mapping_state (enum riscv_seg_mstate to_state, - int max_chars) + int max_chars, + bool frag_align_code) { enum riscv_seg_mstate from_state = seg_info (now_seg)->tc_segment_info_data.map_state; + bool reset_seg_arch_str = false; if (!SEG_NORMAL (now_seg) - /* For now I only add the mapping symbols to text sections. + /* For now we 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. */ @@ -527,13 +564,29 @@ riscv_mapping_state (enum riscv_seg_mstate to_state, return; /* The mapping symbol should be emitted if not in the right - mapping state */ - if (from_state == to_state) + mapping state. */ + symbolS *seg_arch_symbol = + seg_info (now_seg)->tc_segment_info_data.arch_map_symbol; + if (to_state == MAP_INSN && seg_arch_symbol == 0) + { + /* Always add $x+arch at the first instruction of section. */ + reset_seg_arch_str = true; + } + else if (seg_arch_symbol != 0 + && to_state == MAP_INSN + && !frag_align_code + && strcmp (riscv_rps_as.subset_list->arch_str, + S_GET_NAME (seg_arch_symbol) + 2) != 0) + { + reset_seg_arch_str = true; + need_arch_map_symbol = true; + } + else 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); + make_mapping_symbol (to_state, value, frag_now, reset_seg_arch_str); } /* Add the odd bytes of paddings for riscv_handle_align. */ @@ -542,9 +595,27 @@ 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); + removed in the make_mapping_symbol. + + Please see gas/testsuite/gas/riscv/mapping.s: .text.odd.align. */ + make_mapping_symbol (MAP_DATA, frag->fr_fix, frag, false); + make_mapping_symbol (MAP_INSN, frag->fr_fix + 1, frag, false); +} + +/* If previous and current mapping symbol have same value, then remove the + current $x only if the previous is $x+arch; Otherwise, always remove the + previous. */ + +static void +riscv_remove_mapping_symbol (symbolS *pre, symbolS *cur) +{ + know (pre != NULL && cur != NULL + && S_GET_VALUE (pre) == S_GET_VALUE (cur)); + symbolS *removed = pre; + if (strncmp (S_GET_NAME (pre), "$xrv", 4) == 0 + && strcmp (S_GET_NAME (cur), "$x") == 0) + removed = cur; + symbol_remove (removed, &symbol_rootP, &symbol_lastP); } /* Remove any excess mapping symbols generated for alignment frags in @@ -563,6 +634,13 @@ riscv_check_mapping_symbols (bfd *abfd ATTRIBUTE_UNUSED, if (seginfo == NULL || seginfo->frchainP == NULL) return; + /* If we don't set any .option arch directive, then the arch_map_symbol + in each segment must be the first instruction, and we don't need to + add $x+arch for them. */ + if (!need_arch_map_symbol + && seginfo->tc_segment_info_data.arch_map_symbol != 0) + S_SET_NAME (seginfo->tc_segment_info_data.arch_map_symbol, "$x"); + for (fragp = seginfo->frchainP->frch_root; fragp != NULL; fragp = fragp->fr_next) @@ -581,17 +659,24 @@ riscv_check_mapping_symbols (bfd *abfd ATTRIBUTE_UNUSED, do { - if (next->tc_frag_data.first_map_symbol != NULL) + symbolS *next_first = next->tc_frag_data.first_map_symbol; + if (next_first != NULL) { /* The last mapping symbol overlaps with another one - which at the start of the next frag. */ - symbol_remove (last, &symbol_rootP, &symbol_lastP); + which at the start of the next frag. + + Please see the gas/testsuite/gas/riscv/mapping.s: + .text.zero.fill.align.A and .text.zero.fill.align.B. */ + riscv_remove_mapping_symbol (last, next_first); break; } if (next->fr_next == NULL) { - /* The last mapping symbol is at the end of the section. */ + /* The last mapping symbol is at the end of the section. + + Please see the gas/testsuite/gas/riscv/mapping.s: + .text.last.section. */ know (next->fr_fix == 0 && next->fr_var == 0); symbol_remove (last, &symbol_rootP, &symbol_lastP); break; @@ -3455,7 +3540,7 @@ md_assemble (char *str) return; } - riscv_mapping_state (MAP_INSN, 0); + riscv_mapping_state (MAP_INSN, 0, 0/* frag_align_code */); const struct riscv_ip_error error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash); @@ -3963,11 +4048,13 @@ s_riscv_option (int x ATTRIBUTE_UNUSED) if (strcmp (name, "rvc") == 0) { riscv_update_subset (&riscv_rps_as, "+c"); + riscv_reset_subsets_list_arch_str (); riscv_set_rvc (true); } else if (strcmp (name, "norvc") == 0) { riscv_update_subset (&riscv_rps_as, "-c"); + riscv_reset_subsets_list_arch_str (); riscv_set_rvc (false); } else if (strcmp (name, "pic") == 0) @@ -3988,6 +4075,7 @@ s_riscv_option (int x ATTRIBUTE_UNUSED) if (ISSPACE (*name) && *name != '\0') name++; riscv_update_subset (&riscv_rps_as, name); + riscv_reset_subsets_list_arch_str (); riscv_set_rvc (false); if (riscv_subset_supports (&riscv_rps_as, "c")) @@ -4117,6 +4205,10 @@ riscv_frag_align_code (int n) if (!riscv_opts.relax) return false; + /* Maybe we should use frag_var to create a new rs_align_code fragment, + rather than just use frag_more to handle an alignment here? So that we + don't need to call riscv_mapping_state again later, and then only need + to check frag->fr_type to see if it is frag_align_code. */ nops = frag_more (worst_case_bytes); ex.X_op = O_constant; @@ -4127,7 +4219,7 @@ 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); + riscv_mapping_state (MAP_INSN, worst_case_bytes, 1/* frag_align_code */); /* We need to start a new frag after the alignment which may be removed by the linker, to prevent the assembler from computing static offsets. @@ -4201,10 +4293,10 @@ riscv_init_frag (fragS * fragP, int max_chars) case rs_fill: case rs_align: case rs_align_test: - riscv_mapping_state (MAP_DATA, max_chars); + riscv_mapping_state (MAP_DATA, max_chars, 0/* frag_align_code */); break; case rs_align_code: - riscv_mapping_state (MAP_INSN, max_chars); + riscv_mapping_state (MAP_INSN, max_chars, 1/* frag_align_code */); break; default: break; @@ -4436,6 +4528,7 @@ void riscv_elf_final_processing (void) { riscv_set_abi_by_arch (); + riscv_release_subset_list (riscv_rps_as.subset_list); elf_elfheader (stdoutput)->e_flags |= elf_flags; } @@ -4477,7 +4570,7 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED) save_c = *input_line_pointer; *input_line_pointer = '\0'; - riscv_mapping_state (MAP_INSN, 0); + riscv_mapping_state (MAP_INSN, 0, 0/* frag_align_code */); struct riscv_ip_error error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, insn_type_hash); @@ -4520,9 +4613,8 @@ riscv_write_out_attrs (void) unsigned int i; /* Re-write architecture elf attribute. */ - arch_str = riscv_arch_str (xlen, riscv_rps_as.subset_list); + arch_str = riscv_rps_as.subset_list->arch_str; bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str); - xfree ((void *) arch_str); /* For the file without any instruction, we don't set the default_priv_spec according to the privileged elf attributes since the md_assemble isn't |