Support .gnu.lto_.lto section in ELF files (PR 24768).

Message ID 2ea791b1-6f58-70e5-a330-0b89c58050b9@suse.cz
State New
Headers show
Series
  • Support .gnu.lto_.lto section in ELF files (PR 24768).
Related show

Commit Message

Martin Liška July 22, 2019, 2:01 p.m.
Hi.

The patch adds detection of a new LTO ELF section that will eventually
replace presence of the __gnu_lto_slim symbol detection. So, first I would
like to teach binutils about the section and later then (after some years),
detection based on __gnu_lto_slim symbol can be removed.

Ready for trunk?
Thanks,
Martin

bfd/ChangeLog:

2019-07-22  Martin Liska  <mliska@suse.cz>

	PR 24768
	* archive.c (_bfd_compute_and_write_armap): Come up with
	report_plugin_err variable.
	* bfd-in2.h (struct bfd): Add lto_slim_object flag.
	* elf.c (struct lto_section): New.
	(_bfd_elf_make_section_from_shdr): Parse content of
	.gnu_lto_.lto section.
	* elflink.c: Report error for a missing LTO plugin.
	* linker.c (_bfd_generic_link_add_one_symbol): Likewise.

binutils/ChangeLog:

2019-07-22  Martin Liska  <mliska@suse.cz>

	PR 24768
	* nm.c (filter_symbols): Set report_plugin_err if
	error is reported.
	(display_rel_file): Report error for a missing LTO plugin.

gold/ChangeLog:

2019-07-22  Martin Liska  <mliska@suse.cz>

	PR 24768
	* layout.h (class Layout): Add is_lto_slim_object and
	set_lto_slim_object.
	* object.cc (struct lto_section): Add lto_slim_object_.
	(big_endian>::do_layout): Parse content of
	.gnu_lto_.lto section.
	(big_endian>::do_add_symbols): Report error for a missing
	LTO plugin.
---
 bfd/archive.c  | 21 +++++++++++++++++----
 bfd/bfd-in2.h  |  3 +++
 bfd/elf.c      | 23 +++++++++++++++++++++++
 bfd/elflink.c  |  6 ++++++
 bfd/linker.c   | 24 ++++++++++++++++++------
 binutils/nm.c  | 23 ++++++++++++++++++++---
 gold/layout.h  | 10 ++++++++++
 gold/object.cc | 31 ++++++++++++++++++++++++++++++-
 8 files changed, 127 insertions(+), 14 deletions(-)

Comments

Nick Clifton July 25, 2019, 1:56 p.m. | #1
Hi Martin,

> bfd/ChangeLog:

> 2019-07-22  Martin Liska  <mliska@suse.cz>

> 

> 	PR 24768

> 	* archive.c (_bfd_compute_and_write_armap): Come up with

> 	report_plugin_err variable.

> 	* bfd-in2.h (struct bfd): Add lto_slim_object flag.

> 	* elf.c (struct lto_section): New.

> 	(_bfd_elf_make_section_from_shdr): Parse content of

> 	.gnu_lto_.lto section.

> 	* elflink.c: Report error for a missing LTO plugin.

> 	* linker.c (_bfd_generic_link_add_one_symbol): Likewise.

> 

> binutils/ChangeLog:

> 2019-07-22  Martin Liska  <mliska@suse.cz>

> 

> 	PR 24768

> 	* nm.c (filter_symbols): Set report_plugin_err if

> 	error is reported.

> 	(display_rel_file): Report error for a missing LTO plugin.

> 

> gold/ChangeLog:

> 2019-07-22  Martin Liska  <mliska@suse.cz>

> 

> 	PR 24768

> 	* layout.h (class Layout): Add is_lto_slim_object and

> 	set_lto_slim_object.

> 	* object.cc (struct lto_section): Add lto_slim_object_.

> 	(big_endian>::do_layout): Parse content of

> 	.gnu_lto_.lto section.

> 	(big_endian>::do_add_symbols): Report error for a missing

> 	LTO plugin.


Approved - please apply.  However ...

+	  if (current->lto_slim_object && report_plugin_err)
+	    {
+	      report_plugin_err = FALSE;
+	      _bfd_error_handler
+		(_("%pB: plugin needed to handle lto object"),
+		 current);
+	    }

This piece of code is duplicated in several places.  It might be
worthwhile creating a new function for it, and calling it from
wherever it is currently being triggered.  (You might need to extend
the function to allow for the variation in the calls from nm.c, but
that is up to you).

Cheers
  Nick
Martin Liška July 29, 2019, 8:17 a.m. | #2
On 7/25/19 3:56 PM, Nick Clifton wrote:
> Hi Martin,

> 

>> bfd/ChangeLog:

>> 2019-07-22  Martin Liska  <mliska@suse.cz>

>>

>> 	PR 24768

>> 	* archive.c (_bfd_compute_and_write_armap): Come up with

>> 	report_plugin_err variable.

>> 	* bfd-in2.h (struct bfd): Add lto_slim_object flag.

>> 	* elf.c (struct lto_section): New.

>> 	(_bfd_elf_make_section_from_shdr): Parse content of

>> 	.gnu_lto_.lto section.

>> 	* elflink.c: Report error for a missing LTO plugin.

>> 	* linker.c (_bfd_generic_link_add_one_symbol): Likewise.

>>

>> binutils/ChangeLog:

>> 2019-07-22  Martin Liska  <mliska@suse.cz>

>>

>> 	PR 24768

>> 	* nm.c (filter_symbols): Set report_plugin_err if

>> 	error is reported.

>> 	(display_rel_file): Report error for a missing LTO plugin.

>>

>> gold/ChangeLog:

>> 2019-07-22  Martin Liska  <mliska@suse.cz>

>>

>> 	PR 24768

>> 	* layout.h (class Layout): Add is_lto_slim_object and

>> 	set_lto_slim_object.

>> 	* object.cc (struct lto_section): Add lto_slim_object_.

>> 	(big_endian>::do_layout): Parse content of

>> 	.gnu_lto_.lto section.

>> 	(big_endian>::do_add_symbols): Report error for a missing

>> 	LTO plugin.

> 

> Approved - please apply.  However ...


Thanks, I've just installed the patch.

> 

> +	  if (current->lto_slim_object && report_plugin_err)

> +	    {

> +	      report_plugin_err = FALSE;

> +	      _bfd_error_handler

> +		(_("%pB: plugin needed to handle lto object"),

> +		 current);

> +	    }

> 

> This piece of code is duplicated in several places.  It might be

> worthwhile creating a new function for it, and calling it from

> wherever it is currently being triggered.  (You might need to extend

> the function to allow for the variation in the calls from nm.c, but

> that is up to you).


Sure, that will be a nice improvement. Can you please point me to a header/source file
which is already shared among gold, bfd and binutils folders?

Thanks,
Martin

> 

> Cheers

>   Nick

> 

> 

>
Nick Clifton Aug. 5, 2019, 10:41 a.m. | #3
Hi Martin,

>> +	  if (current->lto_slim_object && report_plugin_err)

>> +	    {

>> +	      report_plugin_err = FALSE;

>> +	      _bfd_error_handler

>> +		(_("%pB: plugin needed to handle lto object"),

>> +		 current);

>> +	    }

>>

>> This piece of code is duplicated in several places.  It might be

>> worthwhile creating a new function for it,


> Sure, that will be a nice improvement. Can you please point me to a header/source file

> which is already shared among gold, bfd and binutils folders?


Ah - there isn't anything suitable really.  But if you put the
new function in the BFD sources and only use it from ld and the
binutils tools themselves, then the prototype should go into the
bfd/bfd.h header file.  GOLD does not use the bfd library, so it
would be unable to access the function.  (Which makes sense since
it has its own error reporting mechanism).

Cheers
  Nick

Patch

diff --git a/bfd/archive.c b/bfd/archive.c
index 68a92a3e36..0a7da3a0cb 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -2236,6 +2236,7 @@  _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
   long syms_max = 0;
   bfd_boolean ret;
   bfd_size_type amt;
+  static bfd_boolean report_plugin_err = TRUE;
 
   /* Dunno if this is the best place for this info...  */
   if (elength != 0)
@@ -2270,6 +2271,14 @@  _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
 	  long symcount;
 	  long src_count;
 
+	  if (current->lto_slim_object && report_plugin_err)
+	    {
+	      report_plugin_err = FALSE;
+	      _bfd_error_handler
+		(_("%pB: plugin needed to handle lto object"),
+		 current);
+	    }
+
 	  storage = bfd_get_symtab_upper_bound (current);
 	  if (storage < 0)
 	    goto error_return;
@@ -2322,10 +2331,14 @@  _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
 			  && syms[src_count]->name[1] == '_'
 			  && strcmp (syms[src_count]->name
 				     + (syms[src_count]->name[2] == '_'),
-				     "__gnu_lto_slim") == 0)
-			_bfd_error_handler
-			  (_("%pB: plugin needed to handle lto object"),
-			   current);
+				     "__gnu_lto_slim") == 0
+			  && report_plugin_err)
+			{
+			  report_plugin_err = FALSE;
+			  _bfd_error_handler
+			    (_("%pB: plugin needed to handle lto object"),
+			     current);
+			}
 		      namelen = strlen (syms[src_count]->name);
 		      amt = sizeof (char *);
 		      map[orl_count].name = (char **) bfd_alloc (arch, amt);
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 8374390e60..7e6dad78d4 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -7196,6 +7196,9 @@  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;
+
   /* Set to dummy BFD created when claimed by a compiler plug-in
      library.  */
   bfd *plugin_dummy_bfd;
diff --git a/bfd/elf.c b/bfd/elf.c
index 265150d511..bb35db54ed 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -999,6 +999,18 @@  convert_zdebug_to_debug (bfd *abfd, const char *name)
   return new_name;
 }
 
+/* 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.  */
 
@@ -1262,6 +1274,17 @@  _bfd_elf_make_section_from_shdr (bfd *abfd,
 	newsect->flags |= SEC_ELF_RENAME;
     }
 
+  /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
+     section.  */
+  const char *lto_section_name = ".gnu.lto_.lto.";
+  if (strncmp (name, lto_section_name, strlen (lto_section_name)) == 0)
+    {
+      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 9175d3fa20..1c5eae143a 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -4401,6 +4401,12 @@  error_free_dyn:
       goto error_free_vers;
     }
 
+  if (abfd->lto_slim_object)
+    {
+      _bfd_error_handler
+	(_("%pB: plugin needed to handle lto object"), abfd);
+    }
+
   for (isym = isymbuf, isymend = isymbuf + extsymcount;
        isym < isymend;
        isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
diff --git a/bfd/linker.c b/bfd/linker.c
index 1b71fcf8f0..edbd0a7df4 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -1421,12 +1421,24 @@  _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
   else if (bfd_is_com_section (section))
     {
       row = COMMON_ROW;
-      if (!bfd_link_relocatable (info)
-	  && name[0] == '_'
-	  && name[1] == '_'
-	  && strcmp (name + (name[2] == '_'), "__gnu_lto_slim") == 0)
-	_bfd_error_handler
-	  (_("%pB: plugin needed to handle lto object"), abfd);
+      static bfd_boolean report_plugin_err = TRUE;
+      if (!bfd_link_relocatable (info) && report_plugin_err)
+	{
+	  if (abfd->lto_slim_object)
+	    {
+	      report_plugin_err = FALSE;
+	      _bfd_error_handler
+		(_("%pB: plugin needed to handle lto object"), abfd);
+	    }
+	  else if (name[0] == '_'
+		   && name[1] == '_'
+		   && strcmp (name + (name[2] == '_'), "__gnu_lto_slim") == 0)
+	    {
+	      report_plugin_err = FALSE;
+	      _bfd_error_handler
+		(_("%pB: plugin needed to handle lto object"), abfd);
+	    }
+	}
     }
   else
     row = DEF_ROW;
diff --git a/binutils/nm.c b/binutils/nm.c
index fd3f73167e..5d3d647843 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -438,6 +438,10 @@  print_symdef_entry (bfd *abfd)
     }
 }
 
+
+/* True when we can report missing plugin error.  */
+bfd_boolean report_plugin_err = TRUE;
+
 /* Choose which symbol entries to print;
    compact them downward to get rid of the rest.
    Return the number of symbols to be printed.  */
@@ -470,9 +474,13 @@  filter_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms,
 
       if (sym->name[0] == '_'
 	  && sym->name[1] == '_'
-	  && strcmp (sym->name + (sym->name[2] == '_'), "__gnu_lto_slim") == 0)
-	non_fatal (_("%s: plugin needed to handle lto object"),
-		   bfd_get_filename (abfd));
+	  && strcmp (sym->name + (sym->name[2] == '_'), "__gnu_lto_slim") == 0
+	  && report_plugin_err)
+	{
+	  report_plugin_err = FALSE;
+	  non_fatal (_("%s: plugin needed to handle lto object"),
+		     bfd_get_filename (abfd));
+	}
 
       if (undefined_only)
 	keep = bfd_is_und_section (sym->section);
@@ -1164,6 +1172,15 @@  display_rel_file (bfd *abfd, bfd *archive_bfd)
 	}
     }
 
+  /* lto_slim_object is set to false when a bfd is loaded with a compiler
+     LTO plugin.  */
+  if (abfd->lto_slim_object)
+    {
+      report_plugin_err = FALSE;
+      non_fatal (_("%s: plugin needed to handle lto object"),
+		 bfd_get_filename (abfd));
+    }
+
   /* Discard the symbols we don't want to print.
      It's OK to do this in place; we'll free the storage anyway
      (after printing).  */
diff --git a/gold/layout.h b/gold/layout.h
index bfd44e1307..b9b75816e8 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -593,6 +593,14 @@  class Layout
   set_unique_segment_for_sections_specified()
   { this->unique_segment_for_sections_specified_ = true; }
 
+  bool
+  is_lto_slim_object () const
+  { return this->lto_slim_object_; }
+
+  void
+  set_lto_slim_object ()
+  { this->lto_slim_object_ = true; }
+
   // For incremental updates, allocate a block of memory from the
   // free list.  Find a block starting at or after MINOFF.
   off_t
@@ -1480,6 +1488,8 @@  class Layout
   Incremental_inputs* incremental_inputs_;
   // Whether we record output section data created in script
   bool record_output_section_data_from_script_;
+  // Set if this is a slim LTO object not loaded with a compiler plugin
+  bool lto_slim_object_;
   // List of output data that needs to be removed at relaxation clean up.
   Output_section_data_list script_output_section_data_list_;
   // Structure to save segment states before entering the relaxation loop.
diff --git a/gold/object.cc b/gold/object.cc
index 689448f50c..86c519acf7 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -1380,6 +1380,18 @@  Sized_relobj_file<size, big_endian>::layout_gnu_property_section(
     }
 }
 
+// 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;
+};
+
 // Lay out the input sections.  We walk through the sections and check
 // whether they should be included in the link.  If they should, we
 // pass them to the Layout object, which will return an output section
@@ -1865,6 +1877,19 @@  Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
 		debug_types_sections.push_back(i);
 	    }
 	}
+
+      /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
+	 section.  */
+      const char *lto_section_name = ".gnu.lto_.lto.";
+      if (strncmp (name, lto_section_name, strlen (lto_section_name)) == 0)
+	{
+	  section_size_type contents_len;
+	  const unsigned char* pcontents = this->section_contents(i, &contents_len, false);
+	  struct lto_section lsection = *(const lto_section*)pcontents;
+	  if (lsection.slim_object)
+	    gold_info(_("%s: plugin needed to handle lto object"),
+		      this->name().c_str());
+	}
     }
 
   if (!is_pass_two)
@@ -2083,7 +2108,7 @@  template<int size, bool big_endian>
 void
 Sized_relobj_file<size, big_endian>::do_add_symbols(Symbol_table* symtab,
 						    Read_symbols_data* sd,
-						    Layout*)
+						    Layout* layout)
 {
   if (sd->symbols == NULL)
     {
@@ -2102,6 +2127,10 @@  Sized_relobj_file<size, big_endian>::do_add_symbols(Symbol_table* symtab,
 
   this->symbols_.resize(symcount);
 
+  if (layout->is_lto_slim_object ())
+    gold_info(_("%s: plugin needed to handle lto object"),
+	      this->name().c_str());
+
   const char* sym_names =
     reinterpret_cast<const char*>(sd->symbol_names->data());
   symtab->add_from_relobj(this,