From b0193076dad64abdb42ed0057ad668eaf3c17c7a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Mon, 22 Mar 2010 14:18:24 +0000 Subject: [PATCH] 2010-03-22 Rafael Espindola * archive.cc (Should_include): Move to archive.h. (should_include_member): Make it a member of Archive. (Lib_group): New. (Add_lib_group_symbols): New. * archive.h: Include options.h. (Archive_member): Moved from Archive. (Should_include): Moved from archive.cc. (Lib_group): New. (Add_lib_group_symbols): New. * dynobj.cc (do_should_include_member): New. * dynobj.h (do_should_include_member): New. * gold.cc (queue_initial_tasks): Update call to queue. * main.cc (main): Print lib group stats. * object.cc (do_should_include_member): New. * object.h: Include archive.h. (Object::should_include_member): New. (Object::do_should_include_member): New. (Sized_relobj::do_should_include_member): New. * options.cc (General_options::parse_start_lib): New. (General_options::parse_end_lib): New. (Input_arguments::add_file): Handle lib groups. (Input_arguments::start_group): Check we are not in a lib. (Input_arguments::start_lib): New. (Input_arguments::end_lib): New. * options.h (General_options): Add start_lib and end_lib. (Input_argument::lib_): New. (Input_argument::lib): New. (Input_argument::is_lib): New. (Input_file_lib): New. (Input_arguments::in_lib_): New. (Input_arguments::in_lib): New. (Input_arguments::start_lib): New. (Input_arguments::end_lib_): New. * plugin.cc (Pluginobj::get_symbol_resolution_info): Mark symbols in unused members as preempted. (Sized_pluginobj::do_should_include_member): New. * plugin.h (Sized_pluginobj::do_should_include_member): New. * readsyms.cc (Read_symbols::locks): If we are just reading a member, return the blocker. (Read_symbols::do_whole_lib_group): New. (Read_symbols::do_lib_group): New. (Read_symbols::do_read_symbols): Handle lib groups. (Read_symbols::get_name): Handle lib groups. * readsyms.h (Read_symbols): Add an archive member pointer. (Read_symbols::do_whole_lib_group): New. (Read_symbols::do_lib_group): New. (Read_symbols::member_): New. * script.cc (read_input_script): Update call to queue_soon. --- gold/ChangeLog | 51 ++++++++++++++++ gold/archive.cc | 178 ++++++++++++++++++++++++++++++++++++++++++++++++------- gold/archive.h | 136 +++++++++++++++++++++++++++++++++++++----- gold/dynobj.cc | 8 +++ gold/dynobj.h | 4 ++ gold/gold.cc | 2 +- gold/main.cc | 1 + gold/object.cc | 49 +++++++++++++++ gold/object.h | 16 ++++- gold/options.cc | 52 +++++++++++++++- gold/options.h | 97 ++++++++++++++++++++++++++++-- gold/plugin.cc | 40 +++++++++++++ gold/plugin.h | 4 ++ gold/readsyms.cc | 162 ++++++++++++++++++++++++++++++++++++++++++++------ gold/readsyms.h | 16 ++++- gold/script.cc | 2 +- 16 files changed, 748 insertions(+), 70 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index aa933e5..f3d475a 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,54 @@ +2010-03-22 Rafael Espindola + + * archive.cc (Should_include): Move to archive.h. + (should_include_member): Make it a member of Archive. + (Lib_group): New. + (Add_lib_group_symbols): New. + * archive.h: Include options.h. + (Archive_member): Moved from Archive. + (Should_include): Moved from archive.cc. + (Lib_group): New. + (Add_lib_group_symbols): New. + * dynobj.cc (do_should_include_member): New. + * dynobj.h (do_should_include_member): New. + * gold.cc (queue_initial_tasks): Update call to queue. + * main.cc (main): Print lib group stats. + * object.cc (do_should_include_member): New. + * object.h: Include archive.h. + (Object::should_include_member): New. + (Object::do_should_include_member): New. + (Sized_relobj::do_should_include_member): New. + * options.cc (General_options::parse_start_lib): New. + (General_options::parse_end_lib): New. + (Input_arguments::add_file): Handle lib groups. + (Input_arguments::start_group): Check we are not in a lib. + (Input_arguments::start_lib): New. + (Input_arguments::end_lib): New. + * options.h (General_options): Add start_lib and end_lib. + (Input_argument::lib_): New. + (Input_argument::lib): New. + (Input_argument::is_lib): New. + (Input_file_lib): New. + (Input_arguments::in_lib_): New. + (Input_arguments::in_lib): New. + (Input_arguments::start_lib): New. + (Input_arguments::end_lib_): New. + * plugin.cc (Pluginobj::get_symbol_resolution_info): Mark symbols + in unused members as preempted. + (Sized_pluginobj::do_should_include_member): New. + * plugin.h (Sized_pluginobj::do_should_include_member): New. + * readsyms.cc (Read_symbols::locks): If we are just reading a member, + return the blocker. + (Read_symbols::do_whole_lib_group): New. + (Read_symbols::do_lib_group): New. + (Read_symbols::do_read_symbols): Handle lib groups. + (Read_symbols::get_name): Handle lib groups. + * readsyms.h (Read_symbols): Add an archive member pointer. + (Read_symbols::do_whole_lib_group): New. + (Read_symbols::do_lib_group): New. + (Read_symbols::member_): New. + * script.cc (read_input_script): Update call to queue_soon. + 2010-03-19 Doug Kwan * arm.cc (Stub_table::Stub_table): Initialize new data members diff --git a/gold/archive.cc b/gold/archive.cc index 4411033..c62fb24 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -602,20 +602,10 @@ Archive::read_symbols(off_t off) this->members_[off] = member; } -// When we see a symbol in an archive we might decide to include the member, -// not include the member or be undecided. This enum represents these -// possibilities. - -enum Should_include -{ - SHOULD_INCLUDE_NO, - SHOULD_INCLUDE_YES, - SHOULD_INCLUDE_UNKNOWN -}; - -static Should_include -should_include_member(Symbol_table* symtab, const char* sym_name, Symbol** symp, - std::string* why, char** tmpbufp, size_t* tmpbuflen) +Archive::Should_include +Archive::should_include_member(Symbol_table* symtab, const char* sym_name, + Symbol** symp, std::string* why, char** tmpbufp, + size_t* tmpbuflen) { // In an object file, and therefore in an archive map, an // '@' in the name separates the symbol name from the @@ -659,7 +649,7 @@ should_include_member(Symbol_table* symtab, const char* sym_name, Symbol** symp, { // Check whether the symbol was named in a -u option. if (!parameters->options().is_undefined(sym_name)) - return SHOULD_INCLUDE_UNKNOWN; + return Archive::SHOULD_INCLUDE_UNKNOWN; else { *why = "-u "; @@ -667,11 +657,11 @@ should_include_member(Symbol_table* symtab, const char* sym_name, Symbol** symp, } } else if (!sym->is_undefined()) - return SHOULD_INCLUDE_NO; + return Archive::SHOULD_INCLUDE_NO; else if (sym->binding() == elfcpp::STB_WEAK) - return SHOULD_INCLUDE_UNKNOWN; + return Archive::SHOULD_INCLUDE_UNKNOWN; - return SHOULD_INCLUDE_YES; + return Archive::SHOULD_INCLUDE_YES; } // Select members from the archive and add them to the link. We walk @@ -735,14 +725,15 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, Symbol* sym; std::string why; - Should_include t = should_include_member(symtab, sym_name, - &sym, &why, &tmpbuf, - &tmpbuflen); + Archive::Should_include t = + Archive::should_include_member(symtab, sym_name, &sym, &why, + &tmpbuf, &tmpbuflen); - if (t == SHOULD_INCLUDE_NO || t == SHOULD_INCLUDE_YES) + if (t == Archive::SHOULD_INCLUDE_NO + || t == Archive::SHOULD_INCLUDE_YES) this->armap_checked_[i] = true; - if (t != SHOULD_INCLUDE_YES) + if (t != Archive::SHOULD_INCLUDE_YES) continue; // We want to include this object in the link. @@ -978,4 +969,145 @@ Add_archive_symbols::run(Workqueue* workqueue) } } +// Class Lib_group static variables. +unsigned int Lib_group::total_lib_groups; +unsigned int Lib_group::total_members; +unsigned int Lib_group::total_members_loaded; + +Lib_group::Lib_group(const Input_file_lib* lib, Task* task) + : lib_(lib), task_(task), members_() +{ + this->members_.resize(lib->size()); +} + +// Select members from the lib group and add them to the link. We walk +// through the the members, and check if each one up should be included. +// If the object says it should be included, we do so. We have to do +// this in a loop, since including one member may create new undefined +// symbols which may be satisfied by other members. + +void +Lib_group::add_symbols(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects) +{ + ++Lib_group::total_lib_groups; + + Lib_group::total_members += this->members_.size(); + + bool added_new_object; + do + { + added_new_object = false; + unsigned int i = 0; + while (i < this->members_.size()) + { + const Archive_member& member = this->members_[i]; + Object *obj = member.obj_; + std::string why; + + // Skip files with no symbols. Plugin objects have + // member.sd_ == NULL. + if (obj != NULL + && (member.sd_ == NULL || member.sd_->symbol_names != NULL)) + { + Archive::Should_include t = obj->should_include_member(symtab, + member.sd_, + &why); + + if (t != Archive::SHOULD_INCLUDE_YES) + { + ++i; + continue; + } + + this->include_member(symtab, layout, input_objects, member); + + added_new_object = true; + } + else + { + if (member.sd_ != NULL) + delete member.sd_; + } + + this->members_[i] = this->members_.back(); + this->members_.pop_back(); + } + } + while (added_new_object); +} + +// Include a lib group member in the link. + +void +Lib_group::include_member(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, + const Archive_member& member) +{ + ++Lib_group::total_members_loaded; + + Object* obj = member.obj_; + gold_assert(obj != NULL); + + Pluginobj* pluginobj = obj->pluginobj(); + if (pluginobj != NULL) + { + pluginobj->add_symbols(symtab, NULL, layout); + return; + } + + Read_symbols_data* sd = member.sd_; + gold_assert(sd != NULL); + obj->lock(this->task_); + if (input_objects->add_object(obj)) + { + obj->layout(symtab, layout, sd); + obj->add_symbols(symtab, sd, layout); + // Unlock the file for the next task. + obj->unlock(this->task_); + } + delete sd; +} + +// Print statistical information to stderr. This is used for --stats. + +void +Lib_group::print_stats() +{ + fprintf(stderr, _("%s: lib groups: %u\n"), + program_name, Lib_group::total_lib_groups); + fprintf(stderr, _("%s: total lib groups members: %u\n"), + program_name, Lib_group::total_members); + fprintf(stderr, _("%s: loaded lib groups members: %u\n"), + program_name, Lib_group::total_members_loaded); +} + +Task_token* +Add_lib_group_symbols::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Add_lib_group_symbols::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); +} + +void +Add_lib_group_symbols::run(Workqueue*) +{ + this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_); +} + +Add_lib_group_symbols::~Add_lib_group_symbols() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the next + // input file. +} + } // End namespace gold. diff --git a/gold/archive.h b/gold/archive.h index 7f567b7..a2d2af4 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -41,6 +41,22 @@ class Layout; class Symbol_table; class Object; class Read_symbols_data; +class Input_file_lib; + +// An entry in the archive map of offsets to members. +struct Archive_member +{ + Archive_member() + : obj_(NULL), sd_(NULL) + { } + Archive_member(Object* obj, Read_symbols_data* sd) + : obj_(obj), sd_(sd) + { } + // The object file. + Object* obj_; + // The data to pass from read_symbols() to add_symbols(). + Read_symbols_data* sd_; +}; // This class represents an archive--generally a libNAME.a file. // Archives have a symbol table and a list of objects. @@ -148,6 +164,22 @@ class Archive no_export() { return this->no_export_; } + // When we see a symbol in an archive we might decide to include the member, + // not include the member or be undecided. This enum represents these + // possibilities. + + enum Should_include + { + SHOULD_INCLUDE_NO, + SHOULD_INCLUDE_YES, + SHOULD_INCLUDE_UNKNOWN + }; + + static Should_include + should_include_member(Symbol_table* symtab, const char* sym_name, + Symbol** symp, std::string* why, char** tmpbufp, + size_t* tmpbuflen); + private: Archive(const Archive&); Archive& operator=(const Archive&); @@ -238,21 +270,6 @@ class Archive off_t file_offset; }; - // An entry in the archive map of offsets to members. - struct Archive_member - { - Archive_member() - : obj_(NULL), sd_(NULL) - { } - Archive_member(Object* obj, Read_symbols_data* sd) - : obj_(obj), sd_(sd) - { } - // The object file. - Object* obj_; - // The data to pass from read_symbols() to add_symbols(). - Read_symbols_data* sd_; - }; - // A simple hash code for off_t values. class Seen_hash { @@ -352,6 +369,95 @@ class Add_archive_symbols : public Task Task_token* next_blocker_; }; +// This class represents the files surrunded by a --start-lib ... --end-lib. + +class Lib_group +{ + public: + Lib_group(const Input_file_lib* lib, Task* task); + + // Select members from the lib group as needed and add them to the link. + void + add_symbols(Symbol_table*, Layout*, Input_objects*); + + // Include a member of the lib group in the link. + void + include_member(Symbol_table*, Layout*, Input_objects*, const Archive_member&); + + Archive_member* + get_member(int i) + { + return &this->members_[i]; + } + + // Dump statistical information to stderr. + static void + print_stats(); + + // Total number of archives seen. + static unsigned int total_lib_groups; + // Total number of archive members seen. + static unsigned int total_members; + // Number of archive members loaded. + static unsigned int total_members_loaded; + + private: + // For reading the files. + const Input_file_lib* lib_; + // The task reading this lib group. + Task *task_; + // Table of the objects in the group. + std::vector members_; +}; + +// This class is used to pick out the desired elements and add them to the link. + +class Add_lib_group_symbols : public Task +{ + public: + Add_lib_group_symbols(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, + Lib_group* lib, Task_token* next_blocker) + : symtab_(symtab), layout_(layout), input_objects_(input_objects), + lib_(lib), this_blocker_(NULL), next_blocker_(next_blocker) + { } + + ~Add_lib_group_symbols(); + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + // Set the blocker to use for this task. + void + set_blocker(Task_token* this_blocker) + { + gold_assert(this->this_blocker_ == NULL); + this->this_blocker_ = this_blocker; + } + + std::string + get_name() const + { + return "Add_lib_group_symbols"; + } + + private: + Symbol_table* symtab_; + Layout* layout_; + Input_objects* input_objects_; + Lib_group * lib_; + Task_token* this_blocker_; + Task_token* next_blocker_; +}; + } // End namespace gold. #endif // !defined(GOLD_ARCHIVE_H) diff --git a/gold/dynobj.cc b/gold/dynobj.cc index fca9bbd..81bc085 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -751,6 +751,14 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, this->clear_view_cache_marks(); } +template +Archive::Should_include +Sized_dynobj::do_should_include_member( + Symbol_table*, Read_symbols_data*, std::string*) +{ + return Archive::SHOULD_INCLUDE_YES; +} + // Get symbol counts. template diff --git a/gold/dynobj.h b/gold/dynobj.h index bc69187..08cf78d 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -177,6 +177,10 @@ class Sized_dynobj : public Dynobj void do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + std::string* why); + // Get the size of a section. uint64_t do_section_size(unsigned int shndx) diff --git a/gold/gold.cc b/gold/gold.cc index 5450573..aa7689f 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -206,7 +206,7 @@ queue_initial_tasks(const General_options& options, next_blocker->add_blocker(); workqueue->queue(new Read_symbols(input_objects, symtab, layout, &search_path, 0, mapfile, &*p, NULL, - this_blocker, next_blocker)); + NULL, this_blocker, next_blocker)); this_blocker = next_blocker; } diff --git a/gold/main.cc b/gold/main.cc index 9be4972..e3df9c0 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -264,6 +264,7 @@ main(int argc, char** argv) #endif File_read::print_stats(); Archive::print_stats(); + Lib_group::print_stats(); fprintf(stderr, _("%s: output file size: %lld bytes\n"), program_name, static_cast(layout.output_file_size())); symtab.print_stats(); diff --git a/gold/object.cc b/gold/object.cc index 73bf370..b9d0028 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1486,6 +1486,55 @@ Sized_relobj::do_add_symbols(Symbol_table* symtab, sd->symbol_names = NULL; } +// Find out if this object, that is a member of a lib group, should be included +// in the link. We check every symbol defined by this object. If the symbol +// table has a strong undefined reference to that symbol, we have to include +// the object. + +template +Archive::Should_include +Sized_relobj::do_should_include_member(Symbol_table* symtab, + Read_symbols_data* sd, + std::string* why) +{ + char* tmpbuf = NULL; + size_t tmpbuflen = 0; + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + const unsigned char* syms = + sd->symbols->data() + sd->external_symbols_offset; + const int sym_size = elfcpp::Elf_sizes::sym_size; + size_t symcount = ((sd->symbols_size - sd->external_symbols_offset) + / sym_size); + + const unsigned char* p = syms; + + for (size_t i = 0; i < symcount; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + unsigned int st_shndx = sym.get_st_shndx(); + if (st_shndx == elfcpp::SHN_UNDEF) + continue; + + unsigned int st_name = sym.get_st_name(); + const char* name = sym_names + st_name; + Symbol* symbol; + Archive::Should_include t = Archive::should_include_member(symtab, name, + &symbol, why, + &tmpbuf, + &tmpbuflen); + if (t == Archive::SHOULD_INCLUDE_YES) + { + if (tmpbuf != NULL) + free(tmpbuf); + return t; + } + } + if (tmpbuf != NULL) + free(tmpbuf); + return Archive::SHOULD_INCLUDE_UNKNOWN; +} + // First pass over the local symbols. Here we add their names to // *POOL and *DYNPOOL, and we store the symbol value in // THIS->LOCAL_VALUES_. This function is always called from a diff --git a/gold/object.h b/gold/object.h index 59da7c1..dc0cb2d 100644 --- a/gold/object.h +++ b/gold/object.h @@ -30,6 +30,7 @@ #include "elfcpp_file.h" #include "fileread.h" #include "target.h" +#include "archive.h" namespace gold { @@ -37,7 +38,6 @@ namespace gold class General_options; class Task; class Cref; -class Archive; class Layout; class Output_section; class Output_file; @@ -382,6 +382,12 @@ class Object add_symbols(Symbol_table* symtab, Read_symbols_data* sd, Layout *layout) { this->do_add_symbols(symtab, sd, layout); } + // Add symbol information to the global symbol table. + Archive::Should_include + should_include_member(Symbol_table* symtab, Read_symbols_data* sd, + std::string* why) + { return this->do_should_include_member(symtab, sd, why); } + // Functions and types for the elfcpp::Elf_file interface. This // permit us to use Object as the File template parameter for // elfcpp::Elf_file. @@ -511,6 +517,10 @@ class Object virtual void do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) = 0; + virtual Archive::Should_include + do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + std::string* why) = 0; + // Return the location of the contents of a section. Implemented by // child class. virtual Location @@ -1574,6 +1584,10 @@ class Sized_relobj : public Relobj void do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + std::string* why); + // Read the relocs. void do_read_relocs(Read_relocs_data*); diff --git a/gold/options.cc b/gold/options.cc index c6c8073..0eb38ad 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -499,6 +499,20 @@ General_options::parse_end_group(const char*, const char*, cmdline->inputs().end_group(); } +void +General_options::parse_start_lib(const char*, const char*, + Command_line* cmdline) +{ + cmdline->inputs().start_lib(cmdline->position_dependent_options()); +} + +void +General_options::parse_end_lib(const char*, const char*, + Command_line* cmdline) +{ + cmdline->inputs().end_lib(); +} + // The function add_excluded_libs() in ld/ldlang.c of GNU ld breaks up a list // of names seperated by commas or colons and puts them in a linked list. // We implement the same parsing of names here but store names in an unordered @@ -1161,14 +1175,20 @@ Search_directory::add_sysroot(const char* sysroot, void Input_arguments::add_file(const Input_file_argument& file) { - if (!this->in_group_) - this->input_argument_list_.push_back(Input_argument(file)); - else + if (this->in_group_) { gold_assert(!this->input_argument_list_.empty()); gold_assert(this->input_argument_list_.back().is_group()); this->input_argument_list_.back().group()->add_file(file); } + else if (this->in_lib_) + { + gold_assert(!this->input_argument_list_.empty()); + gold_assert(this->input_argument_list_.back().is_lib()); + this->input_argument_list_.back().lib()->add_file(file); + } + else + this->input_argument_list_.push_back(Input_argument(file)); } // Start a group. @@ -1178,6 +1198,8 @@ Input_arguments::start_group() { if (this->in_group_) gold_fatal(_("May not nest groups")); + if (this->in_lib_) + gold_fatal(_("may not nest groups in libraries")); Input_file_group* group = new Input_file_group(); this->input_argument_list_.push_back(Input_argument(group)); this->in_group_ = true; @@ -1193,6 +1215,30 @@ Input_arguments::end_group() this->in_group_ = false; } +// Start a lib. + +void +Input_arguments::start_lib(const Position_dependent_options& options) +{ + if (this->in_lib_) + gold_fatal(_("may not nest libraries")); + if (this->in_group_) + gold_fatal(_("may not nest libraries in groups")); + Input_file_lib* lib = new Input_file_lib(options); + this->input_argument_list_.push_back(Input_argument(lib)); + this->in_lib_ = true; +} + +// End a lib. + +void +Input_arguments::end_lib() +{ + if (!this->in_lib_) + gold_fatal(_("lib end without lib start")); + this->in_lib_ = false; +} + // Command_line options. Command_line::Command_line() diff --git a/gold/options.h b/gold/options.h index b725b04..3a234d0 100644 --- a/gold/options.h +++ b/gold/options.h @@ -53,6 +53,7 @@ class Command_line; class General_options; class Search_directory; class Input_file_group; +class Input_file_lib; class Position_dependent_options; class Target; class Plugin_manager; @@ -1033,6 +1034,12 @@ class General_options DEFINE_special(end_group, options::TWO_DASHES, ')', N_("End a library search group"), NULL); + + DEFINE_special(start_lib, options::TWO_DASHES, '\0', + N_("Start a library"), NULL); + DEFINE_special(end_lib, options::TWO_DASHES, '\0', + N_("End a library "), NULL); + // The -z options. DEFINE_bool(combreloc, options::DASH_Z, '\0', true, @@ -1500,12 +1507,17 @@ class Input_argument public: // Create a file or library argument. explicit Input_argument(Input_file_argument file) - : is_file_(true), file_(file), group_(NULL) + : is_file_(true), file_(file), group_(NULL), lib_(NULL) { } // Create a group argument. explicit Input_argument(Input_file_group* group) - : is_file_(false), group_(group) + : is_file_(false), group_(group), lib_(NULL) + { } + + // Create a lib argument. + explicit Input_argument(Input_file_lib* lib) + : is_file_(false), group_(NULL), lib_(lib) { } // Return whether this is a file. @@ -1516,7 +1528,12 @@ class Input_argument // Return whether this is a group. bool is_group() const - { return !this->is_file_; } + { return !this->is_file_ && this->lib_ == NULL; } + + // Return whether this is a lib. + bool + is_lib() const + { return this->lib_ != NULL; } // Return the information about the file. const Input_file_argument& @@ -1541,10 +1558,28 @@ class Input_argument return this->group_; } + // Return the information about the lib. + const Input_file_lib* + lib() const + { + gold_assert(!this->is_file_); + gold_assert(this->lib_); + return this->lib_; + } + + Input_file_lib* + lib() + { + gold_assert(!this->is_file_); + gold_assert(this->lib_); + return this->lib_; + } + private: bool is_file_; Input_file_argument file_; Input_file_group* group_; + Input_file_lib* lib_; }; typedef std::vector Input_argument_list; @@ -1580,6 +1615,46 @@ class Input_file_group Input_argument_list files_; }; +// A lib from the command line. This is a set of arguments within +// --start-lib ... --end-lib. + +class Input_file_lib +{ + public: + typedef Input_argument_list::const_iterator const_iterator; + + Input_file_lib(const Position_dependent_options& options) + : files_(), options_(options) + { } + + // Add a file to the end of the lib. + void + add_file(const Input_file_argument& arg) + { this->files_.push_back(Input_argument(arg)); } + + const Position_dependent_options& + options() const + { return this->options_; } + + // Iterators to iterate over the lib contents. + + const_iterator + begin() const + { return this->files_.begin(); } + + const_iterator + end() const + { return this->files_.end(); } + + size_t + size() const + { return this->files_.size(); } + + private: + Input_argument_list files_; + Position_dependent_options options_; +}; + // A list of files from the command line or a script. class Input_arguments @@ -1588,7 +1663,7 @@ class Input_arguments typedef Input_argument_list::const_iterator const_iterator; Input_arguments() - : input_argument_list_(), in_group_(false) + : input_argument_list_(), in_group_(false), in_lib_(false) { } // Add a file. @@ -1603,11 +1678,24 @@ class Input_arguments void end_group(); + // Start a lib (the --start-lib option). + void + start_lib(const Position_dependent_options&); + + // End a lib (the --end-lib option). + void + end_lib(); + // Return whether we are currently in a group. bool in_group() const { return this->in_group_; } + // Return whether we are currently in a lib. + bool + in_lib() const + { return this->in_lib_; } + // The number of entries in the list. int size() const @@ -1631,6 +1719,7 @@ class Input_arguments private: Input_argument_list input_argument_list_; bool in_group_; + bool in_lib_; }; diff --git a/gold/plugin.cc b/gold/plugin.cc index 2831c2b..d9b4c59 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -438,6 +438,7 @@ Plugin_manager::add_input_file(char *pathname, bool is_lib) this->mapfile_, input_argument, NULL, + NULL, this->this_blocker_, next_blocker)); this->this_blocker_ = next_blocker; @@ -475,6 +476,17 @@ Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const { if (nsyms > this->nsyms_) return LDPS_NO_SYMS; + + if (static_cast(nsyms) > this->symbols_.size()) + { + // We never decided to include this object. We mark all symbols as + // preempted. + gold_assert (this->symbols_.size() == 0); + for (int i = 0; i < nsyms; i++) + syms[i].resolution = LDPR_PREEMPTED_REG; + return LDPS_OK; + } + for (int i = 0; i < nsyms; i++) { ld_plugin_symbol* isym = &syms[i]; @@ -662,6 +674,34 @@ Sized_pluginobj::do_add_symbols(Symbol_table* symtab, } } +template +Archive::Should_include +Sized_pluginobj::do_should_include_member( + Symbol_table* symtab, Read_symbols_data*, std::string* why) +{ + char* tmpbuf = NULL; + size_t tmpbuflen = 0; + + for (int i = 0; i < this->nsyms_; ++i) { + const struct ld_plugin_symbol& sym = this->syms_[i]; + const char* name = sym.name; + Symbol* symbol; + Archive::Should_include t = Archive::should_include_member(symtab, name, + &symbol, why, + &tmpbuf, + &tmpbuflen); + if (t == Archive::SHOULD_INCLUDE_YES) + { + if (tmpbuf != NULL) + free(tmpbuf); + return t; + } + } + if (tmpbuf != NULL) + free(tmpbuf); + return Archive::SHOULD_INCLUDE_UNKNOWN; +} + // Get the size of a section. Not used for plugin objects. template diff --git a/gold/plugin.h b/gold/plugin.h index 635ed6f..c6371ea 100644 --- a/gold/plugin.h +++ b/gold/plugin.h @@ -367,6 +367,10 @@ class Sized_pluginobj : public Pluginobj void do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + std::string* why); + // Get the size of a section. uint64_t do_section_size(unsigned int shndx); diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 980e0af..d8af99b 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -127,7 +127,7 @@ Read_symbols::requeue(Workqueue* workqueue, Input_objects* input_objects, workqueue->queue(new Read_symbols(input_objects, symtab, layout, dirpath, dirindex, mapfile, input_argument, - input_group, NULL, next_blocker)); + input_group, NULL, NULL, next_blocker)); } // Return whether a Read_symbols task is runnable. We can read an @@ -149,8 +149,10 @@ Read_symbols::is_runnable() // locks here. void -Read_symbols::locks(Task_locker*) +Read_symbols::locks(Task_locker* tl) { + if (this->member_ != NULL) + tl->add(this, this->next_blocker_); } // Run a Read_symbols task. @@ -165,6 +167,93 @@ Read_symbols::run(Workqueue* workqueue) this->next_blocker_)); } +// Handle a whole lib group. Other then collecting statisticts, this just +// mimics what we do for regular object files in the command line. + +bool +Read_symbols::do_whole_lib_group(Workqueue* workqueue) +{ + const Input_file_lib* lib_group = this->input_argument_->lib(); + + ++Lib_group::total_lib_groups; + + Task_token* this_blocker = this->this_blocker_; + for (Input_file_lib::const_iterator i = lib_group->begin(); + i != lib_group->end(); + ++i) + { + ++Lib_group::total_members; + ++Lib_group::total_members_loaded; + + const Input_argument* arg = &*i; + + Task_token* next_blocker; + if (i != lib_group->end() - 1) + { + next_blocker = new Task_token(true); + next_blocker->add_blocker(); + } + else + next_blocker = this->next_blocker_; + + workqueue->queue_soon(new Read_symbols(this->input_objects_, + this->symtab_, this->layout_, + this->dirpath_, this->dirindex_, + this->mapfile_, arg, NULL, + NULL, this_blocker, next_blocker)); + this_blocker = next_blocker; + } + + return true; +} + +// Handle a lib group. We set Read_symbols Tasks as usual, but have them +// just record the symbol data instead of adding the objects. We also start +// a Add_lib_group_symbols Task which runs after we've read all the symbols. +// In that task we process the members in a loop until we are done. + +bool +Read_symbols::do_lib_group(Workqueue* workqueue) +{ + const Input_file_lib* lib_group = this->input_argument_->lib(); + + if (lib_group->options().whole_archive()) + return this->do_whole_lib_group(workqueue); + + Lib_group* lib = new Lib_group(lib_group, this); + + Add_lib_group_symbols* add_lib_group_symbols = + new Add_lib_group_symbols(this->symtab_, this->layout_, + this->input_objects_, + lib, this->next_blocker_); + + + Task_token* next_blocker = new Task_token(true); + int j = 0; + for (Input_file_lib::const_iterator i = lib_group->begin(); + i != lib_group->end(); + ++i, ++j) + { + const Input_argument* arg = &*i; + Archive_member* m = lib->get_member(j); + + next_blocker->add_blocker(); + + // Since this Read_symbols will not create an Add_symbols, + // just pass NULL as this_blocker. + workqueue->queue_soon(new Read_symbols(this->input_objects_, + this->symtab_, this->layout_, + this->dirpath_, this->dirindex_, + this->mapfile_, arg, NULL, + m, NULL, next_blocker)); + } + + add_lib_group_symbols->set_blocker(next_blocker); + workqueue->queue_soon(add_lib_group_symbols); + + return true; +} + // Open the file and read the symbols. Return true if a new task was // queued, false if that could not happen due to some error. @@ -178,6 +267,9 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) return true; } + if (this->input_argument_->is_lib()) + return this->do_lib_group(workqueue); + Input_file* input_file = new Input_file(&this->input_argument_->file()); if (!input_file->open(*this->dirpath_, this, &this->dirindex_)) return false; @@ -212,7 +304,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) if (this->layout_->incremental_inputs()) { - const Input_argument* ia = this->input_argument_; + const Input_argument* ia = this->input_argument_; this->layout_->incremental_inputs()->report_archive(ia, arch); } @@ -246,6 +338,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) // We are done with the file at this point, so unlock it. obj->unlock(this); + if (this->member_ != NULL) + { + this->member_->sd_ = NULL; + this->member_->obj_ = obj; + return true; + } + workqueue->queue_next(new Add_symbols(this->input_objects_, this->symtab_, this->layout_, @@ -306,6 +405,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) input_file->file().unlock(this); + if (this->member_ != NULL) + { + this->member_->sd_ = sd; + this->member_->obj_ = obj; + return true; + } + // We use queue_next because everything is cached for this // task to run right away if possible. @@ -384,7 +490,7 @@ Read_symbols::do_group(Workqueue* workqueue) this->symtab_, this->layout_, this->dirpath_, this->dirindex_, this->mapfile_, arg, input_group, - this_blocker, next_blocker)); + NULL, this_blocker, next_blocker)); this_blocker = next_blocker; } @@ -398,7 +504,39 @@ Read_symbols::do_group(Workqueue* workqueue) std::string Read_symbols::get_name() const { - if (!this->input_argument_->is_group()) + if (this->input_argument_->is_group()) + { + std::string ret("Read_symbols group ("); + bool add_space = false; + const Input_file_group* group = this->input_argument_->group(); + for (Input_file_group::const_iterator p = group->begin(); + p != group->end(); + ++p) + { + if (add_space) + ret += ' '; + ret += p->file().name(); + add_space = true; + } + return ret + ')'; + } + else if (this->input_argument_->is_lib()) + { + std::string ret("Read_symbols lib ("); + bool add_space = false; + const Input_file_lib* lib = this->input_argument_->lib(); + for (Input_file_lib::const_iterator p = lib->begin(); + p != lib->end(); + ++p) + { + if (add_space) + ret += ' '; + ret += p->file().name(); + add_space = true; + } + return ret + ')'; + } + else { std::string ret("Read_symbols "); if (this->input_argument_->file().is_lib()) @@ -408,20 +546,6 @@ Read_symbols::get_name() const ret += this->input_argument_->file().name(); return ret; } - - std::string ret("Read_symbols group ("); - bool add_space = false; - const Input_file_group* group = this->input_argument_->group(); - for (Input_file_group::const_iterator p = group->begin(); - p != group->end(); - ++p) - { - if (add_space) - ret += ' '; - ret += p->file().name(); - add_space = true; - } - return ret + ')'; } // Class Add_symbols. diff --git a/gold/readsyms.h b/gold/readsyms.h index 4956a82..bc4f38f 100644 --- a/gold/readsyms.h +++ b/gold/readsyms.h @@ -58,12 +58,13 @@ class Read_symbols : public Task Read_symbols(Input_objects* input_objects, Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, int dirindex, Mapfile* mapfile, const Input_argument* input_argument, - Input_group* input_group, Task_token* this_blocker, - Task_token* next_blocker) + Input_group* input_group, Archive_member* member, + Task_token* this_blocker, Task_token* next_blocker) : input_objects_(input_objects), symtab_(symtab), layout_(layout), dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile), input_argument_(input_argument), input_group_(input_group), - this_blocker_(this_blocker), next_blocker_(next_blocker) + member_(member), this_blocker_(this_blocker), + next_blocker_(next_blocker) { } ~Read_symbols(); @@ -99,6 +100,14 @@ class Read_symbols : public Task void do_group(Workqueue*); + // Handle --start-lib ... --end-lib + bool + do_lib_group(Workqueue*); + + // Handle --whole-archive --start-lib ... --end-lib --no-whole-archive + bool + do_whole_lib_group(Workqueue*); + // Open and identify the file. bool do_read_symbols(Workqueue*); @@ -111,6 +120,7 @@ class Read_symbols : public Task Mapfile* mapfile_; const Input_argument* input_argument_; Input_group* input_group_; + Archive_member* member_; Task_token* this_blocker_; Task_token* next_blocker_; }; diff --git a/gold/script.cc b/gold/script.cc index a11672c..bef0cdb 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -1438,7 +1438,7 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout, } workqueue->queue_soon(new Read_symbols(input_objects, symtab, layout, dirsearch, 0, mapfile, &*p, - input_group, this_blocker, nb)); + input_group, NULL, this_blocker, nb)); this_blocker = nb; } -- 2.7.4