aboutsummaryrefslogtreecommitdiff
path: root/bfd/elfnn-riscv.c
diff options
context:
space:
mode:
authorKuan-Lin Chen <rufus@andestech.com>2019-11-14 14:24:22 +0800
committerNelson Chu <nelson@rivosinc.com>2023-05-19 16:24:10 +0800
commitf1cd8b94e7c941c2a9107c1112ab2339916b8efd (patch)
tree158d8ac0400a52e839bd8fabfec6bd15a8a1bdfe /bfd/elfnn-riscv.c
parent26e91972538544a237897baa5c806a008d36a88c (diff)
downloadgdb-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.c83
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)
{