From 072fe7ce7a6d9d6b401284de5858495157a35df3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 15 May 2009 17:01:04 +0000 Subject: * gold.h (Incremental_argument_list): Remove (invalid) forward declaration. * incremental.cc (Incremental_inputs::report_achive): New method. (Incremental_inputs::report_object): New method. (Incremental_inputs::report_script): New method. (Incremental_inputs::finalize_inputs): New method. (Incremental_inputs::finalize): Call finalize_inputs(). (Incremental_inputs::sized_create_incremental_inputs_section_data): Create inputs entries. * incremental.h (Incremental_input_type): New enum. (Incremental_inputs::Incremental_input): Initialize new fields. (Incremental_inputs::report_inputs): New method. (Incremental_inputs::report_achive): New method. (Incremental_inputs::report_object): New method. (Incremental_inputs::report_script): New method. (Incremental_inputs::finalize_inputs): New method. (Incremental_inputs::Input_info): New struct. (Incremental_inputs::Input_info_map): New typedef. (Incremental_inputs::lock_): New field. (Incremental_inputs::Inputs_): New field. (Incremental_inputs::Inputs_map): New field. * main.cc (main): Call Incremental_input::report_inputs. * options.h (Input_argument_list): Typedef moved from Input_arguments. (Input_file_group::Files): Remove, use ::Input_argument_list. (Input_file_group::Input_argument_list): Remove, use ::Input_argument_list. * plugin.cc (Plugin_manager::add_input_file): Add error in incremental build. * read_syms.cc (do_read_syms): Call Incremental_input::report_* functions. * script.cc (read_input_script): Call Incremental_input::report_script. * script.h (Script_info): New class. --- gold/ChangeLog | 37 +++++++++++++ gold/gold.h | 3 +- gold/incremental.cc | 147 ++++++++++++++++++++++++++++++++++++++++++++++++---- gold/incremental.h | 90 ++++++++++++++++++++++++++++++-- gold/main.cc | 5 +- gold/options.h | 8 +-- gold/plugin.cc | 3 ++ gold/readsyms.cc | 18 ++++++- gold/script.cc | 8 +++ gold/script.h | 21 ++++++++ 10 files changed, 317 insertions(+), 23 deletions(-) (limited to 'gold') diff --git a/gold/ChangeLog b/gold/ChangeLog index 5df808b..dd8e3c2 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,40 @@ +2009-05-15 Mikolaj Zalewski + + * gold.h (Incremental_argument_list): Remove (invalid) forward + declaration. + * incremental.cc (Incremental_inputs::report_achive): New method. + (Incremental_inputs::report_object): New method. + (Incremental_inputs::report_script): New method. + (Incremental_inputs::finalize_inputs): New method. + (Incremental_inputs::finalize): Call finalize_inputs(). + (Incremental_inputs::sized_create_incremental_inputs_section_data): + Create inputs entries. + * incremental.h (Incremental_input_type): New enum. + (Incremental_inputs::Incremental_input): Initialize new fields. + (Incremental_inputs::report_inputs): New method. + (Incremental_inputs::report_achive): New method. + (Incremental_inputs::report_object): New method. + (Incremental_inputs::report_script): New method. + (Incremental_inputs::finalize_inputs): New method. + (Incremental_inputs::Input_info): New struct. + (Incremental_inputs::Input_info_map): New typedef. + (Incremental_inputs::lock_): New field. + (Incremental_inputs::Inputs_): New field. + (Incremental_inputs::Inputs_map): New field. + * main.cc (main): Call Incremental_input::report_inputs. + * options.h (Input_argument_list): Typedef moved from + Input_arguments. + (Input_file_group::Files): Remove, use ::Input_argument_list. + (Input_file_group::Input_argument_list): Remove, use + ::Input_argument_list. + * plugin.cc (Plugin_manager::add_input_file): Add error in + incremental build. + * read_syms.cc (do_read_syms): Call Incremental_input::report_* + functions. + * script.cc (read_input_script): Call + Incremental_input::report_script. + * script.h (Script_info): New class. + 2009-04-27 Ian Lance Taylor * x86_64.cc (do_adjust_output_section): Set entsize to diff --git a/gold/gold.h b/gold/gold.h index efebda8..bf014e8 100644 --- a/gold/gold.h +++ b/gold/gold.h @@ -148,7 +148,6 @@ namespace gold class General_options; class Command_line; -class Input_argument_list; class Dirsearch; class Input_objects; class Mapfile; @@ -293,7 +292,7 @@ queue_initial_tasks(const General_options&, // Queue up the set of tasks to be done before // the middle set of tasks. Only used when garbage -// collection is to be done. +// collection is to be done. extern void queue_middle_gc_tasks(const General_options&, const Task*, diff --git a/gold/incremental.cc b/gold/incremental.cc index 7e99e1e..8024551 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -86,7 +86,7 @@ class Incremental_inputs_header_write Incremental_inputs_header_write(unsigned char *p) : p_(reinterpret_cast(p)) { } - + static const int data_size = sizeof(internal::Incremental_inputs_header_data); void @@ -179,12 +179,114 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) this->strtab_->add(args.c_str(), true, &this->command_line_key_); } +// Record that the input argument INPUT is an achive ARCHIVE. This is +// called by Read_symbols after finding out the type of the file. + +void +Incremental_inputs::report_archive(const Input_argument* input, + Archive* archive) +{ + Hold_lock hl(*this->lock_); + + Input_info info; + info.type = INCREMENTAL_INPUT_ARCHIVE; + info.archive = archive; + inputs_map_.insert(std::make_pair(input, info)); +} + +// Record that the input argument INPUT is an object OBJ. This is +// called by Read_symbols after finding out the type of the file. + +void +Incremental_inputs::report_object(const Input_argument* input, + Object* obj) +{ + Hold_lock hl(*this->lock_); + + Input_info info; + info.type = (obj->is_dynamic() + ? INCREMENTAL_INPUT_SHARED_LIBRARY + : INCREMENTAL_INPUT_OBJECT); + info.object = obj; + inputs_map_.insert(std::make_pair(input, info)); +} + +// Record that the input argument INPUT is an script SCRIPT. This is +// called by read_script after parsing the script and reading the list +// of inputs added by this script. + +void +Incremental_inputs::report_script(const Input_argument* input, + Script_info* script) +{ + Hold_lock hl(*this->lock_); + + Input_info info; + info.type = INCREMENTAL_INPUT_SCRIPT; + info.script = script; + inputs_map_.insert(std::make_pair(input, info)); +} + +// Compute indexes in the order in which the inputs should appear in +// .gnu_incremental_inputs. This needs to be done after all the +// scripts are parsed. The function is first called for the command +// line inputs arguments and may call itself recursively for e.g. a +// list of elements of a group or a list of inputs added by a script. +// The [BEGIN; END) interval to analyze and *INDEX is the current +// value of the index (that will be updated). + +void +Incremental_inputs::finalize_inputs( + Input_argument_list::const_iterator begin, + Input_argument_list::const_iterator end, + unsigned int* index) +{ + for (Input_argument_list::const_iterator p = begin; p != end; ++p) + { + if (p->is_group()) + { + finalize_inputs(p->group()->begin(), p->group()->end(), index); + continue; + } + + Inputs_info_map::iterator it = inputs_map_.find(&(*p)); + // TODO: turn it into an assert when the code will be more stable. + if (it == inputs_map_.end()) + { + gold_error("internal error: %s: incremental build info not provided", + (p->is_file() ? p->file().name() : "[group]")); + continue; + } + Input_info* info = &it->second; + info->index = *index; + (*index)++; + this->strtab_->add(p->file().name(), false, &info->filename_key); + if (info->type == INCREMENTAL_INPUT_SCRIPT) + { + finalize_inputs(info->script->inputs()->begin(), + info->script->inputs()->end(), + index); + } + } +} + // Finalize the incremental link information. Called from // Layout::finalize. void Incremental_inputs::finalize() { + unsigned int index = 0; + finalize_inputs(this->inputs_->begin(), this->inputs_->end(), &index); + + // Sanity check. + for (Inputs_info_map::const_iterator p = inputs_map_.begin(); + p != inputs_map_.end(); + ++p) + { + gold_assert(p->second.filename_key != 0); + } + this->strtab_->set_string_offsets(); } @@ -213,7 +315,7 @@ Incremental_inputs::create_incremental_inputs_section_data() #endif default: gold_unreachable(); - } + } } // Sized creation of .gnu_incremental_inputs section. @@ -221,22 +323,49 @@ Incremental_inputs::create_incremental_inputs_section_data() template Output_section_data* Incremental_inputs::sized_create_inputs_section_data() -{ - unsigned int sz = +{ + const int entry_size = + Incremental_inputs_entry_write::data_size; + const int header_size = Incremental_inputs_header_write::data_size; + + unsigned int sz = header_size + entry_size * this->inputs_map_.size(); unsigned char* buffer = new unsigned char[sz]; + unsigned char* inputs_base = buffer + header_size; + Incremental_inputs_header_write header_writer(buffer); - gold_assert(this->command_line_key_ > 0); int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_); - + header_writer.put_version(INCREMENTAL_LINK_VERSION); - header_writer.put_input_file_count(0); // TODO: store input files data. + header_writer.put_input_file_count(this->inputs_map_.size()); header_writer.put_command_line_offset(cmd_offset); header_writer.put_reserved(0); - + + for (Inputs_info_map::const_iterator it = this->inputs_map_.begin(); + it != this->inputs_map_.end(); + ++it) + { + gold_assert(it->second.index < this->inputs_map_.size()); + + unsigned char* entry_buffer = + inputs_base + it->second.index * entry_size; + Incremental_inputs_entry_write entry(entry_buffer); + int filename_offset = + this->strtab_->get_offset_from_key(it->second.filename_key); + entry.put_filename_offset(filename_offset); + // TODO: add per input data and timestamp. Currently we store + // an out-of-bounds offset for future version of gold to reject + // such an incremental_inputs section. + entry.put_data_offset(0xffffffff); + entry.put_timestamp_sec(0); + entry.put_timestamp_usec(0); + entry.put_input_type(it->second.type); + entry.put_reserved(0); + } + return new Output_data_const_buffer(buffer, sz, 8, - "** incremental link inputs list"); + "** incremental link inputs list"); } } // End namespace gold. diff --git a/gold/incremental.h b/gold/incremental.h index dd9ebc5..ed074ae 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -23,6 +23,7 @@ #ifndef GOLD_INCREMENTAL_H #define GOLD_INCREMENTAL_H +#include #include #include "stringpool.h" @@ -37,20 +38,49 @@ class Incremental_inputs_checker; class Object; class Output_section_data; +// Incremental input type as stored in .gnu_incremental_inputs. + +enum Incremental_input_type +{ + INCREMENTAL_INPUT_INVALID = 0, + INCREMENTAL_INPUT_OBJECT = 1, + INCREMENTAL_INPUT_ARCHIVE = 2, + INCREMENTAL_INPUT_SHARED_LIBRARY = 3, + INCREMENTAL_INPUT_SCRIPT = 4 +}; + // This class contains the information needed during an incremental // build about the inputs necessary to build the .gnu_incremental_inputs. class Incremental_inputs { public: Incremental_inputs() - : command_line_key_(0), strtab_(new Stringpool()) + : lock_(new Lock()), inputs_(NULL), command_line_key_(0), + strtab_(new Stringpool()) { } ~Incremental_inputs() { delete this->strtab_; } // Record the command line. void report_command_line(int argc, const char* const* argv); - + + // Record the input arguments obtained from parsing the command line. + void + report_inputs(const Input_arguments& inputs) + { this->inputs_ = &inputs; } + + // Record that the input argument INPUT is an archive ARCHIVE. + void + report_archive(const Input_argument* input, Archive* archive); + + // Record that the input argument INPUT is to an object OBJ. + void + report_object(const Input_argument* input, Object* obj); + + // Record that the input argument INPUT is to an script SCRIPT. + void + report_script(const Input_argument* input, Script_info* script); + // Prepare for layout. Called from Layout::finalize. void finalize(); @@ -58,8 +88,8 @@ class Incremental_inputs // Create the content of the .gnu_incremental_inputs section. Output_section_data* create_incremental_inputs_section_data(); - - // Return the .gnu_incremental_strtab stringpool. + + // Return the .gnu_incremental_strtab stringpool. Stringpool* get_stringpool() { return this->strtab_; } @@ -68,7 +98,57 @@ class Incremental_inputs // Code for each of the four possible variants of create_inputs_section_data. template Output_section_data* - sized_create_inputs_section_data(); + sized_create_inputs_section_data(); + + // Compute indexes in the order in which the inputs should appear in + // .gnu_incremental_inputs and put file names to the stringtable. + // This needs to be done after all the scripts are parsed. + + void + finalize_inputs(Input_argument_list::const_iterator begin, + Input_argument_list::const_iterator end, + unsigned int* index); + + // Additional data about an input needed for an incremental link. + // None of these pointers is owned by the structure. + struct Input_info + { + Input_info() + : type(INCREMENTAL_INPUT_INVALID), archive(NULL), object(NULL), + script(NULL), filename_key(0), index(0) + { } + + // Type of the file pointed by this argument. + Incremental_input_type type; + + // Present if type == INCREMENTAL_INPUT_ARCHIVE. + Archive* archive; + + // Present if type == INCREMENTAL_INPUT_OBJECT or + // INCREMENTAL_INPUT_SHARED_LIBRARY. + Object* object; + + // Present if type == INCREMENTAL_INPUT_SCRIPT. + Script_info* script; + + // Key of the filename string in the section stringtable. + Stringpool::Key filename_key; + + // Position of the entry information in the output section. + unsigned int index; + }; + + typedef std::map Inputs_info_map; + + // A lock guarding access to inputs_ during the first phase of linking, when + // report_ function may be called from multiple threads. + Lock* lock_; + + // The list of input arguments obtained from parsing the command line. + const Input_arguments* inputs_; + + // A map containing additional information about the input elements. + Inputs_info_map inputs_map_; // The key of the command line string in the string pool. Stringpool::Key command_line_key_; diff --git a/gold/main.cc b/gold/main.cc index c2d3c30..84b4ae9 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -221,7 +221,10 @@ main(int argc, char** argv) &command_line.script_options()); if (layout.incremental_inputs() != NULL) - layout.incremental_inputs()->report_command_line(argc, argv); + { + layout.incremental_inputs()->report_command_line(argc, argv); + layout.incremental_inputs()->report_inputs(command_line.inputs()); + } // Get the search path from the -L options. Dirsearch search_path; diff --git a/gold/options.h b/gold/options.h index 904743e..b811332 100644 --- a/gold/options.h +++ b/gold/options.h @@ -1275,14 +1275,15 @@ class Input_argument Input_file_group* group_; }; +typedef std::vector Input_argument_list; + // A group from the command line. This is a set of arguments within // --start-group ... --end-group. class Input_file_group { public: - typedef std::vector Files; - typedef Files::const_iterator const_iterator; + typedef Input_argument_list::const_iterator const_iterator; Input_file_group() : files_() @@ -1304,7 +1305,7 @@ class Input_file_group { return this->files_.end(); } private: - Files files_; + Input_argument_list files_; }; // A list of files from the command line or a script. @@ -1312,7 +1313,6 @@ class Input_file_group class Input_arguments { public: - typedef std::vector Input_argument_list; typedef Input_argument_list::const_iterator const_iterator; Input_arguments() diff --git a/gold/plugin.cc b/gold/plugin.cc index 3c4d4ae..b1007a7 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -407,6 +407,9 @@ Plugin_manager::add_input_file(char *pathname) Input_argument* input_argument = new Input_argument(file); Task_token* next_blocker = new Task_token(true); next_blocker->add_blocker(); + if (this->layout_->incremental_inputs()) + gold_error(_("Input files added by plug-ins in --incremental mode not " + "supported yet.\n")); this->workqueue_->queue_soon(new Read_symbols(this->input_objects_, this->symtab_, this->layout_, diff --git a/gold/readsyms.cc b/gold/readsyms.cc index b6da88d..c05d5a3 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -33,6 +33,8 @@ #include "script.h" #include "readsyms.h" #include "plugin.h" +#include "layout.h" +#include "incremental.h" namespace gold { @@ -199,7 +201,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) { bool is_thin_archive = memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0; - if (is_thin_archive + if (is_thin_archive || memcmp(ehdr, Archive::armag, Archive::sarmag) == 0) { // This is an archive. @@ -207,7 +209,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) input_file, is_thin_archive, this->dirpath_, this); arch->setup(); - + + if (this->layout_->incremental_inputs()) + { + const Input_argument* ia = this->input_argument_; + this->layout_->incremental_inputs()->report_archive(ia, arch); + } + // Unlock the archive so it can be used in the next task. arch->unlock(this); @@ -280,6 +288,12 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) Read_symbols_data* sd = new Read_symbols_data; obj->read_symbols(sd); + if (this->layout_->incremental_inputs()) + { + const Input_argument* ia = this->input_argument_; + this->layout_->incremental_inputs()->report_object(ia, obj); + } + // Opening the file locked it, so now we need to unlock it. We // need to unlock it before queuing the Add_symbols task, // because the workqueue doesn't know about our lock on the diff --git a/gold/script.cc b/gold/script.cc index 30b4e3c..86ce13b 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -43,6 +43,7 @@ #include "target-select.h" #include "script.h" #include "script-c.h" +#include "incremental.h" namespace gold { @@ -1414,6 +1415,13 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout, this_blocker = nb; } + if (layout->incremental_inputs()) + { + // Like new Read_symbols(...) above, we rely on close.inputs() + // getting leaked by closure. + Script_info* info = new Script_info(closure.inputs()); + layout->incremental_inputs()->report_script(input_argument, info); + } *used_next_blocker = true; return true; diff --git a/gold/script.h b/gold/script.h index e4554d0..781d24d 100644 --- a/gold/script.h +++ b/gold/script.h @@ -45,6 +45,7 @@ class Symbol_table; class Layout; class Mapfile; class Input_argument; +class Input_arguments; class Input_objects; class Input_group; class Input_file; @@ -382,6 +383,26 @@ class Script_options Script_sections script_sections_; }; +// Information about a script input that will persist during the whole linker +// run. Needed only during an incremental build to retrieve the input files +// added by this script. + +class Script_info +{ + public: + Script_info(Input_arguments* inputs) + : inputs_(inputs) + { } + + // Returns the input files included because of this script. + Input_arguments* + inputs() + { return inputs_; } + + private: + Input_arguments* inputs_; +}; + // FILE was found as an argument on the command line, but was not // recognized as an ELF file. Try to read it as a script. Return // true if the file was handled. This has to handle /usr/lib/libc.so -- cgit v1.1