[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