This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gold][patch] Layout allocated sections from LTO plugin honoring original link order


The gold plugin interface currently lets the plugin claim IR files and
provide a list of global symbols during first (input) pass of the
link. When all files have been scanned and the symbol table is fully
built, the plugin then gets the opportunity to generate code and
provide a set of replacement files that get added to the link. The
plugin framework was designed to honor the link order as far as symbol
binding goes, but neglected to honor link order when laying out the
contents of sections. For certain sections -- .init, .fini., .ctors,
.dtors, etc. -- this is a problem because the file crtend.o typically
contributes end-of-list markers to those sections, and the new files
get added after that, resulting in a failure to run some initializers.

This patch fixes the problem by deferring the layout of any allocated
section from a normal object file once the first IR file has been
claimed by a plugin. After the plugin has added the replacement files,
the linker then performs the layout of the deferred sections.

-cary


	* object.cc (Sized_relobj::layout_section): New function.
	(Sized_relobj::do_layout): Defer layout of input sections until after
	plugin has provided replacement files.
	(Sized_relobj::do_layout_deferred_sections): New function.
	* object.h (Relobj::set_section_offset): Remove virtual keyword.
	(Relobj::layout_deferred_sections): New function.
	(Relobj::do_layout_deferred_sections): New function.
	(Sized_relobj::do_layout_deferred_sections): New function.
	(Sized_relobj::layout_section): New function.
	(Sized_relobj::Deferred_layout): New structure.
	(Sized_relobj::deferred_layout_): New field.
	* plugin.cc (Plugin_manager::finish): Renamed, was cleanup.
	Change all callers.  Layout deferred sections.
	(class Plugin_finish): Renamed, was Plugin_cleanup.  Change all
	references.
	(Plugin_hook::run): Move code from do_plugin_hook inline.
	(Plugin_hook::do_plugin_hook): Remove.
	* plugin.h (Plugin_manager::Plugin_manager): Add missing initializers.
	(Plugin_manager::finish): Renamed, was cleanup.
	(Plugin_manager::should_defer_layout): New function.
	(Plugin_manager::add_deferred_layout_object): New function.
	(Plugin_manager::Deferred_layout_list): New type.
	(Plugin_manager::deferred_layout_objects_): New field.
	(Plugin_hook::do_plugin_hook): Remove.


Index: object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.78
diff -u -p -r1.78 object.cc
--- object.cc	29 Sep 2008 21:10:26 -0000	1.78
+++ object.cc	19 Dec 2008 01:36:14 -0000
@@ -37,6 +37,7 @@
 #include "reloc.h"
 #include "object.h"
 #include "dynobj.h"
+#include "plugin.h"

 namespace gold
 {
@@ -784,6 +785,34 @@ Sized_relobj<size, big_endian>::include_
   return include1 && include2;
 }

+// Layout an input section.
+
+template<int size, bool big_endian>
+inline void
+Sized_relobj<size, big_endian>::layout_section(Layout* layout,
+                                               unsigned int shndx,
+                                               const char* name,
+                                               typename This::Shdr& shdr,
+                                               unsigned int reloc_shndx,
+                                               unsigned int reloc_type)
+{
+  off_t offset;
+  Output_section* os = layout->layout(this, shndx, name, shdr,
+					  reloc_shndx, reloc_type, &offset);
+
+  this->output_sections()[shndx] = os;
+  if (offset == -1)
+    this->section_offsets_[shndx] = invalid_address;
+  else
+    this->section_offsets_[shndx] = convert_types<Address, off_t>(offset);
+
+  // If this section requires special handling, and if there are
+  // relocs that apply to it, then we must do the special handling
+  // before we apply the relocs.
+  if (offset == -1 && reloc_shndx != 0)
+    this->set_relocs_must_follow_section_writes();
+}
+
 // 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
@@ -807,6 +836,13 @@ Sized_relobj<size, big_endian>::do_layou
   const unsigned char* pnamesu = sd->section_names->data();
   const char* pnames = reinterpret_cast<const char*>(pnamesu);

+  // If any input files have been claimed by plugins, we need to defer
+  // actual layout until the replacement files have arrived.
+  const bool should_defer_layout =
+      (parameters->options().has_plugins()
+       && parameters->options().plugins()->should_defer_layout());
+  unsigned int num_sections_to_defer = 0;
+
   // For each section, record the index of the reloc section if any.
   // Use 0 to mean that there is no reloc section, -1U to mean that
   // there is more than one.
@@ -818,6 +854,10 @@ Sized_relobj<size, big_endian>::do_layou
     {
       typename This::Shdr shdr(pshdrs);

+      // Count the number of sections whose layout will be deferred.
+      if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
+        ++num_sections_to_defer;
+
       unsigned int sh_type = shdr.get_sh_type();
       if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA)
 	{
@@ -856,6 +896,12 @@ Sized_relobj<size, big_endian>::do_layou
       return;
     }

+  if (num_sections_to_defer > 0)
+    {
+      parameters->options().plugins()->add_deferred_layout_object(this);
+      this->deferred_layout_.reserve(num_sections_to_defer);
+    }
+
   // Whether we've seen a .note.GNU-stack section.
   bool seen_gnu_stack = false;
   // The flags of a .note.GNU-stack section.
@@ -960,22 +1006,22 @@ Sized_relobj<size, big_endian>::do_layou
 	  continue;
 	}

-      off_t offset;
-      Output_section* os = layout->layout(this, i, name, shdr,
-					  reloc_shndx[i], reloc_type[i],
-					  &offset);
-
-      out_sections[i] = os;
-      if (offset == -1)
-        out_section_offsets[i] = invalid_address;
+      if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
+        {
+          this->deferred_layout_.push_back(Deferred_layout(i, name, pshdrs,
+                                                           reloc_shndx[i],
+                                                           reloc_type[i]));
+
+          // Put dummy values here; real values will be supplied by
+          // do_layout_deferred_sections.
+          out_sections[i] = reinterpret_cast<Output_section*>(1);
+          out_section_offsets[i] = invalid_address;
+        }
       else
-        out_section_offsets[i] = convert_types<Address, off_t>(offset);
-
-      // If this section requires special handling, and if there are
-      // relocs that apply to it, then we must do the special handling
-      // before we apply the relocs.
-      if (offset == -1 && reloc_shndx[i] != 0)
-	this->set_relocs_must_follow_section_writes();
+        {
+          this->layout_section(layout, i, name, shdr, reloc_shndx[i],
+                               reloc_type[i]);
+        }
     }

   layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
@@ -1059,6 +1105,27 @@ Sized_relobj<size, big_endian>::do_layou
   sd->section_names = NULL;
 }

+// Layout sections whose layout was deferred while waiting for
+// input files from a plugin.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_layout_deferred_sections(Layout* layout)
+{
+  typename std::vector<Deferred_layout>::iterator deferred;
+
+  for (deferred = this->deferred_layout_.begin();
+       deferred != this->deferred_layout_.end();
+       ++deferred)
+    {
+      typename This::Shdr shdr(deferred->shdr_data_);
+      this->layout_section(layout, deferred->shndx_, deferred->name_.c_str(),
+                           shdr, deferred->reloc_shndx_,
deferred->reloc_type_);
+    }
+
+  this->deferred_layout_.clear();
+}
+
 // Add the symbols to the symbol table.

 template<int size, bool big_endian>
Index: object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.66
diff -u -p -r1.66 object.h
--- object.h	29 Sep 2008 21:10:26 -0000	1.66
+++ object.h	19 Dec 2008 01:36:14 -0000
@@ -671,7 +671,7 @@ class Relobj : public Object
   { return this->do_output_section_offset(shndx); }

   // Set the offset of an input section within its output section.
-  virtual void
+  void
   set_section_offset(unsigned int shndx, uint64_t off)
   { this->do_set_section_offset(shndx, off); }

@@ -712,6 +712,12 @@ class Relobj : public Object
     return (*this->map_to_relocatable_relocs_)[reloc_shndx];
   }

+  // Layout sections whose layout was deferred while waiting for
+  // input files from a plugin.
+  void
+  layout_deferred_sections(Layout* layout)
+  { this->do_layout_deferred_sections(layout); }
+
  protected:
   // The output section to be used for each input section, indexed by
   // the input section number.  The output section is NULL if the
@@ -764,6 +770,11 @@ class Relobj : public Object
   virtual void
   do_set_section_offset(unsigned int shndx, uint64_t off) = 0;

+  // Layout sections whose layout was deferred while waiting for
+  // input files from a plugin--implemented by child class.
+  virtual void
+  do_layout_deferred_sections(Layout*) = 0;
+
   // Return the vector mapping input sections to output sections.
   Output_sections&
   output_sections()
@@ -1368,6 +1379,11 @@ class Sized_relobj : public Relobj
   void
   do_layout(Symbol_table*, Layout*, Read_symbols_data*);

+  // Layout sections whose layout was deferred while waiting for
+  // input files from a plugin.
+  void
+  do_layout_deferred_sections(Layout*);
+
   // Add the symbols to the symbol table.
   void
   do_add_symbols(Symbol_table*, Read_symbols_data*);
@@ -1558,6 +1574,12 @@ class Sized_relobj : public Relobj
   include_linkonce_section(Layout*, unsigned int, const char*,
 			   const elfcpp::Shdr<size, big_endian>&);

+  // Layout an input section.
+  void
+  layout_section(Layout* layout, unsigned int shndx, const char* name,
+                 typename This::Shdr& shdr, unsigned int reloc_shndx,
+                 unsigned int reloc_type);
+
   // Views and sizes when relocating.
   struct View_size
   {
@@ -1681,6 +1703,25 @@ class Sized_relobj : public Relobj
   };
   typedef Unordered_map<unsigned int, Tls_got_entry> Local_tls_got_offsets;

+  // Saved information for sections whose layout was deferred.
+  struct Deferred_layout
+  {
+    static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+    Deferred_layout(unsigned int shndx, const char* name,
+                    const unsigned char* pshdr,
+                    unsigned int reloc_shndx, unsigned int reloc_type)
+      : shndx_(shndx), name_(name), reloc_shndx_(reloc_shndx),
+        reloc_type_(reloc_type)
+    {
+      memcpy(this->shdr_data_, pshdr, shdr_size);
+    }
+    unsigned int shndx_;
+    std::string name_;
+    unsigned int reloc_shndx_;
+    unsigned int reloc_type_;
+    unsigned char shdr_data_[shdr_size];
+  };
+
   // General access to the ELF file.
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
   // Index of SHT_SYMTAB section.
@@ -1715,6 +1756,8 @@ class Sized_relobj : public Relobj
   Comdat_group_table comdat_groups_;
   // Whether this object has a GNU style .eh_frame section.
   bool has_eh_frame_;
+  // The list of sections whose layout was deferred.
+  std::vector<Deferred_layout> deferred_layout_;
 };

 // A class to manage the list of all objects.
Index: plugin.cc
===================================================================
RCS file: /cvs/src/src/gold/plugin.cc,v
retrieving revision 1.5
diff -u -p -r1.5 plugin.cc
--- plugin.cc	16 Dec 2008 19:19:15 -0000	1.5
+++ plugin.cc	19 Dec 2008 01:36:14 -0000
@@ -306,11 +306,18 @@ Plugin_manager::all_symbols_read(Workque
   *last_blocker = this->this_blocker_;
 }

-// Call the cleanup handlers.
+// Layout deferred sections and call the cleanup handlers.

 void
-Plugin_manager::cleanup()
+Plugin_manager::finish()
 {
+  Deferred_layout_list::iterator obj;
+
+  for (obj = this->deferred_layout_objects_.begin();
+       obj != this->deferred_layout_objects_.end();
+       ++obj)
+    (*obj)->layout_deferred_sections(this->layout_);
+
   for (this->current_ = this->plugins_.begin();
        this->current_ != this->plugins_.end();
        ++this->current_)
@@ -713,17 +720,18 @@ Add_plugin_symbols::run(Workqueue*)
   this->obj_->add_symbols(this->symtab_, this->layout_);
 }

-// Class Plugin_cleanup.  This task calls the plugin cleanup hooks once all
-// replacement files have been added.
+// Class Plugin_finish.  This task runs after all replacement files have
+// been added.  It calls Layout::layout for any deferred sections and
+// calls each plugin's cleanup handler.

-class Plugin_cleanup : public Task
+class Plugin_finish : public Task
 {
  public:
-  Plugin_cleanup(Task_token* this_blocker, Task_token* next_blocker)
+  Plugin_finish(Task_token* this_blocker, Task_token* next_blocker)
     : this_blocker_(this_blocker), next_blocker_(next_blocker)
   { }

-  ~Plugin_cleanup()
+  ~Plugin_finish()
   {
     if (this->this_blocker_ != NULL)
       delete this->this_blocker_;
@@ -743,11 +751,11 @@ class Plugin_cleanup : public Task

   void
   run(Workqueue*)
-  { parameters->options().plugins()->cleanup(); }
+  { parameters->options().plugins()->finish(); }

   std::string
   get_name() const
-  { return "Plugin_cleanup"; }
+  { return "Plugin_finish"; }

  private:
   Task_token* this_blocker_;
@@ -778,18 +786,10 @@ Plugin_hook::locks(Task_locker*)
 {
 }

-// Run a Plugin_hook task.
-
-void
-Plugin_hook::run(Workqueue* workqueue)
-{
-  this->do_plugin_hook(workqueue);
-}
-
 // Run the "all symbols read" plugin hook.

 void
-Plugin_hook::do_plugin_hook(Workqueue* workqueue)
+Plugin_hook::run(Workqueue* workqueue)
 {
   gold_assert(this->options_.has_plugins());
   this->options_.plugins()->all_symbols_read(workqueue,
@@ -799,8 +799,8 @@ Plugin_hook::do_plugin_hook(Workqueue* w
                                              this->dirpath_,
                                              this->mapfile_,
                                              &this->this_blocker_);
-  workqueue->queue_soon(new Plugin_cleanup(this->this_blocker_,
-					   this->next_blocker_));
+  workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
+					  this->next_blocker_));
 }

 // The C interface routines called by the plugins.
Index: plugin.h
===================================================================
RCS file: /cvs/src/src/gold/plugin.h,v
retrieving revision 1.2
diff -u -p -r1.2 plugin.h
--- plugin.h	5 Dec 2008 21:34:50 -0000	1.2
+++ plugin.h	19 Dec 2008 01:36:14 -0000
@@ -120,7 +120,8 @@ class Plugin_manager
 {
  public:
   Plugin_manager(const General_options& options)
-    : plugins_(), in_replacement_phase_(false), options_(options),
+    : plugins_(), objects_(), deferred_layout_objects_(), input_file_(NULL),
+      plugin_input_file_(), in_replacement_phase_(false), options_(options),
       workqueue_(NULL), input_objects_(NULL), symtab_(NULL), layout_(NULL),
       dirpath_(NULL), mapfile_(NULL), this_blocker_(NULL)
   { this->current_ = plugins_.end(); }
@@ -154,9 +155,9 @@ class Plugin_manager
                    Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
                    Mapfile* mapfile, Task_token** last_blocker);

-  // Call the cleanup handlers.
+  // Run deferred layout and call the cleanup handlers.
   void
-  cleanup();
+  finish();

   // Register a claim-file handler.
   void
@@ -196,6 +197,19 @@ class Plugin_manager
     return this->objects_[handle];
   }

+  // Return TRUE if any input files have been claimed by a plugin
+  // and we are still in the initial input phase.
+  bool
+  should_defer_layout() const
+  { return !this->objects_.empty() && !this->in_replacement_phase_; }
+
+  // Add a regular object to the deferred layout list.  These are
+  // objects whose layout has been deferred until after the
+  // replacement files have arrived.
+  void
+  add_deferred_layout_object(Relobj* obj)
+  { this->deferred_layout_objects_.push_back(obj); }
+
   // Add a new input file.
   ld_plugin_status
   add_input_file(char *pathname);
@@ -211,6 +225,7 @@ class Plugin_manager

   typedef std::list<Plugin*> Plugin_list;
   typedef std::vector<Pluginobj*> Object_list;
+  typedef std::vector<Relobj*> Deferred_layout_list;

   // The list of plugin libraries.
   Plugin_list plugins_;
@@ -221,6 +236,9 @@ class Plugin_manager
   // serves as the "handle" that we pass to the plugins.
   Object_list objects_;

+  // The list of regular objects whose layout has been deferred.
+  Deferred_layout_list deferred_layout_objects_;
+
   // The file currently up for claim by the plugins.
   Input_file* input_file_;
   struct ld_plugin_input_file plugin_input_file_;
@@ -456,10 +474,6 @@ class Plugin_hook : public Task
   { return "Plugin_hook"; }

  private:
-  // Call the plugin hook.
-  void
-  do_plugin_hook(Workqueue*);
-
   const General_options& options_;
   Input_objects* input_objects_;
   Symbol_table* symtab_;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]