* object.cc (Sized_relobj::layout_section): New function.
authorCary Coutant <ccoutant@google.com>
Tue, 23 Dec 2008 02:02:20 +0000 (02:02 +0000)
committerCary Coutant <ccoutant@google.com>
Tue, 23 Dec 2008 02:02:20 +0000 (02:02 +0000)
(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.

gold/ChangeLog
gold/object.cc
gold/object.h
gold/plugin.cc
gold/plugin.h

index 765da2439662de67c2834f928ff25b992ff24369..493681eba0c6e91b3be7a158e38fad36c77bef4f 100644 (file)
@@ -1,3 +1,30 @@
+2008-12-22  Cary Coutant  <ccoutant@google.com>
+
+       * 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.
+
 2008-12-17  Ian Lance Taylor  <iant@google.com>
 
        * options.h (class General_options): Add --no case for
index f7dcda89ceb201f204dc6874a1be3aabe26ac891..b1f83e7aef8eb7f8462b65ca50e81ca289db84e8 100644 (file)
@@ -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_linkonce_section(
   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_layout(Symbol_table* symtab,
   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_layout(Symbol_table* symtab,
     {
       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_layout(Symbol_table* symtab,
       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_layout(Symbol_table* symtab,
          continue;
        }
 
-      off_t offset;
-      Output_section* os = layout->layout(this, i, name, shdr,
-                                         reloc_shndx[i], reloc_type[i],
-                                         &offset);
+      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]));
 
-      out_sections[i] = os;
-      if (offset == -1)
-        out_section_offsets[i] = invalid_address;
+          // 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_layout(Symbol_table* symtab,
   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 fcb5d317ea1f2db0d78188a4f616093e6886f9f2..6c8c7a318364528960edb952da34a6f783f81918 100644 (file)
@@ -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 c4e46b501adbea5d69fdbe93e68cede7aa513e94..498b344c9c9285415f98f1e96af3992970df7dab 100644 (file)
@@ -306,11 +306,18 @@ Plugin_manager::all_symbols_read(Workqueue* workqueue,
   *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* workqueue)
                                              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 5b6fa1fd3400a8cd74fa771714be0f7016567081..20d416aac7ea708c6791fbcc336e0a451954020a 100644 (file)
@@ -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_;