[binutils-gdb] strip: Treat slim GCC/LLVM IR objects the same

H.J. Lu hjl@sourceware.org
Fri Aug 15 01:15:26 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=9b383903e73cd01f2fbe9728d0c31fea765ba8d6

commit 9b383903e73cd01f2fbe9728d0c31fea765ba8d6
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Aug 12 12:02:08 2025 -0700

    strip: Treat slim GCC/LLVM IR objects the same
    
    Slim LLVM IR object is a standalone file whose first 4 bytes are 'B',
    'C', 0xc0, 0xde.  GCC IR object is regular ELF object with sections
    whose names start with .gnu.lto_.* or .gnu.debuglto_.*.  GCC IR object
    uses a .gnu.lto_.lto.<some_hash> section to encode the LTO bytecode
    information:
    
    struct lto_section
    {
      int16_t major_version;
      int16_t minor_version;
      unsigned char slim_object;
    
      /* Flags is a private field that is not defined publicly.  */
      uint16_t flags;
    };
    
    In slim GCC IR object, the slim_object field is non-zero.  Strip should
    treat slim GCC/LLVM IR objects the same.  Since strip won't change slim
    LLVM IR objects, it should leave slim GCC IR object unchanged even when
    asked to remove all IR objects:
    
    1. Set the lto_type field to lto_slim_ir_object for slim LLVM IR object.
    2. Always copy slim IR object as unknown object.
    
    bfd/
    
            PR binutils/33271
            * format.c (bfd_set_lto_type): Set the lto_type field to
            lto_slim_ir_object for slim LLVM IR object.
    
    binutils/
    
            PR binutils/33271
            * objcopy.c (lto_sections_removed): Removed.
            (copy_archive): Always copy slim IR object as unknown object.
            (copy_file): Likewise.
            (strip_main): Updated.
    
    ld/
    
            PR binutils/33271
            * testsuite/ld-plugin/lto-binutils.exp: Don't check if fat IR is
            available when running slim IR tests.
            * testsuite/ld-plugin/strip-1a-s-all.nd: Expect full symbol list.
    
    Signed-off-by: H.J. Lu <hjl.tools@gmail.com>

Diff:
---
 bfd/format.c                             | 66 ++++++++++++++++++++------------
 binutils/objcopy.c                       | 32 +++++-----------
 ld/testsuite/ld-plugin/lto-binutils.exp  | 34 ++++++++--------
 ld/testsuite/ld-plugin/strip-1a-s-all.nd |  5 ++-
 4 files changed, 70 insertions(+), 67 deletions(-)

diff --git a/bfd/format.c b/bfd/format.c
index 25feb5266df..b74c6240f23 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -376,33 +376,49 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
 	     | (bfd_get_flavour (abfd) == bfd_target_elf_flavour
 		? EXEC_P : 0))) == 0)
     {
-      asection *sec;
+      asection *sec = abfd->sections;
       enum bfd_lto_object_type type = lto_non_ir_object;
-      struct lto_section lsection = { 0, 0, 0, 0 };
-      /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
-	 section.  */
-      for (sec = abfd->sections; sec != NULL; sec = sec->next)
-	if (strcmp (sec->name, GNU_OBJECT_ONLY_SECTION_NAME) == 0)
-	  {
-	    type = lto_mixed_object;
-	    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,
-					      sizeof (struct lto_section)))
-	  {
-	    if (lsection.slim_object)
-	      type = lto_slim_ir_object;
-	    else
-	      type = lto_fat_ir_object;
+      if (sec == NULL)
+	{
+	  /* If there are no sections, check for slim LLVM IR object whose
+	     first 4 bytes are: 'B', 'C', 0xc0, 0xde.  */
+	  bfd_byte llvm_ir_magic[4];
+	  if (bfd_seek (abfd, 0, SEEK_SET) == 0
+	      && bfd_read (llvm_ir_magic, 4, abfd) == 4
+	      && llvm_ir_magic[0] == 'B'
+	      && llvm_ir_magic[1] == 'C'
+	      && llvm_ir_magic[2] == 0xc0
+	      && llvm_ir_magic[3] == 0xde)
+	    type = lto_slim_ir_object;
+	}
+      else
+	{
+	  struct lto_section lsection = { 0, 0, 0, 0 };
+	  /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode
+	     information section.  */
+	  for (; sec != NULL; sec = sec->next)
+	    if (strcmp (sec->name, GNU_OBJECT_ONLY_SECTION_NAME) == 0)
+	      {
+		type = lto_mixed_object;
+		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,
+						  sizeof (struct lto_section)))
+	      {
+		if (lsection.slim_object)
+		  type = lto_slim_ir_object;
+		else
+		  type = lto_fat_ir_object;
 	  }
+	}
 
       abfd->lto_type = type;
     }
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index bc07176799a..6d6df024ec6 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -168,13 +168,6 @@ static struct section_list *change_sections;
 /* TRUE if some sections are to be removed.  */
 static bool sections_removed;
 
-#if BFD_SUPPORTS_PLUGINS
-/* TRUE if all GCC LTO sections are to be removed.  */
-static bool lto_sections_removed;
-#else
-#define lto_sections_removed false
-#endif
-
 /* TRUE if only some sections are to be copied.  */
 static bool sections_copied;
 
@@ -3765,9 +3758,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
 	}
 
 #if BFD_SUPPORTS_PLUGINS
-      /* Copy LTO IR file as unknown object.  */
-      if (!lto_sections_removed
-	  && this_element->lto_type == lto_slim_ir_object)
+      /* Copy slim LTO IR file as unknown object.  */
+      if (this_element->lto_type == lto_slim_ir_object)
 	ok_object = false;
 #endif
       if (ok_object)
@@ -4066,9 +4058,8 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
  	}
 
 #if BFD_SUPPORTS_PLUGINS
-      /* Copy LTO IR file as unknown object.  */
-      if (!lto_sections_removed
-	  && ibfd->lto_type == lto_slim_ir_object)
+  /* Copy slim LTO IR file as unknown file.  */
+      if (ibfd->lto_type == lto_slim_ir_object)
 	ok_object = false;
 #endif
       if (ok_object
@@ -5062,18 +5053,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.  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));
-  /* NB: Must keep .gnu.debuglto_* sections unless all GCC LTO sections
+     sections will be removed with -R .gnu.lto_.*.  Remove .gnu.lto_.*
+     sections will also remove .gnu.debuglto_.* sections.
+
+     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)
+  if (!find_section_list (".gnu.lto_.*", false, SECTION_CONTEXT_REMOVE))
     find_section_list (".gnu.debuglto_*", true, SECTION_CONTEXT_KEEP);
 #endif
 
diff --git a/ld/testsuite/ld-plugin/lto-binutils.exp b/ld/testsuite/ld-plugin/lto-binutils.exp
index 4970e2282cb..1e156e4fc78 100644
--- a/ld/testsuite/ld-plugin/lto-binutils.exp
+++ b/ld/testsuite/ld-plugin/lto-binutils.exp
@@ -254,24 +254,22 @@ run_lto_binutils_test [list \
     ] \
 ]
 
-if { [check_lto_fat_available] } {
-    run_lto_binutils_test [list \
-	[list \
-	    "strip" \
-	    "-R .gnu.*lto_* -N __gnu_lto_v1" \
-	    "strip-1a.o" \
-	    "strip-1a-s-all.o" \
-	    {{nm -n strip-1a-s-all.nd}} \
-	] \
-	[list \
-	    "strip" \
-	    "-R .gnu.*lto_* -N __gnu_lto_v1" \
-	    "libstrip-1a.a" \
-	    "libstrip-1a-s-all.a" \
-	    {{nm -n strip-1a-s-all.nd}} \
-	] \
-    ]
-}
+run_lto_binutils_test [list \
+    [list \
+	"strip" \
+	"-R .gnu.*lto_* -N __gnu_lto_v1" \
+	"strip-1a.o" \
+	"strip-1a-s-all.o" \
+	{{nm -n strip-1a-s-all.nd}} \
+    ] \
+    [list \
+	"strip" \
+	"-R .gnu.*lto_* -N __gnu_lto_v1" \
+	"libstrip-1a.a" \
+	"libstrip-1a-s-all.a" \
+	{{nm -n strip-1a-s-all.nd}} \
+    ] \
+]
 
 run_cc_link_tests [list \
     [list \
diff --git a/ld/testsuite/ld-plugin/strip-1a-s-all.nd b/ld/testsuite/ld-plugin/strip-1a-s-all.nd
index 612ba6a39b1..52265c2eb3d 100644
--- a/ld/testsuite/ld-plugin/strip-1a-s-all.nd
+++ b/ld/testsuite/ld-plugin/strip-1a-s-all.nd
@@ -1,3 +1,6 @@
 #...
-[0-9a-f]* C _?__gnu_lto_slim
+ + U foo2
+ + U foo3
+0+ T foo1
+0+ T main
 #pass


More information about the Binutils-cvs mailing list