[PATCH v4] s390: Only use canonical PLT for non-PIC code taking address in PDE
Jens Remus
jremus@linux.ibm.com
Fri Mar 27 16:46:45 GMT 2026
On 3/23/2026 4:43 PM, Jens Remus wrote:
> Fix incorrect use of canonical PLT in position-dependent executables
> (PDE) that violated pointer equality. The linker must distinguish
> between non-PIC code linked as PDE (which requires canonical PLT for
> pointer equality) and PIC code linked as PDE (which must not use
> canonical PLT). This is determined by examining relocations, not just
> the executable type (PIE vs. PDE).
>
> Canonical PLT entries are needed only when non-PIC code takes function
> addresses. Non-PIC code uses absolute addresses and assumes all
> addresses are known at link time. When such code both calls and takes
> the address of a shared library function, the linker creates a canonical
> PLT entry (setting the symbol's value to the PLT stub address) to ensure
> all references use the same address, maintaining pointer equality.
>
> However, PIC code uses GOT-indirect addressing for function pointers.
> When PIC code takes a function's address, it loads from the GOT, which
> the dynamic linker resolves to the actual function address in the shared
> library. Using canonical PLT in this case is wrong, as it forces all
> GOT entries to point to the PLT stub, breaking pointer equality when the
> shared library compares function addresses internally.
>
> Require pointer equality in PDE for symbols with non-PLT PC-relative
> relocations, that are likely in address taken context, and direct
> relocations, that are likely in function reference context. Do so
> for IFUNC symbols defined in a non-shared object. Clear value of PLT
> undefined symbols if pointer equality is not needed and do not hash them
> in '.gnu.hash' section.
>
> As workaround for GCC 12-14 treat PC32DBL relocation for address taking
> instruction "larl rX,<sym>@PLT" as if it was without @PLT suffix and
> require pointer equality. This ensures correct behavior even when the
> compiler incorrectly marks address-taking instructions with @PLT.
> GCC 12-14, since GCC commit 0990d93dd8a4 ("IBM Z: Use @PLT symbols for
> local functions in 64-bit mode") [1], unconditionally suffix non-local
> symbols with @PLT, regardless of whether they are used in function call
> instructions (i.e. brasl) or address taking instructions (i.e. larl).
> The assembler therefore generates a PLT32DBL instead of a PC32DBL
> relocation for larl. The linker therefore cannot distinguish between
> function call and address taking instructions solely from the relocation
> type. The latter requiring pointer equality.
> This complements GCC commit a2e0a30c52fa ("IBM zSystems: Do not use
> @PLT with larl") [2], which makes GCC stop suffixing @PLT to address
> taking larl instructions, so that the correct behavior with regards to
> pointer equality is also achieved with affected GCC 12-14.
> Note that this workaround can be reverted once GCC 12-14 emitting
> address taking larl instructions with @PLT suffix have become
> irrelevant.
>
> Note that without the workaround for GCC 12-14 suffixing @PLT to larl
> the following linker tests would fail:
>
> FAIL: shared
> FAIL: visibility (hidden_normal)
> FAIL: visibility (hidden_weak)
> FAIL: visibility (protected)
> FAIL: visibility (protected_undef_def)
> FAIL: visibility (protected_weak)
> FAIL: visibility (normal)
>
> Based on x86-64, especially Jakub Jelinek's x86 commits 47a9f7b34f7a
> (clearing value of PLT undefined symbols if pointer equality not needed)
> and fdc90cb46b0f (omitting PLT undefined symbols from '.gnu.hash').
>
> Note that on x86-64 PC32 (and PC64) relocations are excluded as
> indication for address taken context requiring function pointer
> equality. This is because x86-64 used a PC32 relocation in function
> calls from non-PIC code, which has been resolved with commit
> bd7ab16b4537 ("x86-64: Generate branch with PLT32 relocation").
>
> [1] GCC commit 0990d93dd8a4 ("IBM Z: Use @PLT symbols for local
> functions in 64-bit mode"),
> https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=0990d93dd8a4
> [2] GCC commit a2e0a30c52fa ("IBM zSystems: Do not use @PLT with larl"),
> https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a2e0a30c52fa
>
> bfd/
> PR ld/29655
> * elf64-s390.c (elf_s390_check_relocs): Require pointer equality
> for direct and non-PLT PC-relative relocations indicating
> address taking instructions and for PLT32DBL relocations, when
> used with address taking larl instruction.
> (elf_s390_finish_dynamic_symbol): Do not use canonical PLT for
> non-local undefined symbols if pointer equality is not needed.
> Abort if pointer equality needed flag not set although required.
> (elf_s390_copy_indirect_symbol): Copy pointer equality needed
> flag.
> (elf_s390_hash_symbol): New function. Based on x86-64.
> (elf_backend_hash_symbol): Wire up elf_s390_hash_symbol.
>
> ld/testsuite/
> PR ld/29655
> * ld-elf/shared.exp: Add new pr29655 test.
> * ld-elf/pr29655a.c: New file. Based on Rui's sample in PR.
> * ld-elf/pr29655b.c: Likewise.
> * ld-elf/pr29655.rd: Expect zero fun_public symbol value.
> * ld-s390/plt_64-1.wf: Adjust expected test output to change in
> .gnu.hash due to omitted PLT undefined symbols that do not need
> pointer equality.
> * ld-s390/plt_64-1_eh.wf: Likewise.
>
> Bug: https://sourceware.org/PR29655
> Co-authored-by: Andreas Krebbel <krebbel@linux.ibm.com>
> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
> ---
>
> Notes (jremus):
> Changes in v4:
> - Reword commit subject and message to clarify canonical PLT is only
> required for non-PIC code taking a function address linked as PDE.
> - Remove setup_xfail and clear_xfail. (Alan)
>
> Changes in v3:
> - Turn pr29655 test into a run_cc_link_tests that checks the executable
> using readelf --dyn-sym looking for a zero value undefined fun_public.
> (Alan)
> - clear-xfail arm*-*-* aarch64-*-* pr29655 test. (Linaro-TCWG-CI)
> - clear-xfail alpha-*-* hppa-*-* ia64-*-* microblaze-*-* mips-*-*
> mips64-*-*. (Alan)
>
> Changes in v2:
> - Reword commit message to reflect that function pointer equality is
> required for all direct and non-PLT PC-relative relocations and to
> mention which tests fail without the GCC 12-14 workaround.
> - Fix typo in comment on GCC 12-14 workaround. (Andreas)
> - Have main() return 0 in test. (Andreas)
> - Adding Nick, Alan, and Jan due to the added common test case.
>
> Note: Splitting the GCC 12-14 workaround into a separate patch either
> requires it to be the first patch or causes one shared and multiple
> visibility tests to fail. Addressing the latter using a setup_fail
> condition as follows (that would get removed by the workaround-patch)
> seemed rather odd to me:
>
> # On s390 64-bit (s390x) GCC 12-14 suffix symbols in address
> # taken context with @PLT, which breaks function pointer equality.
> if { [istarget s390x-*-linux*]
> && [at_least_gcc_version 12 0]
> && ![at_least_gcc_version 15 0] } {
> setup_xfail "s390x-*-linux*"
> }
>
> bfd/elf64-s390.c | 66 ++++++++++++++++++++++++++++-
> ld/testsuite/ld-elf/pr29655.rd | 5 +++
> ld/testsuite/ld-elf/pr29655a.c | 20 +++++++++
> ld/testsuite/ld-elf/pr29655b.c | 15 +++++++
> ld/testsuite/ld-elf/shared.exp | 25 +++++++++++
> ld/testsuite/ld-s390/plt_64-1.wf | 8 ++--
> ld/testsuite/ld-s390/plt_64-1_eh.wf | 2 +-
> 7 files changed, 134 insertions(+), 7 deletions(-)
> create mode 100644 ld/testsuite/ld-elf/pr29655.rd
> create mode 100644 ld/testsuite/ld-elf/pr29655a.c
> create mode 100644 ld/testsuite/ld-elf/pr29655b.c
Committed to mainline with Andreas' off-list approval.
Regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
More information about the Binutils
mailing list