[RFD] gas: elf: binutils: add new section type SHT_GNU_SFRAME
H.J. Lu
hjl.tools@gmail.com
Wed Jun 25 07:05:23 GMT 2025
On Wed, Jun 25, 2025 at 2:07 PM Indu Bhagat via Binutils
<binutils@sourceware.org> wrote:
>
> Hi,
>
> Following up on one of the suggestions for SFrame to be a good ELF
> citizen was for it to have its own section type. This patch tries to
> address the concern by adding a new section type SHT_GNU_SFRAME.
>
> As SFrame sections are not yet enabled extensivley in user space (and
> support in LLVM being added now), we have a window of opportunity now to
> add the section type without causing much damage. But such a judgement
> needs careful thought, hence the RFD nature of this proposal.
>
> So far, SFrame sections were of type SHT_PROGBITS.
>
> As per ELF specification, SHT_PROGBITS indicates that the section holds
> information defined by the program, whose format and meaning are
> determined solely by the program.
>
> On the linker side, SHT_PROGBITS should be reserved for the simple "cat
> contents after applying relocs" semantics.
>
> Currently, the only way to know that a section contains SFrame stack
> trace data is if consumer checks for section name. Such a check for
> section name is not quite conformant to ELF principles.
>
> Some of this was discussed here
> https://sourceware.org/pipermail/binutils/2025-March/140181.html
>
> With this change, SFrame sections generated by GNU Binutils will be of
> type SHT_GNU_SFRAME. The new section type is defined in the
> SHT_LOOS/SHT_HIOS space.
>
> The SFrame sections generated by gas, ld will have section type set to
> SHT_GNU_SFRAME. The SFrame parsing routine _bfd_elf_parse_sframe () now
> checks if the section type is not SHT_GNU_SFRAME.
Please send a patch to document it at
https://gitlab.com/x86-psABIs/Linux-ABI
> ChangeLog:
>
> * bfd/elf-sframe.c (_bfd_elf_parse_sframe): Check if section
> type is SHT_GNU_SFRAME.
> (_bfd_elf_set_section_sframe): Set SHT_GNU_SFRAME for output
> SFrame section.
> * bfd/elflink.c (_bfd_elf_default_action_discarded): Use section
> type for check instead of section name.
> * bfd/elfxx-x86.c: Set SHT_GNU_SFRAME for SFrame sections for
> .plt* sections.
> * binutils/readelf.c (get_os_specific_section_type_name): Add
> SHT_GNU_SFRAME.
> * gas/dw2gencfi.c (cfi_finish): Set SHT_GNU_SFRAME for emitted
> SFrame section.
> * gas/testsuite/gas/cfi-sframe/cfi-sframe.exp: Add new test.
> * gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.d: New test.
> * gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.s: New test.
>
> include/ChangeLog:
>
> * elf/common.h (SHT_GNU_SFRAME): Add new section type for SFrame
> stack trace information.
>
> libsframe/ChangeLog:
> * libsframe/doc/sframe-spec.texi: Add expected ELF section type.
>
> ---
> bfd/elf-sframe.c | 14 ++++++++++++--
> bfd/elflink.c | 2 +-
> bfd/elfxx-x86.c | 15 ++++++---------
> binutils/readelf.c | 2 ++
> gas/dw2gencfi.c | 3 +++
> .../gas/cfi-sframe/cfi-sframe-common-1b.d | 6 ++++++
> .../gas/cfi-sframe/cfi-sframe-common-1b.s | 3 +++
> gas/testsuite/gas/cfi-sframe/cfi-sframe.exp | 1 +
> include/elf/common.h | 2 ++
> libsframe/doc/sframe-spec.texi | 7 ++++---
> 10 files changed, 40 insertions(+), 15 deletions(-)
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.s
>
> diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c
> index 97e00734515..1fe2293238b 100644
> --- a/bfd/elf-sframe.c
> +++ b/bfd/elf-sframe.c
> @@ -197,6 +197,16 @@ _bfd_elf_parse_sframe (bfd *abfd,
> /* This file does not contain .sframe information. */
> return false;
> }
> + /* Prior versions of assembler and ld were generating SFrame sections with
> + section type SHT_PROGBITS. Issue an error for lack of support for such
> + objects now. */
> + else if (elf_section_type (sec) != SHT_GNU_SFRAME)
> + {
> + _bfd_error_handler
> + (_("error in %pB(%pA); unexpected SFrame section type"),
> + abfd, sec);
> + return false;
> + }
>
> if (bfd_is_abs_section (sec->output_section))
> {
> @@ -296,8 +306,7 @@ _bfd_elf_discard_section_sframe
> BFD ABFD. Returns true if no error. */
>
> bool
> -_bfd_elf_set_section_sframe (bfd *abfd,
> - struct bfd_link_info *info)
> +_bfd_elf_set_section_sframe (bfd *abfd, struct bfd_link_info *info)
> {
> asection *cfsec;
>
> @@ -305,6 +314,7 @@ _bfd_elf_set_section_sframe (bfd *abfd,
> if (!cfsec)
> return false;
>
> + elf_section_type (cfsec) = SHT_GNU_SFRAME;
> elf_sframe (abfd) = cfsec;
>
> return true;
> diff --git a/bfd/elflink.c b/bfd/elflink.c
> index 666399bc680..c4f57cf2f3c 100644
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -11293,7 +11293,7 @@ _bfd_elf_default_action_discarded (asection *sec)
> && strncmp (sec->name, ".eh_frame.", 10) == 0)
> return 0;
>
> - if (strcmp (".sframe", sec->name) == 0)
> + if (elf_section_type (sec) == SHT_GNU_SFRAME)
> return 0;
>
> if (strcmp (".gcc_except_table", sec->name) == 0)
> diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
> index bc9bb7010ce..282d4acae39 100644
> --- a/bfd/elfxx-x86.c
> +++ b/bfd/elfxx-x86.c
> @@ -4785,11 +4785,10 @@ _bfd_x86_elf_link_setup_gnu_properties
> | SEC_HAS_CONTENTS | SEC_IN_MEMORY
> | SEC_LINKER_CREATED);
>
> - sec = bfd_make_section_anyway_with_flags (dynobj,
> - ".sframe",
> - flags);
> + sec = bfd_make_section_anyway_with_flags (dynobj, ".sframe", flags);
> if (sec == NULL)
> info->callbacks->fatal (_("%P: failed to create PLT .sframe section\n"));
> + elf_section_type (sec) = SHT_GNU_SFRAME;
>
> // FIXME check this
> // if (!bfd_set_section_alignment (sec, class_align))
> @@ -4800,11 +4799,10 @@ _bfd_x86_elf_link_setup_gnu_properties
> /* Second PLT is generated for Intel IBT + lazy plt. */
> if (htab->plt_second != NULL)
> {
> - sec = bfd_make_section_anyway_with_flags (dynobj,
> - ".sframe",
> - flags);
> + sec = bfd_make_section_anyway_with_flags (dynobj, ".sframe", flags);
> if (sec == NULL)
> info->callbacks->fatal (_("%P: failed to create second PLT .sframe section\n"));
> + elf_section_type (sec) = SHT_GNU_SFRAME;
>
> htab->plt_second_sframe = sec;
> }
> @@ -4812,11 +4810,10 @@ _bfd_x86_elf_link_setup_gnu_properties
> /* .plt.got. */
> if (htab->plt_got != NULL)
> {
> - sec = bfd_make_section_anyway_with_flags (dynobj,
> - ".sframe",
> - flags);
> + sec = bfd_make_section_anyway_with_flags (dynobj, ".sframe", flags);
> if (sec == NULL)
> info->callbacks->fatal (_("%P: failed to create PLT GOT .sframe section\n"));
> + elf_section_type (sec) = SHT_GNU_SFRAME;
>
> htab->plt_got_sframe = sec;
> }
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index 77a88bff032..0db3819f6ec 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -5964,6 +5964,7 @@ get_os_specific_section_type_name (Filedata * filedata, unsigned int sh_type)
> case SHT_GNU_HASH: return "GNU_HASH";
> case SHT_GNU_LIBLIST: return "GNU_LIBLIST";
> case SHT_GNU_OBJECT_ONLY: return "GNU_OBJECT_ONLY";
> + case SHT_GNU_SFRAME: return "SFRAME";
>
> case SHT_SUNW_move: return "SUNW_MOVE";
> case SHT_SUNW_COMDAT: return "SUNW_COMDAT";
> @@ -8359,6 +8360,7 @@ process_section_headers (Filedata * filedata)
>
> case SHT_NOTE:
> case SHT_PROGBITS:
> + case SHT_GNU_SFRAME:
> /* Having a zero sized section is not illegal according to the
> ELF standard, but it might be an indication that something
> is wrong. So issue a warning if we are running in lint mode. */
> diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
> index a21ae322488..ab886a9e4d9 100644
> --- a/gas/dw2gencfi.c
> +++ b/gas/dw2gencfi.c
> @@ -2601,6 +2601,7 @@ cfi_finish (void)
> flag_traditional_format = save_flag_traditional_format;
> }
>
> +#ifdef OBJ_ELF
> /* Generate SFrame section if the user specifies:
> - the command line option to gas, or
> - .sframe in the .cfi_sections directive. */
> @@ -2615,11 +2616,13 @@ cfi_finish (void)
> (SEC_ALLOC | SEC_LOAD | SEC_DATA
> | DWARF2_EH_FRAME_READ_ONLY),
> alignment);
> + elf_section_type (sframe_seg) = SHT_GNU_SFRAME;
> output_sframe (sframe_seg);
> }
> else
> as_bad (_(".sframe not supported for target"));
> }
> +#endif
>
> if ((all_cfi_sections & CFI_EMIT_debug_frame) != 0)
> {
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.d
> new file mode 100644
> index 00000000000..bfc8fee8388
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.d
> @@ -0,0 +1,6 @@
> +#as: --gsframe
> +#readelf: -S
> +#name: SFrame section header in readelf output
> +#...
> +[ ]*\[.*\][ ]+\.sframe[ ]+SFRAME.*
> +#...
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.s
> new file mode 100644
> index 00000000000..ac9c6ca2cf3
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1b.s
> @@ -0,0 +1,3 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> index 341a56a9eab..dbe48bae01a 100644
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> @@ -71,6 +71,7 @@ if { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]) \
> set old_ASFLAGS "$ASFLAGS"
>
> run_dump_test "cfi-sframe-common-1"
> + run_dump_test "cfi-sframe-common-1b"
> run_dump_test "cfi-sframe-common-2"
> run_dump_test "cfi-sframe-common-3"
> run_dump_test "cfi-sframe-common-4"
> diff --git a/include/elf/common.h b/include/elf/common.h
> index 01812b48caa..cf23aeea2fa 100644
> --- a/include/elf/common.h
> +++ b/include/elf/common.h
> @@ -553,6 +553,8 @@
>
> #define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700 /* Incremental build data */
>
> +#define SHT_GNU_SFRAME 0x6fff4800 /* SFrame stack trace information. */
> +
> #define SHT_LLVM_ODRTAB 0x6fff4c00 /* LLVM ODR table. */
> #define SHT_LLVM_LINKER_OPTIONS 0x6fff4c01 /* LLVM Linker Options. */
> #define SHT_LLVM_ADDRSIG 0x6fff4c03 /* List of address-significant symbols for safe ICF. */
> diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
> index 6b8dfa80650..8da59f50e51 100644
> --- a/libsframe/doc/sframe-spec.texi
> +++ b/libsframe/doc/sframe-spec.texi
> @@ -77,9 +77,10 @@ Appendices
> @section Overview
> @cindex Overview
>
> -The SFrame stack trace information is provided in a loaded section, known as the
> -@code{.sframe} section. When available, the @code{.sframe} section appears in
> -a new segment of its own, PT_GNU_SFRAME.
> +The SFrame stack trace information is provided in a loaded section, known as
> +the @code{.sframe} section. When available, the @code{.sframe} section appears
> +in a new segment of its own, PT_GNU_SFRAME. An ELF SFrame section will have
> +the type SHT_GNU_SFRAME.
>
> The SFrame format is currently supported only for select ABIs, namely, AMD64
> and AAPCS64.
> --
> 2.43.0
>
--
H.J.
More information about the Binutils
mailing list