[RFD] gas: elf: binutils: add new section type SHT_GNU_SFRAME

Indu Bhagat indu.bhagat@oracle.com
Wed Jun 25 06:06:28 GMT 2025


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.

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



More information about the Binutils mailing list