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 /bfd/elfnn-riscv.c | |
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 'bfd/elfnn-riscv.c')
-rw-r--r-- | bfd/elfnn-riscv.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index a23b91a..75af040 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -1792,6 +1792,55 @@ perform_relocation (const reloc_howto_type *howto, value = ENCODE_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value)); break; + /* SUB_ULEB128 must be applied after SET_ULEB128, so we only write the + value back for SUB_ULEB128 should be enough. */ + case R_RISCV_SET_ULEB128: + break; + case R_RISCV_SUB_ULEB128: + { + unsigned int len = 0; + _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len); + + /* Clean the contents value to zero (0x80), but keep the original + length. */ + bfd_byte *p = contents + rel->r_offset; + bfd_byte *endp = p + len - 1; + memset (p, 0x80, len - 1); + *(endp) = 0; + + /* Make sure the length of the new uleb128 value within the + original (available) length. */ + unsigned int new_len = 0; + unsigned int val_t = value; + do + { + new_len++; + val_t >>= 7; + } + while (val_t); + if (new_len > len) + { + _bfd_error_handler + (_("final size of uleb128 value at offset 0x%lx in %pA from " + "%pB exceeds available space"), + (long) rel->r_offset, input_section, input_bfd); + return bfd_reloc_dangerous; + } + else + { + p = _bfd_write_unsigned_leb128 (p, endp, value); + BFD_ASSERT (p); + + /* If the length of the value is reduced and shorter than the + original uleb128 length, then _bfd_write_unsigned_leb128 may + clear the 0x80 to 0x0 for the last byte that was written. + So reset it to keep the the original uleb128 length. */ + if (--p < endp) + *p |= 0x80; + } + return bfd_reloc_ok; + } + case R_RISCV_32: case R_RISCV_64: case R_RISCV_ADD8: @@ -2086,6 +2135,8 @@ riscv_elf_relocate_section (bfd *output_bfd, Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd); struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd); + bfd_vma uleb128_set_vma = 0; + Elf_Internal_Rela *uleb128_set_rel = NULL; bool absolute; if (!riscv_init_pcrel_relocs (&pcrel_relocs)) @@ -2427,6 +2478,38 @@ riscv_elf_relocate_section (bfd *output_bfd, /* These require no special handling beyond perform_relocation. */ break; + case R_RISCV_SET_ULEB128: + if (uleb128_set_rel == NULL) + { + /* Saved for later usage. */ + uleb128_set_vma = relocation; + uleb128_set_rel = rel; + continue; + } + else + { + msg = ("Mismatched R_RISCV_SET_ULEB128, it must be paired with" + "and applied before R_RISCV_SUB_ULEB128"); + r = bfd_reloc_dangerous; + } + break; + + case R_RISCV_SUB_ULEB128: + if (uleb128_set_rel != NULL + && uleb128_set_rel->r_offset == rel->r_offset) + { + relocation = uleb128_set_vma - relocation; + uleb128_set_vma = 0; + uleb128_set_rel = NULL; + } + else + { + msg = ("Mismatched R_RISCV_SUB_ULEB128, it must be paired with" + "and applied after R_RISCV_SET_ULEB128"); + r = bfd_reloc_dangerous; + } + break; + case R_RISCV_GOT_HI20: if (h != NULL) { |