RISC-V: Fix weak function call reloc overflow on llvm build.

Message ID 20200107175848.12759-1-jimw@sifive.com
State New
Headers show
  • RISC-V: Fix weak function call reloc overflow on llvm build.
Related show

Commit Message

Jim Wilson Jan. 7, 2020, 5:58 p.m.
This fixes the llvm build failure that Andreas Schwab reported.

In _bfd_riscv_relax_section, if there is a PLT then we use it unconditionally.
However, in riscv_elf_relocate_section, a PLT is only used if bfd_link_pic,
i.e. the output is a shared library or PIE.  So we are relaxing using a
different symbol address than what we are linking for which causes the trouble.
Since this is a linker relaxation problem, it must be _bfd_riscv_relax_section
that is wrong.  Adding a check for bfd_link_pic solves the linker errors.  But
there is still a potential problem that we aren't handling undef weak functions
in riscv_elf_relocate_section if there is a PLT, which could be a problem if a
program is linked to run at a high address out of range of 0.  This is common
for embedded but probably not for linux, but I think we should still fix it.
So I need to add a !bfd_link_pic check there.  

Tested with a native binutils/gcc/glibc build and check with no regressions.
And Andreas verified that it fixes his llvm build failure.



	PR 25205
	* elfnn-riscv.c (riscv_elf_relocate_section) <R_RISCV_CALL>: Add
	check for !bfd_link_pic (info).
	<R_RISCV_JAL>: Add comment.
	(_bfd_riscv_relax_section): For plt.offset check, add check for
	bfd_link_pic (info).  Add comment.

Change-Id: I9ace567eb4800cfcfb7e8111a901051f48f41760
 bfd/elfnn-riscv.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)



diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index d30fc8b66a..46f0100ace 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1987,10 +1987,11 @@  riscv_elf_relocate_section (bfd *output_bfd,
 	case R_RISCV_CALL:
 	  /* Handle a call to an undefined weak function.  This won't be
 	     relaxed, so we have to handle it here.  */
 	  if (h != NULL && h->root.type == bfd_link_hash_undefweak
-	      && h->plt.offset == MINUS_ONE)
+	      && (!bfd_link_pic (info) || h->plt.offset == MINUS_ONE))
 	      /* We can use x0 as the base register.  */
 	      bfd_vma insn = bfd_get_32 (input_bfd,
@@ -2003,9 +2004,9 @@  riscv_elf_relocate_section (bfd *output_bfd,
 	  /* Fall through.  */
 	case R_RISCV_JAL:
+	  /* This line has to match the check in _bfd_riscv_relax_section.  */
 	  if (bfd_link_pic (info) && h != NULL && h->plt.offset != MINUS_ONE)
 	      /* Refer to the PLT entry.  */
@@ -4128,7 +4129,9 @@  _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 	      undefined_weak = TRUE;
-	  if (h->plt.offset != MINUS_ONE)
+	  /* This line has to match the check in riscv_elf_relocate_section
+	     in the R_RISCV_CALL[_PLT] case.  */
+	  if (bfd_link_pic (info) && h->plt.offset != MINUS_ONE)
 	      sym_sec = htab->elf.splt;
 	      symval = h->plt.offset;