Re: [Patch] LoongArch: Restore pointer_equality_needed for GOT data relocations

Yanjun Yang <[email protected]> Mon, 3 Aug 2026 15:35:14 +0800
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
On Sun, Aug 02, 2026 at 07:26:13AM +0800, Xi Ruoyao wrote:
> On Thu, 2026-07-30 at 17:34 +0800, Yanjun Yang wrote:
> > From: Pluto Yang <[email protected]>
> > 
> > Commit 7f9d6d6ead5 ("LoongArch: Fix Build pr29655") removed the
> > setting of pointer_equality_needed for GOT relocations
> > (R_LARCH_GOT_PC_HI20, R_LARCH_GOT_PCADD_HI20, R_LARCH_GOT_HI20,
> > R_LARCH_SOP_PUSH_GPREL).  This was correct for function symbols to
> > fix PR 29655 (function pointer equality in PIE executables), but it
> > had an unintended side effect: the CRT startup code uses
> > R_LARCH_GOT_PC_HI20 to access data symbols like __environ,
> > __rela_iplt_start, __rela_iplt_end, and _dl_ns.  Without
> > pointer_equality_needed, the GOT layout for these data symbols is
> > altered, corrupting the static binary and causing runtime segfaults.
> 
> This does not make sense to me.  Global data symbols are accessed via
> R_LARCH_GOT_PC_HI20 everywhere, not only the CRT startup code.  Thus if
> accessing data symbols with R_LARCH_GOT_PC_HI20 is broken we'd have a
> much more wide-spreading breakage.
> 
> > Restore pointer_equality_needed for GOT relocations, but only for
> > non-function symbols (h->type != STT_FUNC).  This preserves the
> > PR 29655 fix for function symbols while fixing static executables
> > that use data symbols accessed via GOT relocations.
> 
> This again does not make sense to me.  Pointer equality matters because
> if you end up comparing the address of the PLT stub and the address of
> the real function you'd break pointer equality.  You cannot use a PLT
> stub for data symbols so pointer equality has nothing to do with data
> symbols.
> 

You are right, and thank you for the analysis.

I bisected the regression and found commit 7f9d6d6ead5 ("LoongArch:
Fix Build pr29655") was the first bad commit, which removed the
pointer_equality_needed = 1 for GOT relocations.  Based on that,
I incorrectly assumed the removal itself was the problem.

> > This bug was discovered when building GCC for loongarch64: the
> > libstdc++ configure script tests TLS support by running a statically
> > linked program.  The corrupted GOT caused the test to crash, leading
> > to gcc_cv_have_tls=no, which disabled TLS support in libstdc++ and
> > broke ABI compatibility with system libraries.
> 
> I cannot reproduce the issue by building GCC: GCC builds fine with
> gcc_cv_have_tls=yes in config.log files.  But maybe this test case:
> 

This is likely a difference in the build environment.  I hit this when
packaging GCC 16.1.1 for Arch Linux on loongarch64.  The chroot has
binutils 2.47-1, where the libstdc++ configure TLS test runs a
statically linked program that crashed due to the .got.plt bug,
resulting in gcc_cv_have_tls=no.

> int f1() { return 42; }
> int f2() { return 47; }
> 
> void *fx() { return f1; }
> 
> [[gnu::ifunc("fx")]] int f();
> 
> int main() { int (*p)() = f; asm("":"+r"(p)); return p();}
> 
> This thing indeed crashes with ld-2.47 and -static: debugger shows the
> value of p is now __strrchr_lasx in glibc (!!!) which will definitely
> not work at the place of f1().
> 
> It "works" with ld-2.46 but the value of p is the address of the PLT
> entry, not the address of f1.  On x86 it behaves the same way but on
> aarch64 we get the address of f1.  I don't know which way is better yet.
> 
> And I'm also unsure if the malfunction demonstrated with the test case
> above is the same "GOT corruption" in your case.

Yes, it is the same bug, and your ifunc_got_off patch (from: [PATCH]
LoongArch: fix .got.plt dislocation in static PDE) is the proper fix.
I have applied it on top of my tree and verified GCC libstdc++ configure
TLS test now passes.

Best regards,
Yanjun Yang

> 
> > Signed-off-by: Pluto Yang <[email protected]>
> > ---
> >  bfd/elfnn-loongarch.c | 5 +++++
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> > index 4bdc3f26285..1c643c587f2 100644
> > --- a/bfd/elfnn-loongarch.c
> > +++ b/bfd/elfnn-loongarch.c
> > @@ -1249,6 +1249,11 @@ loongarch_elf_check_relocs (bfd *abfd, struct
> > bfd_link_info *info,
> >  	case R_LARCH_GOT_PCADD_HI20:
> >  	case R_LARCH_GOT_HI20:
> >  	case R_LARCH_SOP_PUSH_GPREL:
> > +	  /* For la.global: set pointer_equality_needed for data
> > symbols
> 
> This line especially makes no sense...
> 
> > +	     to ensure correct GOT layout.  Function symbols are
> > excluded
> > +	     to avoid breaking function pointer equality (PR 29655). 
> > */
> > +	  if (h && h->type != STT_FUNC)
> 
> So, maybe just h->type == STT_GNU_IFUNC?
> 
> > +	    h->pointer_equality_needed = 1;
> >  	  if (!loongarch_elf_record_tls_and_got_reference (abfd,
> > info, h,
> >  							   r_symndx,
> >  							  
> > GOT_NORMAL,
> 
> -- 
> Xi Ruoyao <[email protected]>