diff options
author | Kuan-Lin Chen <rufus@andestech.com> | 2019-11-14 14:24:22 +0800 |
---|---|---|
committer | Nelson Chu <nelson@rivosinc.com> | 2023-05-19 16:24:10 +0800 |
commit | f1cd8b94e7c941c2a9107c1112ab2339916b8efd (patch) | |
tree | 158d8ac0400a52e839bd8fabfec6bd15a8a1bdfe /gas | |
parent | 26e91972538544a237897baa5c806a008d36a88c (diff) | |
download | gdb-f1cd8b94e7c941c2a9107c1112ab2339916b8efd.zip gdb-f1cd8b94e7c941c2a9107c1112ab2339916b8efd.tar.gz gdb-f1cd8b94e7c941c2a9107c1112ab2339916b8efd.tar.bz2 |
RISC-V: Support subtraction of .uleb128.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/commit/96d6e190e9fc04a8517f9ff7fb9aed3e9876cbd6
There are some known limitations for now,
* Do not shrink the length of the uleb128 value, even if the value is reduced
after relaxations. Also reports error if the length grows up.
* The R_RISCV_SET_ULEB128 needs to be paired with and be placed before the
R_RISCV_SUB_ULEB128.
bfd/
* bfd-in2.h: Regenerated.
* elfnn-riscv.c (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
R_RISCV_SET_ULEB128 relocations. Do not shrink the length of the
uleb128 value, and report error if the length grows up. Called the
generic functions, _bfd_read_unsigned_leb128 and _bfd_write_unsigned_leb128,
to encode the uleb128 into the section contents.
(riscv_elf_relocate_section): Make sure that the R_RISCV_SET_ULEB128
must be paired with and be placed before the R_RISCV_SUB_ULEB128.
* elfxx-riscv.c (howto_table): Added R_RISCV_SUB_ULEB128 and
R_RISCV_SET_ULEB128.
(riscv_reloc_map): Likewise.
(riscv_elf_ignore_reloc): New function.
* libbfd.h: Regenerated.
* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
New relocations to support .uleb128 subtraction.
gas/
* config/tc-riscv.c (md_apply_fix): Added BFD_RELOC_RISCV_SET_ULEB128
and BFD_RELOC_RISCV_SUB_ULEB128.
(s_riscv_leb128): Updated to allow uleb128 subtraction.
(riscv_insert_uleb128_fixes): New function, scan uleb128 subtraction
expressions and insert fixups for them.
(riscv_md_finish): Called riscv_insert_uleb128_fixes for all sections.
include/
* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Defined.
ld/
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
* testsuite/ld-riscv-elf/uleb128*: New testcase for uleb128 subtraction.
binutils/
* testsuite/binutils-all/nm.exp: Updated since RISCV supports .uleb128.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/config/tc-riscv.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 0cc2484..fceb53e 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -3950,6 +3950,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_RISCV_SUB32: case BFD_RELOC_RISCV_SUB64: case BFD_RELOC_RISCV_RELAX: + /* cvt_frag_to_fill () has called output_leb128 (). */ + case BFD_RELOC_RISCV_SET_ULEB128: + case BFD_RELOC_RISCV_SUB_ULEB128: break; case BFD_RELOC_RISCV_TPREL_HI20: @@ -4714,8 +4717,11 @@ s_riscv_leb128 (int sign) char *save_in = input_line_pointer; expression (&exp); - if (exp.X_op != O_constant) - as_bad (_("non-constant .%cleb128 is not supported"), sign ? 's' : 'u'); + if (sign && exp.X_op != O_constant) + as_bad (_("non-constant .sleb128 is not supported")); + else if (!sign && exp.X_op != O_constant && exp.X_op != O_subtract) + as_bad (_(".uleb128 only supports constant or subtract expressions")); + demand_empty_rest_of_line (); input_line_pointer = save_in; @@ -4835,12 +4841,58 @@ riscv_set_public_attributes (void) riscv_write_out_attrs (); } +/* Scan uleb128 subtraction expressions and insert fixups for them. + e.g., .uleb128 .L1 - .L0 + Because relaxation may change the value of the subtraction, we + must resolve them at link-time. */ + +static void +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, void *xxx ATTRIBUTE_UNUSED) +{ + segment_info_type *seginfo = seg_info (sec); + struct frag *fragP; + + subseg_set (sec, 0); + + for (fragP = seginfo->frchainP->frch_root; + fragP; fragP = fragP->fr_next) + { + expressionS *exp, *exp_dup; + + if (fragP->fr_type != rs_leb128 || fragP->fr_symbol == NULL) + continue; + + exp = symbol_get_value_expression (fragP->fr_symbol); + + if (exp->X_op != O_subtract) + continue; + + /* Only unsigned leb128 can be handled. */ + gas_assert (fragP->fr_subtype == 0); + exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp)); + exp_dup->X_op = O_symbol; + exp_dup->X_op_symbol = NULL; + + /* Insert relocations to resolve the subtraction at link-time. + Emit the SET relocation first in riscv. */ + exp_dup->X_add_symbol = exp->X_add_symbol; + fix_new_exp (fragP, fragP->fr_fix, 0, + exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128); + exp_dup->X_add_symbol = exp->X_op_symbol; + fix_new_exp (fragP, fragP->fr_fix, 0, + exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128); + } +} + /* Called after all assembly has been done. */ void riscv_md_finish (void) { riscv_set_public_attributes (); + if (riscv_opts.relax) + bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL); } /* Adjust the symbol table. */ |