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

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Mon May 11 18:39:29 GMT 2026



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?




More information about the Libc-alpha mailing list