aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog27
-rw-r--r--gold/object.cc95
-rw-r--r--gold/object.h45
-rw-r--r--gold/plugin.cc40
-rw-r--r--gold/plugin.h28
5 files changed, 193 insertions, 42 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 765da24..493681e 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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
diff --git a/gold/object.cc b/gold/object.cc
index f7dcda8..b1f83e7 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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>
diff --git a/gold/object.h b/gold/object.h
index fcb5d31..6c8c7a3 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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.
diff --git a/gold/plugin.cc b/gold/plugin.cc
index c4e46b5..498b344 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -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.
diff --git a/gold/plugin.h b/gold/plugin.h
index 5b6fa1f..20d416a 100644
--- a/gold/plugin.h
+++ b/gold/plugin.h
@@ -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_;