diff options
-rw-r--r-- | gold/ChangeLog | 27 | ||||
-rw-r--r-- | gold/object.cc | 95 | ||||
-rw-r--r-- | gold/object.h | 45 | ||||
-rw-r--r-- | gold/plugin.cc | 40 | ||||
-rw-r--r-- | gold/plugin.h | 28 |
5 files changed, 193 insertions, 42 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 765da243966..493681eba0c 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 f7dcda89ceb..b1f83e7aef8 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 fcb5d317ea1..6c8c7a31836 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 c4e46b501ad..498b344c9c9 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 5b6fa1fd340..20d416aac7e 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_; |