[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