]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
strip: Don't treat fat IR objects as plugin object
authorH.J. Lu <hjl.tools@gmail.com>
Sun, 3 Aug 2025 17:28:40 +0000 (10:28 -0700)
committerSam James <sam@gentoo.org>
Mon, 1 Sep 2025 09:08:08 +0000 (10:08 +0100)
Fat IR objects contains both regular sections and IR sections.  After

commit 717a38e9a02109fcbcb18bb2ec3aa251e2ad0a0d
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sun May 4 05:12:46 2025 +0800

    strip: Add GCC LTO IR support

"strip --strip-debug" no longer strips debug sections in fat IR objects
since fat IR objects are recognized as plugin object and copied as unknown
objects.  Add a is_strip_input field to bfd to indicate called from strip.
Update bfd_check_format_matches not to treat archive member nor standalone
fat IR object as IR object so that strip can remove debug and IR sections
in fat IR object.  For archive member, it is copied as an unknown object
if the plugin target is in use or it is a slim IR object.  For standalone
fat IR object, it is copied as non-IR object.

bfd/

PR binutils/33246
* archive.c: Include "plugin-api.h" and "plugin.h" if plugin is
enabled.
(_bfd_compute_and_write_armap): Don't complain plugin is needed
when the plugin target is in use.
* bfd-in2.h: Regenerated.
* bfd.c (bfd): Add is_strip_input.
* format.c (bfd_set_lto_type): If there is .llvm.lto section,
set LTO type to lto_fat_ir_object.
(bfd_check_format_matches): Don't set LTO type when setting
format.  When called from strip, don't treat archive member nor
standalone fat IR object as an IR object.
* plugin.c (bfd_plugin_get_symbols_in_object_only): Copy LTO
type derived from input sections.

nm/

PR binutils/33246
* nm.c (filter_symbols): Don't complain plugin is needed when
the plugin target is in use.
(display_rel_file): Likewise.
* objcopy.c (copy_archive): Set the BFD is_strip_input field of
archive member to 1 to indicate called from strip.  Also copy
slim IR archive member as unknown object.
(copy_file): Set the BFD is_strip_input field of input bfd to
1 to indicate called from strip.
(strip_main): Keep .gnu.debuglto_* sections unless all GCC LTO
sections will be removed.

ld/

PR binutils/33246
* testsuite/ld-plugin/lto-binutils.exp (run_pr33246_test): New.
Run binutils/33246 tests with GCC and Clang.
* testsuite/ld-plugin/pr33246.c: New file.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit c2729c37f10af09126b2916215cae425ae724f55)

bfd/archive.c
bfd/bfd-in2.h
bfd/bfd.c
bfd/format.c
bfd/plugin.c
binutils/nm.c
binutils/objcopy.c
ld/testsuite/ld-plugin/lto-binutils.exp
ld/testsuite/ld-plugin/pr33246.c [new file with mode: 0644]

index c61d4b126586981b3ebd1d720ef330c109410a1e..697b2ed23f2183fa8a2d01c3a8f63bb7b94f696d 100644 (file)
@@ -141,6 +141,10 @@ SUBSECTION
 #include "hashtab.h"
 #include "filenames.h"
 #include "bfdlink.h"
+#if BFD_SUPPORTS_PLUGINS
+#include "plugin-api.h"
+#include "plugin.h"
+#endif
 
 #ifndef errno
 extern int errno;
@@ -2343,6 +2347,9 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
          long src_count;
 
          if (bfd_get_lto_type (current) == lto_slim_ir_object
+#if BFD_SUPPORTS_PLUGINS
+             && !bfd_plugin_target_p (current->xvec)
+#endif
              && report_plugin_err)
            {
              report_plugin_err = false;
@@ -2400,6 +2407,9 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
 
                      if (bfd_lto_slim_symbol_p (current,
                                                 syms[src_count]->name)
+#if BFD_SUPPORTS_PLUGINS
+                         && !bfd_plugin_target_p (current->xvec)
+#endif
                          && report_plugin_err)
                        {
                          report_plugin_err = false;
index 2ff3e930bfa2fb441aa68bc81618747a576571a2..bcff44a0f44782ccf3698ca896cf8bafb4babf50 100644 (file)
@@ -2131,6 +2131,9 @@ struct bfd
   /* Set if this is the linker input BFD.  */
   unsigned int is_linker_input : 1;
 
+  /* Set if this is the strip input BFD.  */
+  unsigned int is_strip_input : 1;
+
   /* If this is an input for a compiler plug-in library.  */
   ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
 
index 858ab5ce017911d585e2718d1dfa7ccd1df2be89..4aded6809bb60f08fe73a224cb9eea89b7daf98b 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -296,6 +296,9 @@ CODE_FRAGMENT
 .  {* Set if this is the linker input BFD.  *}
 .  unsigned int is_linker_input : 1;
 .
+.  {* Set if this is the strip input BFD.  *}
+.  unsigned int is_strip_input : 1;
+.
 .  {* If this is an input for a compiler plug-in library.  *}
 .  ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
 .
index f3a0774af081ce445eeea1788b8cb97774a6dd46..246838c7ab501deeab7a460e2d6841ec0ab3671f 100644 (file)
@@ -413,6 +413,11 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
            abfd->object_only_section = sec;
            break;
          }
+       else if (strcmp (sec->name, ".llvm.lto") == 0)
+         {
+           type = lto_fat_ir_object;
+           break;
+         }
        else if (lsection.major_version == 0
                 && startswith (sec->name, ".gnu.lto_.lto.")
                 && bfd_get_section_contents (abfd, sec, &lsection, 0,
@@ -481,10 +486,7 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
     }
 
   if (abfd->format != bfd_unknown)
-    {
-      bfd_set_lto_type (abfd);
-      return abfd->format == format;
-    }
+    return abfd->format == format;
 
   if (matching != NULL || *bfd_associated_vector != NULL)
     {
@@ -537,7 +539,20 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
 
       cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
 
-      if (cleanup)
+      /* When called from strip, don't treat archive member nor
+        standalone fat IR object as an IR object.  For archive
+        member, it will be copied as an unknown object if the
+        plugin target is in use or it is a slim IR object.  For
+        standalone fat IR object, it will be copied as non-IR
+        object.  */
+      if (cleanup
+#if BFD_SUPPORTS_PLUGINS
+         && (!abfd->is_strip_input
+             || !bfd_plugin_target_p (abfd->xvec)
+             || (abfd->lto_type != lto_fat_ir_object
+                 && abfd->my_archive == NULL))
+#endif
+         )
        goto ok_ret;
 
       /* For a long time the code has dropped through to check all
index 1c72b748a8fa639348aa665dbb3b0995d53a4d05..6dd22d7513731dd0b5e05f326301d2149d13b0a4 100644 (file)
@@ -203,6 +203,9 @@ bfd_plugin_get_symbols_in_object_only (bfd *abfd)
          bfd_close (nbfd);
          return;
        }
+
+      /* Copy LTO type derived from input sections.  */
+      abfd->lto_type = nbfd->lto_type;
     }
   else
     {
index a5d56311ddedd1c35d07c1feb77b219a3a811afc..d44083dcc948c855fca2401c464d93659aa1375b 100644 (file)
@@ -802,6 +802,9 @@ filter_symbols (bfd *abfd, bool is_dynamic, void *minisyms,
        continue;
 
       if (bfd_lto_slim_symbol_p (abfd, sym->name)
+#if BFD_SUPPORTS_PLUGINS
+         && !bfd_plugin_target_p (abfd->xvec)
+#endif
          && report_plugin_err)
        {
          report_plugin_err = false;
@@ -1484,7 +1487,11 @@ display_rel_file (bfd *abfd, bfd *archive_bfd)
 
   /* lto_type is set to lto_non_ir_object when a bfd is loaded with a
      compiler LTO plugin.  */
-  if (bfd_get_lto_type (abfd) == lto_slim_ir_object)
+  if (bfd_get_lto_type (abfd) == lto_slim_ir_object
+#if BFD_SUPPORTS_PLUGINS
+      && !bfd_plugin_target_p (abfd->xvec)
+#endif
+     )
     {
       report_plugin_err = false;
       non_fatal (_("%s: plugin needed to handle lto object"),
index 5774711abe63f5d6a5450241005c8bfa9aabe5c1..a569025705909ec279a03310c13bed2dd885b5fc 100644 (file)
@@ -3687,6 +3687,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
       bool ok_object;
       const char *element_name;
 
+      this_element->is_strip_input = 1;
+
       element_name = bfd_get_filename (this_element);
       /* PR binutils/17533: Do not allow directory traversal
         outside of the current directory tree by archive members.  */
@@ -3768,7 +3770,9 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
 
 #if BFD_SUPPORTS_PLUGINS
       /* Copy LTO IR file as unknown object.  */
-      if (bfd_plugin_target_p (this_element->xvec))
+      if ((!lto_sections_removed
+          && this_element->lto_type == lto_slim_ir_object)
+         || bfd_plugin_target_p (this_element->xvec))
        ok_object = false;
       else
 #endif
@@ -3946,6 +3950,8 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
       break;
     }
 
+  ibfd->is_strip_input = 1;
+
   if (bfd_check_format (ibfd, bfd_archive))
     {
       bool force_output_target;
@@ -5066,6 +5072,11 @@ strip_main (int argc, char *argv[])
                                               SECTION_CONTEXT_REMOVE)
                          || !!find_section_list (".llvm.lto", false,
                                               SECTION_CONTEXT_REMOVE));
+  /* NB: Must keep .gnu.debuglto_* sections unless all GCC LTO sections
+     will be removed to avoid undefined references to symbols in GCC LTO
+     debug sections.  */
+  if (!lto_sections_removed)
+    find_section_list (".gnu.debuglto_*", true, SECTION_CONTEXT_KEEP);
 #endif
 
   i = optind;
index 5b4e0a10991810b3fdec770b0015c6f3203c4acc..51332696d5b65d9051f08e2165899e8ad1329b5f 100644 (file)
@@ -356,3 +356,178 @@ run_cc_link_tests [list \
        "tmpdir/libstrip-1b-fat-s.a" \
     ] \
 ]
+
+proc run_pr33246_test { llvm fat } {
+    global srcdir
+    global subdir
+    global plug_opt
+    global llvm_plug_opt
+    global ar
+    global CLANG_FOR_TARGET
+    global CC_FOR_TARGET
+    global NM
+    global READELF
+    global strip
+
+    set strip_flags "--strip-debug --enable-deterministic-archives"
+
+    set test pr33246
+    set testname "${test}${llvm}${fat} with $strip_flags"
+
+    if { "$llvm" == "-llvm" } {
+       # Skip native x32 and i?86 targets since system LLVMgold.so may
+       # not be compatible with native x32 and i?86 targets binutils.
+       if { [istarget "x86_64-*-linux*-gnux32"]
+            || [istarget "i?86-*-*"]
+            || ![info exists CLANG_FOR_TARGET]
+            || [string match "" $llvm_plug_opt] } then {
+           untested $testname
+           return
+       }
+       set CC $CLANG_FOR_TARGET
+       set binutils_plug_opt "$llvm_plug_opt"
+    } else {
+       if { ![info exists CC_FOR_TARGET]
+            || [string match "" $plug_opt] } then {
+           untested $testname
+           return
+       }
+       set CC $CC_FOR_TARGET
+       set binutils_plug_opt "$plug_opt"
+    }
+
+    append strip_flags " $binutils_plug_opt"
+
+    set src $srcdir/$subdir/${test}.c
+    set obj tmpdir/${test}${llvm}${fat}.o
+    set archive tmpdir/${test}${llvm}${fat}.a
+    set CFLAGS "-c -g -O2 -flto"
+    if { "$fat" == "-fat" } {
+       append CFLAGS " -ffat-lto-objects"
+    } else {
+       append CFLAGS " -fno-fat-lto-objects"
+    }
+
+    set cmd "$CC $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 "$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 $binutils_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 " \.debug_" $got] then {
+           send_log "$got\n"
+           verbose "$got" 1
+           fail "$testname (strip $obj)"
+           return
+       }
+    } else {
+       set cmd "cmp $obj ${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
+       }
+    }
+
+    pass "$testname (strip $obj)"
+
+    set cmd "$ar $binutils_plug_opt -D -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 "$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 $binutils_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 " \.debug_" $got] then {
+           send_log "$got\n"
+           verbose "$got" 1
+           fail "$testname (strip $archive)"
+           return
+       }
+    } else {
+       set cmd "cmp $archive ${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
+       }
+    }
+
+    pass "$testname (strip $archive)"
+}
+
+run_pr33246_test "" ""
+run_pr33246_test "" "-fat"
+run_pr33246_test "-llvm" ""
+run_pr33246_test "-llvm" "-fat"
diff --git a/ld/testsuite/ld-plugin/pr33246.c b/ld/testsuite/ld-plugin/pr33246.c
new file mode 100644 (file)
index 0000000..cd0130c
--- /dev/null
@@ -0,0 +1,4 @@
+void
+foo (void)
+{
+}