[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.
This commit is contained in:
Indu Bhagat
2026-01-15 16:43:35 -08:00
parent dc49e2f284
commit 832ca9ef67
21 changed files with 102 additions and 11 deletions

View File

@@ -211,6 +211,9 @@ _bfd_elf_parse_sframe (bfd *abfd,
bfd_size_type sf_size;
int decerr = 0;
if (info->discard_sframe)
sec->flags |= SEC_EXCLUDE;
/* 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. Even if section size is zero, a valid section type is

View File

@@ -4309,7 +4309,7 @@ elf_s390_create_dynamic_sections (bfd *dynobj,
}
/* Create .sframe section for .plt section. */
if (!info->no_ld_generated_unwind_info)
if (!info->discard_sframe)
{
flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY

View File

@@ -4827,7 +4827,7 @@ _bfd_x86_elf_link_setup_gnu_properties
}
/* .sframe sections are emitted for AMD64 ABI only. */
if (ABI_64_P (info->output_bfd) && !info->no_ld_generated_unwind_info)
if (ABI_64_P (info->output_bfd) && !info->discard_sframe)
{
flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY

View File

@@ -475,6 +475,10 @@ struct bfd_link_info
linker created sections, TRUE if it should be omitted. */
unsigned int no_ld_generated_unwind_info: 1;
/* TRUE if no .sframe stack trace info should be generated for the output.
This includes linker generated SFrame info as well. */
unsigned int discard_sframe: 1;
/* TRUE if BFD should generate a "task linked" object file,
similar to relocatable but also with globals converted to
statics. */

View File

@@ -42,7 +42,8 @@ ZLIBINC = @zlibinc@
ELF_CFLAGS=-DELF_LIST_OPTIONS=@elf_list_options@ \
-DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
-DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
-DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@ \
-DELF_SFRAME_LIST_OPTIONS=@elf_sframe_list_options@
WARN_CFLAGS = @WARN_CFLAGS@
NO_WERROR = @NO_WERROR@
AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CFLAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)

View File

@@ -520,6 +520,7 @@ docdir = @docdir@
dvidir = @dvidir@
elf_list_options = @elf_list_options@
elf_plt_unwind_list_options = @elf_plt_unwind_list_options@
elf_sframe_list_options = @elf_sframe_list_options@
elf_shlib_list_options = @elf_shlib_list_options@
enable_initfini_array = @enable_initfini_array@
enable_libctf = @enable_libctf@
@@ -579,7 +580,8 @@ ZLIB = @zlibdir@ -lz
ZLIBINC = @zlibinc@
ELF_CFLAGS = -DELF_LIST_OPTIONS=@elf_list_options@ \
-DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
-DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
-DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@ \
-DELF_SFRAME_LIST_OPTIONS=@elf_sframe_list_options@
AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CFLAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)

11
ld/configure vendored
View File

@@ -644,6 +644,7 @@ EMUL_EXTRA_OFILES
EMULATION_OFILES
TDIRS
EMUL
elf_sframe_list_options
elf_plt_unwind_list_options
elf_shlib_list_options
elf_list_options
@@ -11893,7 +11894,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 11896 "configure"
#line 11897 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11999,7 +12000,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 12002 "configure"
#line 12003 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -19211,6 +19212,7 @@ TDIRS=
elf_list_options=false
elf_shlib_list_options=false
elf_plt_unwind_list_options=false
elf_sframe_list_options=false
for targ_alias in `echo $target_alias $enable_targets | sed 's/,/ /g'`
do
if test "$targ_alias" = "all"; then
@@ -19218,6 +19220,7 @@ do
elf_list_options=true
elf_shlib_list_options=true
elf_plt_unwind_list_options=true
elf_sframe_list_options=true
else
# Canonicalize the secondary target names.
result=`$ac_config_sub $targ_alias 2>/dev/null`
@@ -19273,6 +19276,9 @@ tdir_$i=$result"
if test x${PLT_UNWIND} = xyes; then
elf_plt_unwind_list_options=true
fi
if test x${SFRAME_INFO} = xyes; then
elf_sframe_list_options=true
fi
fi
;;
esac
@@ -19481,6 +19487,7 @@ _ACEOF
if test x${all_targets} = xtrue; then
if test x${have_64_bit_bfd} = xyes; then
EMULATION_OFILES='$(ALL_EMULATIONS) $(ALL_64_EMULATIONS)'

View File

@@ -506,6 +506,7 @@ TDIRS=
elf_list_options=false
elf_shlib_list_options=false
elf_plt_unwind_list_options=false
elf_sframe_list_options=false
for targ_alias in `echo $target_alias $enable_targets | sed 's/,/ /g'`
do
if test "$targ_alias" = "all"; then
@@ -513,6 +514,7 @@ do
elf_list_options=true
elf_shlib_list_options=true
elf_plt_unwind_list_options=true
elf_sframe_list_options=true
else
# Canonicalize the secondary target names.
result=`$ac_config_sub $targ_alias 2>/dev/null`
@@ -568,6 +570,9 @@ tdir_$i=$result"
if test x${PLT_UNWIND} = xyes; then
elf_plt_unwind_list_options=true
fi
if test x${SFRAME_INFO} = xyes; then
elf_sframe_list_options=true
fi
fi
;;
esac
@@ -730,6 +735,7 @@ AC_DEFINE_UNQUOTED([DEFAULT_EMIT_GNU_HASH],
AC_SUBST(elf_list_options)
AC_SUBST(elf_shlib_list_options)
AC_SUBST(elf_plt_unwind_list_options)
AC_SUBST(elf_sframe_list_options)
AC_SUBST(EMUL)
AC_SUBST(TDIRS)

View File

@@ -1,4 +1,5 @@
source_sh ${srcdir}/emulparams/plt_unwind.sh
source_sh ${srcdir}/emulparams/sframe-info.sh
SCRIPT_NAME=elf
ELFSIZE=64
OUTPUT_FORMAT="elf64-s390"

View File

@@ -1,4 +1,5 @@
source_sh ${srcdir}/emulparams/plt_unwind.sh
source_sh ${srcdir}/emulparams/sframe-info.sh
source_sh ${srcdir}/emulparams/extern_protected_data.sh
source_sh ${srcdir}/emulparams/dynamic_undefined_weak.sh
source_sh ${srcdir}/emulparams/reloc_overflow.sh

View File

@@ -0,0 +1,15 @@
SFRAME_INFO=yes
PARSE_AND_LIST_LONGOPTS_SFRAME='
{"discard-sframe", no_argument, NULL,
OPTION_DISCARD_SFRAME},
'
PARSE_AND_LIST_ARGS_CASES_SFRAME='
case OPTION_DISCARD_SFRAME:
link_info.discard_sframe = true;
break;
'
PARSE_AND_LIST_LONGOPTS="$PARSE_AND_LIST_LONGOPTS $PARSE_AND_LIST_LONGOPTS_SFRAME"
PARSE_AND_LIST_ARGS_CASES="$PARSE_AND_LIST_ARGS_CASES $PARSE_AND_LIST_ARGS_CASES_SFRAME"

View File

@@ -487,6 +487,7 @@ PARSE_AND_LIST_LONGOPTS='
{ "fix-cortex-a53-835769", no_argument, NULL, OPTION_FIX_ERRATUM_835769},
{ "fix-cortex-a53-843419", optional_argument, NULL, OPTION_FIX_ERRATUM_843419},
{ "no-apply-dynamic-relocs", no_argument, NULL, OPTION_NO_APPLY_DYNAMIC_RELOCS},
{ "discard-sframe", no_argument, NULL, OPTION_DISCARD_SFRAME},
'
PARSE_AND_LIST_OPTIONS='
@@ -495,6 +496,7 @@ PARSE_AND_LIST_OPTIONS='
fprintf (file, _(" --no-wchar-size-warning Don'\''t warn about objects with incompatible\n"
" wchar_t sizes\n"));
fprintf (file, _(" --pic-veneer Always generate PIC interworking veneers\n"));
fprintf (file, _(" --discard-sframe Don'\''t generate SFrame stack trace info in output\n"));
fprintf (file, _("\
--stub-group-size=N Maximum size of a group of input sections that\n\
can be handled by one stub section. A negative\n\
@@ -632,6 +634,11 @@ PARSE_AND_LIST_ARGS_CASES='
fatal (_("%P: invalid number `%s'\''\n"), optarg);
}
break;
case OPTION_DISCARD_SFRAME:
link_info.discard_sframe = true;
break;
'
# We have our own before_allocation etc. functions, but they call

View File

@@ -3251,9 +3251,13 @@ section and ELF @code{PT_GNU_EH_FRAME} segment header.
@item --no-ld-generated-unwind-info
Request creation of @code{.eh_frame} unwind info for linker
generated code sections like PLT. This option is on by default
if linker generated unwind info is supported. This option also
controls the generation of @code{.sframe} stack trace info for linker
generated code sections like PLT.
if linker generated unwind info is supported.
@kindex --discard-sframe
@item --discard-sframe
Discard @code{.sframe} stack trace info from the output. This option also
prohibits the creation of SFrame stack trace data for linker generated code
sections like PLT. This option is off by default.
@kindex --enable-new-dtags
@kindex --disable-new-dtags

View File

@@ -215,6 +215,8 @@ enum option_values
/* Used by emulparams/plt_unwind.sh. */
OPTION_LD_GENERATED_UNWIND_INFO,
OPTION_NO_LD_GENERATED_UNWIND_INFO,
/* Used by emulparams/sframe-info.sh. */
OPTION_DISCARD_SFRAME,
/* Used by emultempl/aarch64elf.em. */
OPTION_FIX_ERRATUM_835769,
OPTION_FIX_ERRATUM_843419,

View File

@@ -2364,13 +2364,23 @@ elf_plt_unwind_list_options (FILE *file)
}
static void
ld_list_options (FILE *file, bool elf, bool shlib, bool plt_unwind)
elf_sframe_list_options (FILE *file)
{
fprintf (file, _("\
--discard-sframe Don't generate SFrame stack trace info in output\n"));
}
static void
ld_list_options (FILE *file, bool elf, bool shlib, bool plt_unwind,
bool sframe_info)
{
if (!elf)
return;
printf (_("ELF emulations:\n"));
if (plt_unwind)
elf_plt_unwind_list_options (file);
if (sframe_info)
elf_sframe_list_options (file);
elf_static_list_options (file);
if (shlib)
elf_shlib_list_options (file);
@@ -2495,7 +2505,8 @@ help (void)
/* xgettext:c-format */
printf (_("%s: emulation specific options:\n"), program_name);
ld_list_options (stdout, ELF_LIST_OPTIONS, ELF_SHLIB_LIST_OPTIONS,
ELF_PLT_UNWIND_LIST_OPTIONS);
ELF_PLT_UNWIND_LIST_OPTIONS,
ELF_SFRAME_LIST_OPTIONS);
ldemul_list_emulation_options (stdout);
printf ("\n");

View File

@@ -430,4 +430,5 @@ if { [supports_dt_relr] } {
if { ![skip_sframe_tests] } {
run_dump_test "sframe-simple-1"
run_dump_test "sframe-command-line-1"
}

View File

@@ -0,0 +1,8 @@
#as: --gsframe
#source: sframe-foo.s
#source: sframe-bar.s
#readelf: --sframe
#ld: -shared --discard-sframe
#name: Command line option --discard-sframe
Section '.sframe' has no debugging data.

View File

@@ -192,5 +192,6 @@ if [istarget "s390x-*-*"] {
if { ![skip_sframe_tests] } {
run_dump_test "sframe-simple-1"
run_dump_test "sframe-plt-1"
run_dump_test "sframe-command-line-1"
}
}

View File

@@ -0,0 +1,8 @@
#as: --gsframe
#source: sframe-foo.s
#source: sframe-bar.s
#readelf: --sframe
#ld: -shared --no-rosegment --discard-sframe
#name: Command line option --discard-sframe
Section '.sframe' has no debugging data.

View File

@@ -0,0 +1,8 @@
#as: --gsframe
#source: sframe-foo.s
#source: sframe-bar.s
#readelf: --sframe
#ld: -shared --no-rosegment -z separate-code --discard-sframe
#name: Command line option --discard-sframe
Section '.sframe' has no debugging data.

View File

@@ -587,6 +587,7 @@ run_dump_test "tls-le-pic-3-x32"
if { ![skip_sframe_tests] } {
run_dump_test "sframe-simple-1"
run_dump_test "sframe-command-line-1"
run_dump_test "sframe-reloc-1"
run_dump_test "sframe-plt-1"
run_dump_test "sframe-ibt-plt-1"