From: Indu Bhagat Date: Fri, 16 Jan 2026 00:43:35 +0000 (-0800) Subject: [SFrame-V3] ld: add --discard-sframe command line option X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=832ca9ef67064aa3bdb198e3d591aaab9261bd6d;p=thirdparty%2Fbinutils-gdb.git [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. --- diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c index 511a297054b..33e4df5b1c7 100644 --- a/bfd/elf-sframe.c +++ b/bfd/elf-sframe.c @@ -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 diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index 012457827e0..8ad10ce6bd1 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -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 diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 0348da9f0a1..901b858fb34 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -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 diff --git a/include/bfdlink.h b/include/bfdlink.h index d715fcbd6fb..eac72b8c388 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -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. */ diff --git a/ld/Makefile.am b/ld/Makefile.am index 3f2a9ae9832..c219662d2e3 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -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) diff --git a/ld/Makefile.in b/ld/Makefile.in index 0af36e9e310..f1ba6af5269 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -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) diff --git a/ld/configure b/ld/configure index 3dcd0aaca72..bd10f0a145b 100755 --- a/ld/configure +++ b/ld/configure @@ -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)' diff --git a/ld/configure.ac b/ld/configure.ac index a0a1361a0eb..8c5e9606ac0 100644 --- a/ld/configure.ac +++ b/ld/configure.ac @@ -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) diff --git a/ld/emulparams/elf64_s390.sh b/ld/emulparams/elf64_s390.sh index b58314800d1..750e83b714f 100644 --- a/ld/emulparams/elf64_s390.sh +++ b/ld/emulparams/elf64_s390.sh @@ -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" diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh index fb4fcd6ae17..747114bc4b4 100644 --- a/ld/emulparams/elf_x86_64.sh +++ b/ld/emulparams/elf_x86_64.sh @@ -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 diff --git a/ld/emulparams/sframe-info.sh b/ld/emulparams/sframe-info.sh new file mode 100644 index 00000000000..b7cc10bd981 --- /dev/null +++ b/ld/emulparams/sframe-info.sh @@ -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" diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em index e15eb432458..cd3a6c63d99 100644 --- a/ld/emultempl/aarch64elf.em +++ b/ld/emultempl/aarch64elf.em @@ -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 diff --git a/ld/ld.texi b/ld/ld.texi index 1ec56c08337..7cadc853af9 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -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 diff --git a/ld/ldlex.h b/ld/ldlex.h index 1efbe58002b..85e06b6fcc4 100644 --- a/ld/ldlex.h +++ b/ld/ldlex.h @@ -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, diff --git a/ld/lexsup.c b/ld/lexsup.c index 843b809bacb..158abb6dd8f 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -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"); diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index 8791df3f3d3..a0a8867dca1 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -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" } diff --git a/ld/testsuite/ld-aarch64/sframe-command-line-1.d b/ld/testsuite/ld-aarch64/sframe-command-line-1.d new file mode 100644 index 00000000000..a9255d4abaa --- /dev/null +++ b/ld/testsuite/ld-aarch64/sframe-command-line-1.d @@ -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. diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp index b81ebe280da..0fdfb39c5aa 100644 --- a/ld/testsuite/ld-s390/s390.exp +++ b/ld/testsuite/ld-s390/s390.exp @@ -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" } } diff --git a/ld/testsuite/ld-s390/sframe-command-line-1.d b/ld/testsuite/ld-s390/sframe-command-line-1.d new file mode 100644 index 00000000000..90ce394f5cf --- /dev/null +++ b/ld/testsuite/ld-s390/sframe-command-line-1.d @@ -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. diff --git a/ld/testsuite/ld-x86-64/sframe-command-line-1.d b/ld/testsuite/ld-x86-64/sframe-command-line-1.d new file mode 100644 index 00000000000..3f54ff9f83a --- /dev/null +++ b/ld/testsuite/ld-x86-64/sframe-command-line-1.d @@ -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. diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index f80f718c15b..df2bb5ea1bd 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -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"