s390: Only use canonical PLT for non-PIC code taking address in PDE
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>
ld: sframe: do not generate .sframe for PLT if no .sframe is in input BFDs
GNU ld creates SFrame stack trace info for the PLT. For x86 the linker-
created .sframe section is created in setup_gnu_properties. For s390 it
is created in create_dynamic_sections. For both, the section data is
itself emitted a bit later in late_size_sections. Note that for aarch64 the
linker does not create .sframe for PLT yet.
Recall that a previous patch 832ca9ef670 uncoupled
--no-ld-generated-unwind-info from the linker-generated .sframe
sections. This means that the linker now generates .sframe section (for
.plt*) for the first input BFD enthusiatically even when none of the
input BFDs have any .sframe section, unless --discard-sframe is also
added. The issue is that these (unexpected) linker-generated .sframe
sections (on x86_64, and s390) may now trip the linking process, e.g.,
when using --orphan-handling=error together with a linker script that
treats .sframe differently than the default linker script.
https://sourceware.org/pipermail/binutils/2026-January/147826.html
Further, with SFrame sections to be soon marked KEEP for fixing
GC/SFrame (PR ld/32769), the presence of these linker generated SFrame
sections will also cause emission of an empty .sframe (for x86_64 and
s390x), even when all input bfd's have no .sframe section.
This patch avoids creation of .sframe for .plt* if none of the input
BFDs had any .sframe section. This then avoids creation of empty
.sframe in linked objects on x86_64 and s390x, when none of the inputs
have SFrame sections. This also fixes PR ld/33830.
For the code changes:
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
New testcases have (since the above Reviewed-by) been added. Since
--no-ld-generated-unwind-info is not supported on aarch64, add
target-specific ld tests. Additionally add a generic test (for all
targets that support SFrame) to ensure no output .sframe is generated if
users says no --gsframe or similar.
bfd/
PR ld/33830
* elf-bfd.h (_bfd_elf_sframe_present_input_bfds): New
declaration.
* elf-sframe.c (_bfd_elf_sframe_present_input_bfds): New
definition.
* elf64-s390.c (elf_s390_create_dynamic_sections): Do not
generate .sframe for .plt unconditionally.
* elfxx-x86.c (_bfd_x86_elf_link_setup_gnu_properties):
Likewise.
ld/testsuite/
PR ld/33830
* ld-s390/no-sframe.ld: Linker script with no specification for
SFrame sections.
* ld-s390/s390.exp: Add new test.
* ld-s390/sframe-command-line-2.d: New testcase that uses
--no-ld-generated-unwind-info and a linker script that has no
specific rules for .sframe.
* ld-x86-64/no-sframe.ld: Likewise for x86_64.
* ld-x86-64/sframe-command-line-2.d: Likewise for x86_64.
* ld-x86-64/x86-64.exp: Add new test.
* ld-sframe/no-ld-generated-sframe.d: Ensure no .sframe in
output if no .sframe in input.
* ld-sframe/no-sframe.ld: Linker script with no specification
for SFrame sections.
* ld-sframe/test.s: Add new test.
s390: Only use canonical PLT for non-PIC code taking address in PDE
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>
s390: Only use canonical PLT for non-PIC code taking address in PDE
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>
ld: sframe: do not generate .sframe for PLT if no .sframe is in input BFDs
GNU ld creates SFrame stack trace info for the PLT. For x86 the linker-
created .sframe section is created in setup_gnu_properties. For s390 it
is created in create_dynamic_sections. For both, the section data is
itself emitted a bit later in late_size_sections. Note that for aarch64 the
linker does not create .sframe for PLT yet.
Recall that a previous patch 832ca9ef670 uncoupled
--no-ld-generated-unwind-info from the linker-generated .sframe
sections. This means that the linker now generates .sframe section (for
.plt*) for the first input BFD enthusiatically even when none of the
input BFDs have any .sframe section, unless --discard-sframe is also
added. The issue is that these (unexpected) linker-generated .sframe
sections (on x86_64, and s390) may now trip the linking process, e.g.,
when using --orphan-handling=error together with a linker script that
treats .sframe differently than the default linker script.
https://sourceware.org/pipermail/binutils/2026-January/147826.html
Further, with SFrame sections to be soon marked KEEP for fixing
GC/SFrame (PR ld/32769), the presence of these linker generated SFrame
sections will also cause emission of an empty .sframe (for x86_64 and
s390x), even when all input bfd's have no .sframe section.
This patch avoids creation of .sframe for .plt* if none of the input
BFDs had any .sframe section. This then avoids creation of empty
.sframe in linked objects on x86_64 and s390x, when none of the inputs
have SFrame sections. This also fixes PR ld/33830.
For the code changes:
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
New testcases have (since the above Reviewed-by) been added. Since
--no-ld-generated-unwind-info is not supported on aarch64, add
target-specific ld tests. Additionally add a generic test (for all
targets that support SFrame) to ensure no output .sframe is generated if
users says no --gsframe or similar.
bfd/
PR ld/33830
* elf-bfd.h (_bfd_elf_sframe_present_input_bfds): New
declaration.
* elf-sframe.c (_bfd_elf_sframe_present_input_bfds): New
definition.
* elf64-s390.c (elf_s390_create_dynamic_sections): Do not
generate .sframe for .plt unconditionally.
* elfxx-x86.c (_bfd_x86_elf_link_setup_gnu_properties):
Likewise.
ld/testsuite/
PR ld/33830
* ld-s390/no-sframe.ld: Linker script with no specification for
SFrame sections.
* ld-s390/s390.exp: Add new test.
* ld-s390/sframe-command-line-2.d: New testcase that uses
--no-ld-generated-unwind-info and a linker script that has no
specific rules for .sframe.
* ld-x86-64/no-sframe.ld: Likewise for x86_64.
* ld-x86-64/sframe-command-line-2.d: Likewise for x86_64.
* ld-x86-64/x86-64.exp: Add new test.
* ld-sframe/no-ld-generated-sframe.d: Ensure no .sframe in
output if no .sframe in input.
* ld-sframe/no-sframe.ld: Linker script with no specification
for SFrame sections.
* ld-sframe/test.s: Add new test.
s390: Initial support to generate .sframe from CFI directives in assembler
This introduces initial support to generate .sframe from CFI directives
in assembler on s390 64-bit (s390x). Due to SFrame V2 format
limitations it has the following limitations, some of them getting
addressed by subsequent patches, which cause generation of SFrame FDE
to be skipped:
- SFrame FP/RA tracking only supports register contents being saved on
the stack (i.e. .cfi_offset). It does not support FP/RA register
contents being saved in other registers (i.e. .cfi_register). GCC on
s390x can be observed to save the FP/RA register contents in floating-
point registers, but only in leaf functions.
This issue is detailed further and resolved in the subsequent commit
"s390: Represent FP/RA saved in register in SFrame".
- SFrame FP/RA tracking cannot represent FP without RA saved. This is
because the format assumes SFrame FDE offset2 to be the RA offset, if
there are two offsets, and offset3 to be the FP offset, if there are
three offsets. There is no mean to distinguish whether offset2 is the
RA or FP offset, if there are only two offsets.
This issue is detailed further and resolved in the subsequent commit
"s390: Represent FP without RA saved in SFrame".
- SFrame assumes a dedicated FP register number. The s390x ELF ABI [1]
does only designate register 11 as preferred FP register number. In
general GCC and Clang on s390x use register 11 as frame pointer.
GCC on s390x can be observed to use register 14 as frame pointer in
the stack clash protector in the function prologue.
glibc on s390x contains hand-written assembler code that uses
register 12 as frame pointer.
This s390x support is largely based on the AArch64 support from commit
b52c4ee46657 ("gas: generate .sframe from CFI directives").
The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced
for s390x and added to the SFrame format specification.
The s390x ELF ABI [1] specifies the following C calling conventions for
s390x architecture:
- Register 15 is the stack pointer (SP).
- Register 14 contains the return address (RA) at function entry.
- There is no dedicated frame pointer register. Register 11 is the
preferred frame pointer (FP). [2] GCC and Clang in general use
register 11 as frame pointer.
- The CFA is defined as SP at call site +160. [3] The SP at call site
can therefore be derived from the CFA using a SP value offset from CFA
of -160.
The s390x ELF ABI [1] does not assign any standard save slot to each
register in the register save area of a stack frame. Neither the
return address (RA, r14) nor preferred frame pointer (FP, r11)
necessarily need to be saved. Therefore SFrame RA and FP tracking is
used.
Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI
(z/Architecture with 64-bit addressing mode). It is disabled for the
32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing
mode).
s390x-specific SFrame assembler and linker tests are added, including
error tests for use of a non-preferred frame pointer (FP) register and
specification of a non-default return address (RA) register.
[1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases
[2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame
pointer register"),
https://github.com/IBM/s390x-abi/commit/f00421825979
[3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"),
https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88
include/
* sframe.h: Add reference to s390x architecture in comments.
(SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier
for s390x.
(SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value
offset from CFA.
libsframe/
* sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG.
* doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x,
SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier
for s390x, add references to s390x architecture, and document
s390x-specifics, such as the SP value offset from CFA of -160.
gas/
* config/tc-s390.h: s390x support to generate .sframe from CFI
directives in assembler.
(support_sframe_p): Define.
(SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG):
Define.
(sframe_ra_tracking_p): Define.
(sframe_cfa_ra_offset): Define.
(sframe_get_abi_arch): Define.
* config/tc-s390.c: s390x support to generate .sframe from CFI
directives in assembler.
(s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg,
s390_sframe_cfa_ra_reg): New. Initialize to DWARF register
numbers of stack pointer (SP, r15), preferred frame pointer
(FP, r11), and return address (RA, r14) registers.
(s390_support_sframe_p): New function. Return true if s390x.
(s390_sframe_ra_tracking_p): New function. Return true.
(s390_sframe_cfa_ra_offset): New function. Return
SFRAME_CFA_FIXED_RA_INVALID.
(s390_sframe_get_abi_arch): New function. Return
SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero.
* gen-sframe.c: Add reference to s390x architecture in comments.
(sframe_xlate_do_val_offset): Add support for s390x-specific
SFRAME_S390X_SP_VAL_OFFSET.
* NEWS: Add news entry.
gas/testsuite/
* gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for
s390x. Add s390x-specific SFrame (error) tests.
* gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame
test.
* gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific
SFrame error test that uses a non-default frame-pointer register
as CFA base register.
* gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific
SFrame error test that uses a non-default return address
register.
* gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x-
specific SFrame test that saves RA and FP individually on the
stack.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New
s390x-specific SFrame error test that saves FP and RA
individually, to trigger FP without RA saved.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New
s390x-specific SFrame error test that saves FP and RA
individually in registers.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s:
Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New
s390x-specific SFrame error test that saves RA and FP
individually in registers.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s:
Likewise.
ld/testsuite/
* ld-s390/s390.exp: Add simple SFrame test.
* ld-s390/sframe-simple-1.d: New simple SFrame test.
* ld-s390/sframe-bar.s: Likewise.
* ld-s390/sframe-foo.s: Likewise.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
[SFrame-V3] ld: add --discard-sframe command line option
Add a new command line option --discard-sframe to the linker.
This option allows users to prevent the linker from generating an output
.sframe section.
The rationale for this option is: Consider the case when say, the distro
is shipped with SFrame sections in the installed binaries/libraries. A
user application using these installed libraries, but not enabling
.sframe for itself just yet, will see an output .sframe corresponding to
the pulled in libraries. This is "partial" .sframe information for the
application. Adding such an option to the linker, gives user a way to
turn off the .sframe section completely without relying on a linker
script.
Previously, the existing --no-ld-generated-unwind-info option
controlled whether (not just .eh_frame for PLT entries, but also) SFrame
for PLT entries. The new command line option,
--discard-sframe now decouples SFrame from other unwind
formats (like .eh_frame), allowing for more control over the output
binary's SFrame data.
The option is added for architectures that currently support SFrame:
AArch64, s390x, and x86_64.
bfd/
* elf-sframe.c (_bfd_elf_parse_sframe): Mark with SEC_EXCLUDE if
--discard-sframe is in effect.
* elf64-s390.c (elf_s390_create_dynamic_sections): Use
discard_sframe to guard .sframe section creation.
* elfxx-x86.c (_bfd_x86_elf_link_setup_gnu_properties): Likewise.
include/
* bfdlink.h (struct bfd_link_info): Add discard_sframe bitfield.
ld/
* ldlex.h (enum option_values): Add OPTION_NO_LD_SFRAME_INFO.
* lexsup.c (elf_sframe_list_options): New function.
(ld_list_options): Add sframe_info argument. Update callers.
* ld.texi: Update documentation.
* emulparams/sframe-info.sh: New file.
* emultempl/aarch64elf.em: Add --discard-sframe option
listing and handling.
* emulparams/elf64_s390.sh: Likewise.
* emulparams/elf_x86_64.sh: Likewise.
* Makefile.am: Update to handle sframe-info.sh and new list options.
* configure.ac: Handle SFRAME_INFO target variable.
* Makefile.in: Regenerate.
* configure: Regenerate.
ld/testsuite/
* ld-x86-64/x86-64.exp: New test.
* ld-x86-64/sframe-command-line-1.d: New test.
* ld-aarch64/aarch64-elf.exp: New test.
* ld-s390/s390.exp: New test.
* ld-x86-64/x86-64.exp: New test.
* ld-aarch64/sframe-command-line-1.d: New test.
* ld-s390/sframe-command-line-1.d: New test.
* ld-x86-64/sframe-command-line-1.d: New test.
ld: sframe: do not generate .sframe for PLT if no .sframe is in input BFDs
GNU ld creates SFrame stack trace info for the PLT. For x86 the linker-
created .sframe section is created in setup_gnu_properties. For s390 it
is created in create_dynamic_sections. For both, the section data is
itself emitted a bit later in late_size_sections. Note that for aarch64 the
linker does not create .sframe for PLT yet.
Recall that a previous patch 832ca9ef670 uncoupled
--no-ld-generated-unwind-info from the linker-generated .sframe
sections. This means that the linker now generates .sframe section (for
.plt*) for the first input BFD enthusiatically even when none of the
input BFDs have any .sframe section, unless --discard-sframe is also
added. The issue is that these (unexpected) linker-generated .sframe
sections (on x86_64, and s390) may now trip the linking process, e.g.,
when using --orphan-handling=error together with a linker script that
treats .sframe differently than the default linker script.
https://sourceware.org/pipermail/binutils/2026-January/147826.html
Further, with SFrame sections to be soon marked KEEP for fixing
GC/SFrame (PR ld/32769), the presence of these linker generated SFrame
sections will also cause emission of an empty .sframe (for x86_64 and
s390x), even when all input bfd's have no .sframe section.
This patch avoids creation of .sframe for .plt* if none of the input
BFDs had any .sframe section. This then avoids creation of empty
.sframe in linked objects on x86_64 and s390x, when none of the inputs
have SFrame sections. This also fixes PR ld/33830.
For the code changes:
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
New testcases have (since the above Reviewed-by) been added. Since
--no-ld-generated-unwind-info is not supported on aarch64, add
target-specific ld tests. Additionally add a generic test (for all
targets that support SFrame) to ensure no output .sframe is generated if
users says no --gsframe or similar.
bfd/
PR ld/33830
* elf-bfd.h (_bfd_elf_sframe_present_input_bfds): New
declaration.
* elf-sframe.c (_bfd_elf_sframe_present_input_bfds): New
definition.
* elf64-s390.c (elf_s390_create_dynamic_sections): Do not
generate .sframe for .plt unconditionally.
* elfxx-x86.c (_bfd_x86_elf_link_setup_gnu_properties):
Likewise.
ld/testsuite/
PR ld/33830
* ld-s390/no-sframe.ld: Linker script with no specification for
SFrame sections.
* ld-s390/s390.exp: Add new test.
* ld-s390/sframe-command-line-2.d: New testcase that uses
--no-ld-generated-unwind-info and a linker script that has no
specific rules for .sframe.
* ld-x86-64/no-sframe.ld: Likewise for x86_64.
* ld-x86-64/sframe-command-line-2.d: Likewise for x86_64.
* ld-x86-64/x86-64.exp: Add new test.
* ld-sframe/no-ld-generated-sframe.d: Ensure no .sframe in
output if no .sframe in input.
* ld-sframe/no-sframe.ld: Linker script with no specification
for SFrame sections.
* ld-sframe/test.s: Add new test.
s390: Initial support to generate .sframe from CFI directives in assembler
This introduces initial support to generate .sframe from CFI directives
in assembler on s390 64-bit (s390x). Due to SFrame V2 format
limitations it has the following limitations, some of them getting
addressed by subsequent patches, which cause generation of SFrame FDE
to be skipped:
- SFrame FP/RA tracking only supports register contents being saved on
the stack (i.e. .cfi_offset). It does not support FP/RA register
contents being saved in other registers (i.e. .cfi_register). GCC on
s390x can be observed to save the FP/RA register contents in floating-
point registers, but only in leaf functions.
This issue is detailed further and resolved in the subsequent commit
"s390: Represent FP/RA saved in register in SFrame".
- SFrame FP/RA tracking cannot represent FP without RA saved. This is
because the format assumes SFrame FDE offset2 to be the RA offset, if
there are two offsets, and offset3 to be the FP offset, if there are
three offsets. There is no mean to distinguish whether offset2 is the
RA or FP offset, if there are only two offsets.
This issue is detailed further and resolved in the subsequent commit
"s390: Represent FP without RA saved in SFrame".
- SFrame assumes a dedicated FP register number. The s390x ELF ABI [1]
does only designate register 11 as preferred FP register number. In
general GCC and Clang on s390x use register 11 as frame pointer.
GCC on s390x can be observed to use register 14 as frame pointer in
the stack clash protector in the function prologue.
glibc on s390x contains hand-written assembler code that uses
register 12 as frame pointer.
This s390x support is largely based on the AArch64 support from commit
b52c4ee46657 ("gas: generate .sframe from CFI directives").
The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced
for s390x and added to the SFrame format specification.
The s390x ELF ABI [1] specifies the following C calling conventions for
s390x architecture:
- Register 15 is the stack pointer (SP).
- Register 14 contains the return address (RA) at function entry.
- There is no dedicated frame pointer register. Register 11 is the
preferred frame pointer (FP). [2] GCC and Clang in general use
register 11 as frame pointer.
- The CFA is defined as SP at call site +160. [3] The SP at call site
can therefore be derived from the CFA using a SP value offset from CFA
of -160.
The s390x ELF ABI [1] does not assign any standard save slot to each
register in the register save area of a stack frame. Neither the
return address (RA, r14) nor preferred frame pointer (FP, r11)
necessarily need to be saved. Therefore SFrame RA and FP tracking is
used.
Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI
(z/Architecture with 64-bit addressing mode). It is disabled for the
32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing
mode).
s390x-specific SFrame assembler and linker tests are added, including
error tests for use of a non-preferred frame pointer (FP) register and
specification of a non-default return address (RA) register.
[1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases
[2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame
pointer register"),
https://github.com/IBM/s390x-abi/commit/f00421825979
[3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"),
https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88
include/
* sframe.h: Add reference to s390x architecture in comments.
(SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier
for s390x.
(SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value
offset from CFA.
libsframe/
* sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG.
* doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x,
SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier
for s390x, add references to s390x architecture, and document
s390x-specifics, such as the SP value offset from CFA of -160.
gas/
* config/tc-s390.h: s390x support to generate .sframe from CFI
directives in assembler.
(support_sframe_p): Define.
(SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG):
Define.
(sframe_ra_tracking_p): Define.
(sframe_cfa_ra_offset): Define.
(sframe_get_abi_arch): Define.
* config/tc-s390.c: s390x support to generate .sframe from CFI
directives in assembler.
(s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg,
s390_sframe_cfa_ra_reg): New. Initialize to DWARF register
numbers of stack pointer (SP, r15), preferred frame pointer
(FP, r11), and return address (RA, r14) registers.
(s390_support_sframe_p): New function. Return true if s390x.
(s390_sframe_ra_tracking_p): New function. Return true.
(s390_sframe_cfa_ra_offset): New function. Return
SFRAME_CFA_FIXED_RA_INVALID.
(s390_sframe_get_abi_arch): New function. Return
SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero.
* gen-sframe.c: Add reference to s390x architecture in comments.
(sframe_xlate_do_val_offset): Add support for s390x-specific
SFRAME_S390X_SP_VAL_OFFSET.
* NEWS: Add news entry.
gas/testsuite/
* gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for
s390x. Add s390x-specific SFrame (error) tests.
* gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame
test.
* gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific
SFrame error test that uses a non-default frame-pointer register
as CFA base register.
* gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific
SFrame error test that uses a non-default return address
register.
* gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x-
specific SFrame test that saves RA and FP individually on the
stack.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New
s390x-specific SFrame error test that saves FP and RA
individually, to trigger FP without RA saved.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New
s390x-specific SFrame error test that saves FP and RA
individually in registers.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s:
Likewise.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New
s390x-specific SFrame error test that saves RA and FP
individually in registers.
* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s:
Likewise.
ld/testsuite/
* ld-s390/s390.exp: Add simple SFrame test.
* ld-s390/sframe-simple-1.d: New simple SFrame test.
* ld-s390/sframe-bar.s: Likewise.
* ld-s390/sframe-foo.s: Likewise.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>