[v2] Don't claim a fat IR object if no IR object should be claimed

Message ID 20240326133340.2979066-1-hjl.tools@gmail.com
State Committed
Headers
Series [v2] Don't claim a fat IR object if no IR object should be claimed |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

H.J. Lu March 26, 2024, 1:33 p.m. UTC
  Changes in v2:

1. Rename lto_ir_object to lto_slim_ir_object and add comments.
2. Add bfd_get_lto_type.
3. Remove lto_slim_object.
4. Change bfd_set_lto_type to set lto_type based on LTO bytecode
information.
5. Change the lto_slim_object check to bfd_get_lto_type (abfd).

---
When the linker sees an input object containing nothing but IR during
rescan, it should ignore it (LTO phase is over).  But if the input object
is a fat IR object, which has non-IR code as well, it should be used to
resolve references as if it did not contain any IR at all.  This patch
adds lto_type to bfd and linker avoids claiming a fat IR object if no IR
object should be claimed.

bfd/

	PR ld/23935
	* archive.c (_bfd_compute_and_write_armap): Check bfd_get_lto_type
	instead of lto_slim_object.
	* elflink.c (elf_link_add_object_symbols): Likewise.
	* bfd.c (bfd_lto_object_type): New.
	(bfd): Remove lto_slim_object and add lto_type.
	(bfd_get_lto_type): New function.
	* elf.c (lto_section): Removed.
	(_bfd_elf_make_section_from_shdr): Don't set lto_slim_object.
	* format.c: (lto_section): New.
	(bfd_set_lto_type): New function.
	(bfd_check_format_matches): Call bfd_set_lto_type.
	* bfd-in2.h: Regenerated.

binutils/

	PR ld/23935
	* nm.c (display_rel_file): Check bfd_get_lto_type instead of
	lto_slim_object.

ld/

	PR ld/23935
	* ldmain.c (add_archive_element): Don't claim a fat IR object if
	no IR object should be claimed.
	* testsuite/ld-plugin/lto.exp (pr20103): Adjust fat IR test.
	Add PR ld/23935 test.
	* testsuite/ld-plugin/pr23935a.c: New file.
	* testsuite/ld-plugin/pr23935b.c: Likewise.
---
 bfd/archive.c                     |  3 +-
 bfd/bfd-in2.h                     | 20 ++++++++++--
 bfd/bfd.c                         | 20 ++++++++++--
 bfd/elf.c                         | 22 -------------
 bfd/elflink.c                     |  2 +-
 bfd/format.c                      | 51 ++++++++++++++++++++++++++++++-
 binutils/nm.c                     |  6 ++--
 ld/ldmain.c                       |  5 ++-
 ld/testsuite/ld-plugin/lto.exp    | 35 +++++++++++++++++++--
 ld/testsuite/ld-plugin/pr23935a.c |  2 ++
 ld/testsuite/ld-plugin/pr23935b.c |  2 ++
 11 files changed, 131 insertions(+), 37 deletions(-)
 create mode 100644 ld/testsuite/ld-plugin/pr23935a.c
 create mode 100644 ld/testsuite/ld-plugin/pr23935b.c
  

Comments

Nick Clifton March 26, 2024, 2:07 p.m. UTC | #1
Hi H.J.

> Changes in v2:
> 
> 1. Rename lto_ir_object to lto_slim_ir_object and add comments.
> 2. Add bfd_get_lto_type.
> 3. Remove lto_slim_object.
> 4. Change bfd_set_lto_type to set lto_type based on LTO bytecode
> information.
> 5. Change the lto_slim_object check to bfd_get_lto_type (abfd).


Looks good to me.  Thanks for making the changes.  Patch approved, please apply.
Cheers
   Nick
  
Nick Clifton April 3, 2024, 4:05 p.m. UTC | #2
Hi H.J.

> Changes in v2:
> 
> 1. Rename lto_ir_object to lto_slim_ir_object and add comments.
> 2. Add bfd_get_lto_type.
> 3. Remove lto_slim_object.
> 4. Change bfd_set_lto_type to set lto_type based on LTO bytecode
> information.
> 5. Change the lto_slim_object check to bfd_get_lto_type (abfd).

Approved - please apply.

Cheers
   Nick
  

Patch

diff --git a/bfd/archive.c b/bfd/archive.c
index 9f3fbce9bc9..ad7673971a3 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -2355,7 +2355,8 @@  _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
 	  long symcount;
 	  long src_count;
 
-	  if (current->lto_slim_object && report_plugin_err)
+	  if (bfd_get_lto_type (current) == lto_slim_ir_object
+	      && report_plugin_err)
 	    {
 	      report_plugin_err = false;
 	      _bfd_error_handler
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 1166ddd75ef..b332f5adad1 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1954,6 +1954,14 @@  struct bfd_build_id
     bfd_byte data[1];
   };
 
+enum bfd_lto_object_type
+  {
+    lto_non_object,            /* Not an LTO object.  */
+    lto_non_ir_object,         /* An object without LTO IR.  */
+    lto_slim_ir_object,        /* A slim LTO IR object.  */
+    lto_fat_ir_object          /* A fat LTO IR object.  */
+  };
+
 struct bfd
 {
   /* The filename the application opened the BFD with.  */
@@ -2155,13 +2163,13 @@  struct bfd
   /* Set if this is a plugin output file.  */
   unsigned int lto_output : 1;
 
-  /* Set if this is a slim LTO object not loaded with a compiler plugin.  */
-  unsigned int lto_slim_object : 1;
-
   /* Do not attempt to modify this file.  Set when detecting errors
      that BFD is not prepared to handle for objcopy/strip.  */
   unsigned int read_only : 1;
 
+  /* LTO object type.  */
+  ENUM_BITFIELD (bfd_lto_object_type) lto_type : 2;
+
   /* Set to dummy BFD created when claimed by a compiler plug-in
      library.  */
   bfd *plugin_dummy_bfd;
@@ -2303,6 +2311,12 @@  bfd_get_format (const bfd *abfd)
   return abfd->format;
 }
 
+static inline enum bfd_lto_object_type
+bfd_get_lto_type (const bfd *abfd)
+{
+  return abfd->lto_type;
+}
+
 static inline flagword
 bfd_get_file_flags (const bfd *abfd)
 {
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 54061a34240..e579788e42f 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -74,6 +74,14 @@  EXTERNAL
 .    bfd_byte data[1];
 .  };
 .
+.enum bfd_lto_object_type
+.  {
+.    lto_non_object,		{* Not an LTO object.  *}
+.    lto_non_ir_object,		{* An object without LTO IR.  *}
+.    lto_slim_ir_object,	{* A slim LTO IR object.  *}
+.    lto_fat_ir_object		{* A fat LTO IR object.  *}
+.  };
+.
 
 CODE_FRAGMENT
 .struct bfd
@@ -278,13 +286,13 @@  CODE_FRAGMENT
 .  {* Set if this is a plugin output file.  *}
 .  unsigned int lto_output : 1;
 .
-.  {* Set if this is a slim LTO object not loaded with a compiler plugin.  *}
-.  unsigned int lto_slim_object : 1;
-.
 .  {* Do not attempt to modify this file.  Set when detecting errors
 .     that BFD is not prepared to handle for objcopy/strip.  *}
 .  unsigned int read_only : 1;
 .
+.  {* LTO object type.  *}
+.  ENUM_BITFIELD (bfd_lto_object_type) lto_type : 2;
+.
 .  {* Set to dummy BFD created when claimed by a compiler plug-in
 .     library.  *}
 .  bfd *plugin_dummy_bfd;
@@ -428,6 +436,12 @@  EXTERNAL
 .  return abfd->format;
 .}
 .
+.static inline enum bfd_lto_object_type
+.bfd_get_lto_type (const bfd *abfd)
+.{
+.  return abfd->lto_type;
+.}
+.
 .static inline flagword
 .bfd_get_file_flags (const bfd *abfd)
 .{
diff --git a/bfd/elf.c b/bfd/elf.c
index 8bffd3c5141..f7717547fad 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -970,18 +970,6 @@  bfd_elf_group_name (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
   return NULL;
 }
 
-/* This a copy of lto_section defined in GCC (lto-streamer.h).  */
-
-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;
-};
-
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -1261,16 +1249,6 @@  _bfd_elf_make_section_from_shdr (bfd *abfd,
 	}
     }
 
-  /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
-     section.  */
-  if (startswith (name, ".gnu.lto_.lto."))
-    {
-      struct lto_section lsection;
-      if (bfd_get_section_contents (abfd, newsect, &lsection, 0,
-				    sizeof (struct lto_section)))
-	abfd->lto_slim_object = lsection.slim_object;
-    }
-
   return true;
 }
 
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 5a6cb07b2ce..24eb30d1946 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -4785,7 +4785,7 @@  elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
     }
 
   if (!bfd_link_relocatable (info)
-      && abfd->lto_slim_object)
+      && bfd_get_lto_type (abfd) == lto_slim_ir_object)
     {
       _bfd_error_handler
 	(_("%pB: plugin needed to handle lto object"), abfd);
diff --git a/bfd/format.c b/bfd/format.c
index 8f3fc7e7b96..6d95683acb5 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -278,6 +278,50 @@  null_error_handler (const char *fmt ATTRIBUTE_UNUSED,
 {
 }
 
+/* This a copy of lto_section defined in GCC (lto-streamer.h).  */
+
+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;
+};
+
+/* Set lto_type in ABFD.  */
+
+static void
+bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
+{
+#if BFD_SUPPORTS_PLUGINS
+  if (abfd->format == bfd_object
+      && abfd->lto_type == lto_non_object
+      && (abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+    {
+      asection *sec;
+      enum bfd_lto_object_type type = lto_non_ir_object;
+      struct lto_section lsection;
+      /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
+	 section.  */
+      for (sec = abfd->sections; sec != NULL; sec = sec->next)
+	if (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;
+	    break;
+	  }
+
+      abfd->lto_type = type;
+    }
+#endif
+}
+
 /*
 FUNCTION
 	bfd_check_format_matches
@@ -327,7 +371,10 @@  bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
     }
 
   if (abfd->format != bfd_unknown)
-    return abfd->format == format;
+    {
+      bfd_set_lto_type (abfd);
+      return abfd->format == format;
+    }
 
   if (matching != NULL || *bfd_associated_vector != NULL)
     {
@@ -601,6 +648,8 @@  bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
 	clear_warnmsg (list++);
       --in_check_format;
 
+      bfd_set_lto_type (abfd);
+
       /* File position has moved, BTW.  */
       return true;
     }
diff --git a/binutils/nm.c b/binutils/nm.c
index a8e915bc0b4..faf27c59b4d 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -1466,9 +1466,9 @@  display_rel_file (bfd *abfd, bfd *archive_bfd)
 	free (dyn_syms);
     }
 
-  /* lto_slim_object is set to false when a bfd is loaded with a compiler
-     LTO plugin.  */
-  if (abfd->lto_slim_object)
+  /* 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)
     {
       report_plugin_err = false;
       non_fatal (_("%s: plugin needed to handle lto object"),
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 9ae541a5d82..fe389681bd3 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -902,7 +902,10 @@  add_archive_element (struct bfd_link_info *info,
      BFD, but we still want to output the original BFD filename.  */
   orig_input = *input;
 #if BFD_SUPPORTS_PLUGINS
-  if (link_info.lto_plugin_active)
+  /* Don't claim a fat IR object if no IR object should be claimed.  */
+  if (link_info.lto_plugin_active
+      && (!no_more_claiming
+	  || bfd_get_lto_type (abfd) != lto_fat_ir_object))
     {
       /* We must offer this archive member to the plugins to claim.  */
       plugin_maybe_claim (input);
diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp
index cf1691fec6d..259a0643cc7 100644
--- a/ld/testsuite/ld-plugin/lto.exp
+++ b/ld/testsuite/ld-plugin/lto.exp
@@ -964,10 +964,20 @@  proc pr20103 {cflags libs} {
 
     set testname "PR ld/20103 ($cflags $libs)"
     set exec_output [run_host_cmd "$CC_FOR_TARGET" "$cflags $libs"]
+    # NB: Starting from GCC 4.9, -flto is optional for final link.
+    if { [ regexp "fatpr20103" "$libs" ] \
+	 && ([regexp " -flto" "$cflags"] \
+	     || [at_least_gcc_version 4 9]) } {
+	set result1good "fail"
+	set result1bad "pass"
+    } {
+	set result1good "pass"
+	set result1bad "fail"
+    }
     if { [ regexp "undefined reference to `\\.?dead'" $exec_output ] } {
-        pass "$testname (1)"
+	$result1good "$testname (1)"
     } {
-        fail "$testname (1)"
+	$result1bad "$testname (1)"
     }
     if { [ regexp "plugin needed to handle lto object" $exec_output ] } {
         fail "$testname (2)"
@@ -1026,6 +1036,27 @@  if { [check_lto_fat_available] } {
 	    "-O2" \
 	    {dummy.c} {} "pr20103c" \
 	] \
+	[list "Build fatpr23935.a" \
+	    "$plug_opt" \
+	    "-flto -fno-builtin -ffat-lto-objects" \
+	    {pr23935a.c} \
+	    "" \
+	    "fatpr23935.a" \
+	] \
+	[list "Build pr23935b.o" \
+	    "$plug_opt" \
+	    "-flto -fno-fat-lto-objects" \
+	    {pr23935b.c} \
+	] \
+	[list \
+	    "Build pr23935" \
+	    "-static -flto -Wl,-emain -nostdlib tmpdir/pr23935b.o \
+	     tmpdir/fatpr23935.a" \
+	    "-flto -fno-fat-lto-objects" \
+	    {dummy.c} \
+	    "" \
+	    "pr23935" \
+	] \
     ]
     pr20103 "-O2 -flto" "tmpdir/thinpr20103a.a tmpdir/thinpr20103b.a tmpdir/thinpr20103c.a"
     pr20103 "-O2 -flto" "tmpdir/fatpr20103a.a tmpdir/fatpr20103b.a tmpdir/fatpr20103c.a"
diff --git a/ld/testsuite/ld-plugin/pr23935a.c b/ld/testsuite/ld-plugin/pr23935a.c
new file mode 100644
index 00000000000..8c731977f41
--- /dev/null
+++ b/ld/testsuite/ld-plugin/pr23935a.c
@@ -0,0 +1,2 @@ 
+#include <stdio.h>
+int puts(const char *s) { return 0; }
diff --git a/ld/testsuite/ld-plugin/pr23935b.c b/ld/testsuite/ld-plugin/pr23935b.c
new file mode 100644
index 00000000000..58ae07e8698
--- /dev/null
+++ b/ld/testsuite/ld-plugin/pr23935b.c
@@ -0,0 +1,2 @@ 
+#include <stdio.h>
+int main() { printf("hi\n"); return 0; }