diff options
author | Nelson Chu <nelson@rivosinc.com> | 2023-03-25 08:41:12 +0800 |
---|---|---|
committer | Nelson Chu <nelson@rivosinc.com> | 2023-03-30 07:40:14 +0800 |
commit | b679fb488a8c35e573d50f118a09f72c1f6289de (patch) | |
tree | 523872417472d0d54487e0ca668b3260c2b391ca /bfd/elfnn-riscv.c | |
parent | 23068b02d3a6743658110c7662178fdebbe2ac6a (diff) | |
download | gdb-b679fb488a8c35e573d50f118a09f72c1f6289de.zip gdb-b679fb488a8c35e573d50f118a09f72c1f6289de.tar.gz gdb-b679fb488a8c35e573d50f118a09f72c1f6289de.tar.bz2 |
RISC-V: Clarify link behaviors of R_RISCV_32/64 relocations with ABS symbol.
There are two improvements, which are all referenced to aarch64,
* R_RISCV_32 with non ABS symbol cannot be used under RV64 when making
shard objects.
* Don't need dynamic relocation for R_RISCV_32/64 under RV32/RV64 when
making shared objects, if the referenced symbol is local ABS symbol.
However, considering this link,
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/341
Seems like we should makes all R_RISCV_32/64 relocs with ABS symbol
that don't need any dynamic relocations when making the shared objects.
But anyway, I just sync the current behavior as aarch64 ld, in case
there are any unexpected behaviors happen.
Passed the gcc/binutils regressions in riscv-gnu-toolchain.
bfd/
* elfnn-riscv.c (riscv_elf_check_relocs): Only allow R_RISCV_32 with ABS
symbol under RV64.
(riscv_elf_relocate_section): R_RISCV_32/64 with local ABS symbol under
RV32/RV64 doesn't need any dynamic relocation when making shared objects.
I just make the implementations similar to other targets, so that will be
more easy to mainatain.
ld/
* testsuite/ld-riscv-elf/data-reloc*: New testcases.
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Added new data-reloc* testcases,
and need to make ifunc-seperate* testcases work for rv32.
* testsuite/ld-riscv-elf/ifunc-seperate-caller-nonplt.s: Likewise.
* testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s: Likewise.
Diffstat (limited to 'bfd/elfnn-riscv.c')
-rw-r--r-- | bfd/elfnn-riscv.c | 61 |
1 files changed, 53 insertions, 8 deletions
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 59e949a..00f034a 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -734,6 +734,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, unsigned int r_type; unsigned int r_symndx; struct elf_link_hash_entry *h; + bool is_abs_symbol = false; r_symndx = ELFNN_R_SYM (rel->r_info); r_type = ELFNN_R_TYPE (rel->r_info); @@ -753,6 +754,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (isym == NULL) return false; + is_abs_symbol = isym->st_shndx == SHN_ABS ? true : false; + /* Check relocation against local STT_GNU_IFUNC symbol. */ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { @@ -778,6 +781,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + + is_abs_symbol = bfd_is_abs_symbol (&h->root) ? true : false; } if (h != NULL) @@ -879,13 +884,31 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_RISCV_HI20: if (bfd_link_pic (info)) return bad_static_reloc (abfd, r_type, h); - /* Fall through. */ + goto static_reloc; + + case R_RISCV_32: + if (ARCH_SIZE > 32 + && bfd_link_pic (info) + && (sec->flags & SEC_ALLOC) != 0) + { + if (is_abs_symbol) + break; + + reloc_howto_type *r_t = riscv_elf_rtype_to_howto (abfd, r_type); + _bfd_error_handler + (_("%pB: relocation %s against non-absolute symbol `%s' can " + "not be used in RVNN when making a shared object"), + abfd, r_t ? r_t->name : _("<unknown>"), + h != NULL ? h->root.root.string : "a local symbol"); + bfd_set_error (bfd_error_bad_value); + return false; + } + goto static_reloc; case R_RISCV_COPY: case R_RISCV_JUMP_SLOT: case R_RISCV_RELATIVE: case R_RISCV_64: - case R_RISCV_32: /* Fall through. */ static_reloc: @@ -2630,6 +2653,11 @@ riscv_elf_relocate_section (bfd *output_bfd, break; case R_RISCV_32: + /* Non ABS symbol should be blocked in check_relocs. */ + if (ARCH_SIZE > 32) + break; + /* Fall through. */ + case R_RISCV_64: if ((input_section->flags & SEC_ALLOC) == 0) break; @@ -2639,7 +2667,6 @@ riscv_elf_relocate_section (bfd *output_bfd, { Elf_Internal_Rela outrel; asection *sreloc; - bool skip_static_relocation, skip_dynamic_relocation; /* When generating a shared object, these relocations are copied into the output file to be resolved at run @@ -2648,26 +2675,44 @@ riscv_elf_relocate_section (bfd *output_bfd, outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, rel->r_offset); - skip_static_relocation = outrel.r_offset != (bfd_vma) -2; - skip_dynamic_relocation = outrel.r_offset >= (bfd_vma) -2; + bool skip = false; + bool relocate = false; + if (outrel.r_offset == (bfd_vma) -1) + skip = true; + else if (outrel.r_offset == (bfd_vma) -2) + { + skip = true; + relocate = true; + } + else if (h != NULL && bfd_is_abs_symbol (&h->root)) + { + /* Don't need dynamic reloc when the ABS symbol is + non-dynamic or forced to local. Maybe just use + SYMBOL_REFERENCES_LOCAL to check? */ + skip = (h->forced_local || (h->dynindx == -1)); + relocate = skip; + } + outrel.r_offset += sec_addr (input_section); - if (skip_dynamic_relocation) - memset (&outrel, 0, sizeof outrel); + if (skip) + memset (&outrel, 0, sizeof outrel); /* R_RISCV_NONE. */ else if (RISCV_COPY_INPUT_RELOC (info, h)) { + /* Maybe just use !SYMBOL_REFERENCES_LOCAL to check? */ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type); outrel.r_addend = rel->r_addend; } else { + /* This symbol is local, or marked to become local. */ outrel.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE); outrel.r_addend = relocation + rel->r_addend; } sreloc = elf_section_data (input_section)->sreloc; riscv_elf_append_rela (output_bfd, sreloc, &outrel); - if (skip_static_relocation) + if (!relocate) continue; } break; |