[PATCH] elf: Defer all IRELATIVE relocations until after PLT setup (BZ 20673)

H.J. Lu hjl.tools@gmail.com
Mon May 11 18:56:08 GMT 2026


On Tue, May 12, 2026 at 2:39 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 11/05/26 15:24, H.J. Lu wrote:
> > On Mon, May 11, 2026 at 10:41 PM Adhemerval Zanella Netto
> > <adhemerval.zanella@linaro.org> wrote:
> >>
> >>
> >>
> >> On 08/05/26 20:48, H.J. Lu wrote:
> >>> On Tue, Apr 28, 2026 at 9:42 PM Adhemerval Zanella
> >>> <adhemerval.zanella@linaro.org> wrote:
> >>>>
> >>>> When a shared library is built with -z lazy and its IFUNC resolver calls
> >>>> a PLT function, the dynamic linker can crash.  The resolver runs while
> >>>> the PLT stubs still hold their raw ELF virtual addresses — l_addr has
> >>>> not yet been added — so the call branches to an unmapped address.
> >>>>
> >>>> The old code deferred IRELATIVE entries only to the end of the relocation
> >>>> range currently being processed (via the r2/end2 scan-ahead mechanism in
> >>>> elf_dynamic_do_Rel).  This was sufficient only when both IRELATIVE and the
> >>>> JMP_SLOT entries for the PLT functions it needs are in the same section.
> >>>> On x86-64, aarch64, arm, i386 and most other targets, a file-scope
> >>>> initialiser of the form
> >>>>
> >>>>   int (*fptr)(void) = some_ifunc;
> >>>>
> >>>> causes the linker to place R_*_IRELATIVE in .rela.dyn, while JMP_SLOT
> >>>> entries for any PLT calls made by the resolver live in .rela.plt.
> >>>> Processing .rela.dyn before .rela.plt means the resolver fires before the
> >>>> PLT is usable, regardless of where within .rela.dyn IRELATIVE appears.
> >>>>
> >>>> Fix this by splitting IRELATIVE processing into a separate, explicitly
> >>>> deferred pass.  In elf/do-rel.h:
> >>>>
> >>>>  - Remove the r2/end2 variables and the post-loop IRELATIVE re-scan from
> >>>>    elf_dynamic_do_Rel.  IRELATIVE entries are now always skipped in the
> >>>>    non-bootstrap path.
> >>>>
> >>>>  - Add a new elf_dynamic_do_Rel_irelative function that scans a
> >>>>    relocation range and calls elf_machine_rel/elf_machine_lazy_rel for
> >>>>    IRELATIVE and ifunc relocations.
> >>>>
> >>>> In elf/dynamic-link.h, update _ELF_DYNAMIC_DO_RELOC to use a two-phase
> >>>> approach for non-bootstrap builds unconditionally (regardless of whether
> >>>> ranges[1].size is zero):
> >>>>
> >>>>  Phase 1+2: elf_dynamic_do_Rel over .rela.dyn then .rela.plt — processes
> >>>>             everything except IRELATIVE/STT_GNU_IFUNC.
> >>>>  Phase 3+4: elf_dynamic_do_Rel_irelative over .rela.dyn then .rela.plt —
> >>>>             processes only IRELATIVE, by which point all PLT stubs are
> >>>>             valid.
> >>>>
> >>>> This guarantees that IRELATIVE resolvers can call PLT stubs safely
> >>>> regardless of which section the linker placed R_*_IRELATIVE in.
> >>>>
> >>>> Add ELF_MACHINE_IRELATIVE to the architectures that were missing it so
> >>>> the new skip logic in elf_dynamic_do_Rel is compiled for all targets.
> >>>>
> >>>> I checked on all ABI that support iFUNC (x86_64, i686, aarch64, arm,
> >>>> loongarch, powerpc, riscv, s390, and sparc), although on some through
> >>>> qemu-system (which should not matter for this case).
> >>>>
> >>>> It also fixes the mold reported issues [1], which shows an example
> >>>> where IFUNC relocation placement and processing can works different
> >>>> for different ABIs.
> >>>
> >>> Just to be clear.  This patch doesn't fully fix:
> >>>
> >>> https://sourceware.org/bugzilla/show_bug.cgi?id=20673
> >>>
> >>> This fix only deals with IRELATIVE relocation order within an object.
> >>> Calling an external function from an IFUC resolver may still crash.
> >>> Am I correct?
> >> Yes, it does not solve all the iFUNC raised by Szabolcs [1], nor the
> >> original BZ#21041 issues [2] which Fangrui creates an example [3]. For this
> >> I think we will need something like what Florian did [4], and I am exploring
> >> a solution similar.
> >>
> >>
> >> [1] https://sourceware.org/legacy-ml/libc-alpha/2015-11/msg00108.html
> >> [2] https://sourceware.org/bugzilla/show_bug.cgi?id=21041
> >> [3] https://maskray.me/blog/2021-01-18-gnu-indirect-function
> >> [4] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/fw/bug21242
> >
> > IFUNC resolvers have many limitations when they call another function.
> > I don't think we can make it work in all cases.   Can you remove the
> > reference to BZ 20673 in your commit message?  Your patch supports
> > any IRELATIVE relocation orders.  It should be good enough on its own.
> Indeed, albeit I think there are still room for improvements.  From Szabolcs
> raised points, I think at least we can make point 1 (calling extern functions
> from an IFUNC resolver may not work) to work more reliable. I am working on
> a patch that should fix it.
>
> The point 2 (-fstack-protector-all may crash a resolver) could be resolved,
> although I think it would be complex for ABIs that places the cookie on the TCB
> (since we need to know the static TLS size prior sizing the TCB header).  I think
> a better approach would to warn and disable this by the compiler.
>
> The point 3 (libc functions are not safe to call from resolvers under static
> linking) could also be resolved, but I haven't dig into yet.  Most likely it will
> require adjust the static linking initialization order.
>
> The point 4 (limited methods for an IFUNC resolver to learn about the machine)
> is somewhat out of scope of IFUNC implementation. However, I think if we can
> make 1. work properly the resolve can rely on calling external library
> to gather better information.
>
> The Point 5 (caching results in userspace is unsafe / causes dirty pages) is
> an implementation detail of libgcc, so I think it is out-of-scope for the glibc.
>
> The Point 6 (lazy binding requires the resolver to be async-signal-safe and
> thread-safe) is also quite hard and I think it falls on same category of
> atfork handlers; where glibc can not really enforce a program model
> without some compiler help.
>
> I will drop the bug report from commit message, should I send another version?
>
>

Yes, please.  If you want, you may reference

https://sourceware.org/bugzilla/show_bug.cgi?id=13302

Your patch addresses the same issue from the glibc side.

-- 
H.J.


More information about the Libc-alpha mailing list