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

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Mon May 11 14:41:36 GMT 2026



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


More information about the Libc-alpha mailing list