commit: 94c4ba7c7271a8356739b2da33bb921c9caa447d Author: Sam James <sam <AT> gentoo <DOT> org> AuthorDate: Wed Jul 23 22:36:53 2025 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Wed Jul 23 22:37:31 2025 +0000 URL: https://gitweb.gentoo.org/proj/toolchain/binutils-patches.git/commit/?id=94c4ba7c
9999: add strip vs LTO IR patch Bug: https://sourceware.org/PR33198 Signed-off-by: Sam James <sam <AT> gentoo.org> ...006-strip-Properly-handle-LLVM-IR-bitcode.patch | 523 +++++++++++++++++++++ 1 file changed, 523 insertions(+) diff --git a/9999/0006-strip-Properly-handle-LLVM-IR-bitcode.patch b/9999/0006-strip-Properly-handle-LLVM-IR-bitcode.patch new file mode 100644 index 0000000..ccb99ed --- /dev/null +++ b/9999/0006-strip-Properly-handle-LLVM-IR-bitcode.patch @@ -0,0 +1,523 @@ +https://sourceware.org/bugzilla/show_bug.cgi?id=33198#c2 + +From 252058908602dc41b2e483e663aba211395c5c9d Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" <[email protected]> +Date: Tue, 22 Jul 2025 14:09:48 -0700 +Subject: [PATCH] strip: Properly handle LLVM IR bitcode + +commit 717a38e9a02109fcbcb18bb2ec3aa251e2ad0a0d +Author: H.J. Lu <[email protected]> +Date: Sun May 4 05:12:46 2025 +0800 + + strip: Add GCC LTO IR support + +added "-R .gnu.lto_.*" to strip to remove the GCC LTO sections. When +"-R .gnu.lto_.*" is used, the plugin target is ignored so that the LTO +sections are stripped as the regular sections. It works for the non-fat +GCC LTO IR since the GCC LTO IR is stored in the regular sections. When +the plugin target is ignored, the GCC LTO IR can be recognized as the +normal object files. But it doesn't work for the non-fat LLVM IR which +is stored in a standalone file. + +1. Add bfd_check_format_matches_lto and bfd_check_format_lto to take an +argument, lto_sections_removed, to indicate if LTO sections should be +ignored. +2. Update strip to always enable the plugin target so that the plugin +target is enabled when checking for bfd_archive. +3. Update strip to ignore the plugin target for bfd_object when all LTO +sections should be removed. If the object is unknown, copy it as an +unknown file without any messages. +4. Treat the "-R .llvm.lto" strip option as removing all LTO sections. + +bfd/ + + PR binutils/33198 + * format.c (bfd_check_format_lto): New function. + (bfd_check_format): Call bfd_check_format_matches_lto. + (bfd_check_format_matches): Renamed to ... + (bfd_check_format_matches_lto): This. Add an argument, + lto_sections_removed, to indicate if LTO sections should be + removed and don't match the plugin target if lto_sections_removed + is true. + (bfd_check_format_matches): Call bfd_check_format_matches_lto. + * bfd-in2.h: Regenerated. + +binutils/ + + PR binutils/33198 + * objcopy.c (copy_archive): Call bfd_check_format_lto, instead + of bfd_check_format, and pass lto_sections_removed. Remove the + non-fatal message on unknown element since it will be copied as + an unknown file. + (copy_file): Don't check lto_sections_removed when enabling LTO + plugin in strip. + (copy_file): Ignore plugin target first if all LTO sections should + be removed. Try with plugin target next if ignoring plugin target + fails to match the format. + (strip_main): Also set lto_sections_removed for -R .llvm.lto. + * testsuite/binutils-all/x86-64/pr33198.c: New file. + * testsuite/binutils-all/x86-64/x86-64.exp (run_pr33198_test): + New. + Run binutils/33198 tests. + +Signed-off-by: H.J. Lu <[email protected]> +--- + bfd/bfd-in2.h | 7 + + bfd/format.c | 84 ++++++++-- + binutils/objcopy.c | 40 +++-- + .../testsuite/binutils-all/x86-64/pr33198.c | 4 + + .../testsuite/binutils-all/x86-64/x86-64.exp | 158 ++++++++++++++++++ + binutils/testsuite/lib/binutils-common.exp | 16 ++ + 6 files changed, 288 insertions(+), 21 deletions(-) + create mode 100644 binutils/testsuite/binutils-all/x86-64/pr33198.c + +diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h +index b013ef954da..2ff3e930bfa 100644 +--- a/bfd/bfd-in2.h ++++ b/bfd/bfd-in2.h +@@ -2903,8 +2903,15 @@ bool generic_core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + + /* Extracted from format.c. */ ++bool bfd_check_format_lto (bfd *abfd, bfd_format format, ++ bool lto_sections_removed); ++ + bool bfd_check_format (bfd *abfd, bfd_format format); + ++bool bfd_check_format_matches_lto ++ (bfd *abfd, bfd_format format, char ***matching, ++ bool lto_sections_removed); ++ + bool bfd_check_format_matches + (bfd *abfd, bfd_format format, char ***matching); + +diff --git a/bfd/format.c b/bfd/format.c +index a909b70fe81..f3a0774af08 100644 +--- a/bfd/format.c ++++ b/bfd/format.c +@@ -56,16 +56,19 @@ extern const size_t _bfd_target_vector_entries; + + /* + FUNCTION +- bfd_check_format ++ bfd_check_format_lto + + SYNOPSIS +- bool bfd_check_format (bfd *abfd, bfd_format format); ++ bool bfd_check_format_lto (bfd *abfd, bfd_format format, ++ bool lto_sections_removed); + + DESCRIPTION + Verify if the file attached to the BFD @var{abfd} is compatible + with the format @var{format} (i.e., one of <<bfd_object>>, + <<bfd_archive>> or <<bfd_core>>). + ++ If LTO_SECTION_REMOVED is true, ignore plugin target. ++ + If the BFD has been set to a specific target before the + call, only the named target and format combination is + checked. If the target has not been set, or has been set to +@@ -99,10 +102,31 @@ DESCRIPTION + itself. + */ + ++bool ++bfd_check_format_lto (bfd *abfd, bfd_format format, ++ bool lto_sections_removed) ++{ ++ return bfd_check_format_matches_lto (abfd, format, NULL, ++ lto_sections_removed); ++} ++ ++ ++/* ++FUNCTION ++ bfd_check_format ++ ++SYNOPSIS ++ bool bfd_check_format (bfd *abfd, bfd_format format); ++ ++DESCRIPTION ++ Similar to bfd_check_format_plugin, except plugin target isn't ++ ignored. ++*/ ++ + bool + bfd_check_format (bfd *abfd, bfd_format format) + { +- return bfd_check_format_matches (abfd, format, NULL); ++ return bfd_check_format_matches_lto (abfd, format, NULL, false); + } + + struct bfd_preserve +@@ -407,11 +431,12 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED) + + /* + FUNCTION +- bfd_check_format_matches ++ bfd_check_format_matches_lto + + SYNOPSIS +- bool bfd_check_format_matches +- (bfd *abfd, bfd_format format, char ***matching); ++ bool bfd_check_format_matches_lto ++ (bfd *abfd, bfd_format format, char ***matching, ++ bool lto_sections_removed); + + DESCRIPTION + Like <<bfd_check_format>>, except when it returns FALSE with +@@ -423,10 +448,14 @@ DESCRIPTION + + When done with the list that @var{matching} points to, the caller + should free it. ++ ++ If LTO_SECTION_REMOVED is true, ignore plugin target. + */ + + bool +-bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) ++bfd_check_format_matches_lto (bfd *abfd, bfd_format format, ++ char ***matching, ++ bool lto_sections_removed ATTRIBUTE_UNUSED) + { + extern const bfd_target binary_vec; + const bfd_target * const *target; +@@ -495,8 +524,13 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) + if (!bfd_preserve_save (abfd, &preserve, NULL)) + goto err_ret; + +- /* If the target type was explicitly specified, just check that target. */ +- if (!abfd->target_defaulted) ++ /* If the target type was explicitly specified, just check that target. ++ If LTO_SECTION_REMOVED is true, don't match the plugin target. */ ++ if (!abfd->target_defaulted ++#if BFD_SUPPORTS_PLUGINS ++ && (!lto_sections_removed || !bfd_plugin_target_p (abfd->xvec)) ++#endif ++ ) + { + if (bfd_seek (abfd, 0, SEEK_SET) != 0) /* rewind! */ + goto err_ret; +@@ -540,10 +574,12 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) + searching. Don't match the plugin target if we have another + alternative since we want to properly set the input format + before allowing a plugin to claim the file. Also, don't +- check the default target twice. */ ++ check the default target twice. If LTO_SECTION_REMOVED is ++ true, don't match the plugin target. */ + if (*target == &binary_vec + #if BFD_SUPPORTS_PLUGINS +- || (match_count != 0 && bfd_plugin_target_p (*target)) ++ || ((lto_sections_removed || match_count != 0) ++ && bfd_plugin_target_p (*target)) + #endif + || (!abfd->target_defaulted && *target == save_targ)) + continue; +@@ -795,6 +831,32 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) + return false; + } + ++/* ++FUNCTION ++ bfd_check_format_matches ++ ++SYNOPSIS ++ bool bfd_check_format_matches ++ (bfd *abfd, bfd_format format, char ***matching); ++ ++DESCRIPTION ++ Like <<bfd_check_format>>, except when it returns FALSE with ++ <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that ++ case, if @var{matching} is not NULL, it will be filled in with ++ a NULL-terminated list of the names of the formats that matched, ++ allocated with <<malloc>>. ++ Then the user may choose a format and try again. ++ ++ When done with the list that @var{matching} points to, the caller ++ should free it. ++*/ ++ ++bool ++bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) ++{ ++ return bfd_check_format_matches_lto (abfd, format, matching, false); ++} ++ + /* + FUNCTION + bfd_set_format +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 2ca04e84d47..905ce917708 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -3741,10 +3741,13 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, + l->obfd = NULL; + list = l; + ++#if BFD_SUPPORTS_PLUGINS ++ /* Ignore plugin target if all LTO sections should be removed. */ ++ ok_object = bfd_check_format_lto (this_element, bfd_object, ++ lto_sections_removed); ++#else + ok_object = bfd_check_format (this_element, bfd_object); +- if (!ok_object) +- bfd_nonfatal_message (NULL, this_element, NULL, +- _("Unable to recognise the format of file")); ++#endif + + /* PR binutils/3110: Cope with archives + containing multiple target types. */ +@@ -3880,9 +3883,8 @@ copy_file (const char *input_filename, const char *output_filename, int ofd, + } + + #if BFD_SUPPORTS_PLUGINS +- /* Enable LTO plugin in strip unless all LTO sections should be +- removed. */ +- if (is_strip && !target && !lto_sections_removed) ++ /* Enable LTO plugin in strip. */ ++ if (is_strip && !target) + target = "plugin"; + #endif + +@@ -3980,7 +3982,21 @@ copy_file (const char *input_filename, const char *output_filename, int ofd, + input_arch)) + status = 1; + } +- else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching)) ++ else if ( ++#if BFD_SUPPORTS_PLUGINS ++ /* Ignore plugin target first if all LTO sections should be ++ removed. Try with plugin target next if ignoring plugin ++ target fails to match the format. */ ++ bfd_check_format_matches_lto (ibfd, bfd_object, &obj_matching, ++ lto_sections_removed) ++ || (lto_sections_removed ++ && bfd_check_format_matches_lto (ibfd, bfd_object, ++ &obj_matching, false)) ++#else ++ bfd_check_format_matches_lto (ibfd, bfd_object, &obj_matching, ++ false) ++#endif ++ ) + { + bfd *obfd; + do_copy: +@@ -5036,9 +5052,13 @@ strip_main (int argc, char *argv[]) + #if BFD_SUPPORTS_PLUGINS + /* Check if all GCC LTO sections should be removed, assuming all LTO + sections will be removed with -R .gnu.lto_.*. * Remove .gnu.lto_.* +- sections will also remove .gnu.debuglto_. sections. */ +- lto_sections_removed = !!find_section_list (".gnu.lto_.*", false, +- SECTION_CONTEXT_REMOVE); ++ sections will also remove .gnu.debuglto_. sections. LLVM IR ++ bitcode is stored in .llvm.lto section which will be removed with ++ -R .llvm.lto. */ ++ lto_sections_removed = (!!find_section_list (".gnu.lto_.*", false, ++ SECTION_CONTEXT_REMOVE) ++ || !!find_section_list (".llvm.lto", false, ++ SECTION_CONTEXT_REMOVE)); + #endif + + i = optind; +diff --git a/binutils/testsuite/binutils-all/x86-64/pr33198.c b/binutils/testsuite/binutils-all/x86-64/pr33198.c +new file mode 100644 +index 00000000000..cd0130cacdf +--- /dev/null ++++ b/binutils/testsuite/binutils-all/x86-64/pr33198.c +@@ -0,0 +1,4 @@ ++void ++foo (void) ++{ ++} +diff --git a/binutils/testsuite/binutils-all/x86-64/x86-64.exp b/binutils/testsuite/binutils-all/x86-64/x86-64.exp +index 05c73047b60..ab1aa50a9a1 100644 +--- a/binutils/testsuite/binutils-all/x86-64/x86-64.exp ++++ b/binutils/testsuite/binutils-all/x86-64/x86-64.exp +@@ -96,3 +96,161 @@ if {[catch "system \"bzip2 -dc $t > $tempfile\""] != 0} { + } + } + } ++ ++proc run_pr33198_test { fat strip_flags } { ++ global srcdir ++ global subdir ++ global llvm_plug_opt ++ global AR ++ global CLANG_FOR_TARGET ++ global NM ++ global READELF ++ global STRIP ++ ++ set test pr33198 ++ set testname "${test}${fat} with $strip_flags" ++ ++ if { [istarget "x86_64-*-linux*-gnux32"] \ ++ || ![info exists CLANG_FOR_TARGET] ++ || [string match "" $llvm_plug_opt] } then { ++ untested $testname ++ return ++ } ++ ++ set src $srcdir/$subdir/${test}.c ++ set obj tmpdir/${test}${fat}.o ++ set archive tmpdir/${test}${fat}.a ++ set CLANG_CFLAGS "-c -O2 -flto" ++ if { "$fat" == "-fat" } { ++ append CLANG_CFLAGS " -ffat-lto-objects" ++ } ++ ++ append strip_flags " --strip-unneeded $llvm_plug_opt" ++ ++ set cmd "$CLANG_FOR_TARGET $CLANG_CFLAGS -o $obj $src" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![string match "" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname ($obj)" ++ return ++ } ++ ++ set cmd "$NM $llvm_plug_opt $obj\n" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![regexp "0+ T foo" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname ($obj)" ++ return ++ } ++ ++ pass "$testname ($obj)" ++ ++ set cmd "$STRIP $strip_flags $obj -o ${obj}.strip" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![string match "" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname (strip $obj)" ++ return ++ } ++ ++ set cmd "$NM $llvm_plug_opt ${obj}.strip" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![regexp "0+ T foo" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname (strip $obj)" ++ return ++ } ++ ++ if { "$fat" == "-fat" } { ++ set cmd "$READELF -SW ${obj}.strip" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if [regexp "\.llvm\.lto *LLVM_LTO *" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname (strip $obj)" ++ return ++ } ++ } ++ ++ pass "$testname (strip $obj)" ++ ++ set cmd "$AR $llvm_plug_opt -s -r -c $archive $obj" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![string match "" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname ($archive)" ++ return ++ } ++ ++ set cmd "$NM $llvm_plug_opt $archive\n" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![regexp "0+ T foo" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname ($archive)" ++ return ++ } ++ ++ pass "$testname ($archive)" ++ ++ set cmd "$STRIP $strip_flags $archive -o ${archive}.strip" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![string match "" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname (strip $archive)" ++ return ++ } ++ ++ set cmd "$NM $llvm_plug_opt ${archive}.strip" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if ![regexp "0+ T foo" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname (strip $archive)" ++ return ++ } ++ ++ if { "$fat" == "-fat" } { ++ set cmd "$READELF -SW ${archive}.strip" ++ send_log "$cmd\n" ++ verbose "$cmd" 1 ++ catch "exec $cmd" got ++ if [regexp "\.llvm\.lto *LLVM_LTO *" $got] then { ++ send_log "$got\n" ++ verbose "$got" 1 ++ fail "$testname (strip $archive)" ++ return ++ } ++ } ++ ++ pass "$testname (strip $archive)" ++} ++ ++run_pr33198_test "" "-R .gnu.lto_* -R .gnu.debuglto_* -R .llvm.lto -N __gnu_lto_v1" ++run_pr33198_test "-fat" "-R .gnu.lto_* -R .gnu.debuglto_* -R .llvm.lto -N __gnu_lto_v1" ++run_pr33198_test "" "-R .llvm.lto" ++run_pr33198_test "-fat" "-R .llvm.lto" +diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp +index b73b5558c27..d3a73337762 100644 +--- a/binutils/testsuite/lib/binutils-common.exp ++++ b/binutils/testsuite/lib/binutils-common.exp +@@ -1811,3 +1811,19 @@ proc get_standard_section_names {} { + } + return + } ++ ++set llvm_plug_opt "" ++if { [isnative] } then { ++ if ![info exists CLANG_FOR_TARGET] then { ++ catch "exec clang -v" got ++ if [regexp "clang version" $got] then { ++ set CLANG_FOR_TARGET clang ++ } ++ } ++ if [info exists CLANG_FOR_TARGET] then { ++ set llvm_plug_so [string trim [exec $CLANG_FOR_TARGET -print-file-name=LLVMgold.so]] ++ if { $llvm_plug_so ne "LLVMgold.so" } then { ++ set llvm_plug_opt "--plugin $llvm_plug_so" ++ } ++ } ++} +-- +2.50.1
