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

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

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

Jim Wilson-2
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_CALL_PLT>: Move next to R_RISCV_CALL.
        <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;