X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Farchive.cc;h=3922860685f7f366ded83abef263d1933fa7a0b4;hb=1b61f46da5e55bf2df243215f34ffbca4bcf6d9e;hp=73fa6767ba9e838ce086025efe32c53398c28ee9;hpb=15f8229bbf3f6fff866cbc04b07ddde9f6e41941;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/archive.cc b/gold/archive.cc index 73fa6767ba..3922860685 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -1,6 +1,6 @@ // archive.cc -- archive support for gold -// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +// Copyright (C) 2006-2019 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -36,14 +36,124 @@ #include "readsyms.h" #include "symtab.h" #include "object.h" +#include "layout.h" #include "archive.h" #include "plugin.h" +#include "incremental.h" namespace gold { +// Library_base methods. + +// Determine whether a definition of SYM_NAME should cause an archive +// library member to be included in the link. Returns SHOULD_INCLUDE_YES +// if the symbol is referenced but not defined, SHOULD_INCLUDE_NO if the +// symbol is already defined, and SHOULD_INCLUDE_UNKNOWN if the symbol is +// neither referenced nor defined. + +Library_base::Should_include +Library_base::should_include_member(Symbol_table* symtab, Layout* layout, + 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 + // version name. If there are two '@' characters, this is + // the default version. + char* tmpbuf = *tmpbufp; + const char* ver = strchr(sym_name, '@'); + bool def = false; + if (ver != NULL) + { + size_t symlen = ver - sym_name; + if (symlen + 1 > *tmpbuflen) + { + tmpbuf = static_cast(xrealloc(tmpbuf, symlen + 1)); + *tmpbufp = tmpbuf; + *tmpbuflen = symlen + 1; + } + memcpy(tmpbuf, sym_name, symlen); + tmpbuf[symlen] = '\0'; + sym_name = tmpbuf; + + ++ver; + if (*ver == '@') + { + ++ver; + def = true; + } + } + + Symbol* sym = symtab->lookup(sym_name, ver); + if (def + && ver != NULL + && (sym == NULL + || !sym->is_undefined() + || sym->binding() == elfcpp::STB_WEAK)) + sym = symtab->lookup(sym_name, NULL); + + *symp = sym; + + if (sym != NULL) + { + if (!sym->is_undefined()) + return Library_base::SHOULD_INCLUDE_NO; + + // PR 12001: Do not include an archive when the undefined + // symbol has actually been defined on the command line. + if (layout->script_options()->is_pending_assignment(sym_name)) + return Library_base::SHOULD_INCLUDE_NO; + + // If the symbol is weak undefined, we still need to check + // for other reasons (like a -u option). + if (sym->binding() != elfcpp::STB_WEAK) + return Library_base::SHOULD_INCLUDE_YES; + } + + // Check whether the symbol was named in a -u option. + if (parameters->options().is_undefined(sym_name)) + { + *why = "-u "; + *why += sym_name; + return Library_base::SHOULD_INCLUDE_YES; + } + + if (parameters->options().is_export_dynamic_symbol(sym_name)) + { + *why = "--export-dynamic-symbol "; + *why += sym_name; + return Library_base::SHOULD_INCLUDE_YES; + } + + if (layout->script_options()->is_referenced(sym_name)) + { + size_t alc = 100 + strlen(sym_name); + char* buf = new char[alc]; + snprintf(buf, alc, _("script or expression reference to %s"), + sym_name); + *why = buf; + delete[] buf; + return Library_base::SHOULD_INCLUDE_YES; + } + + if (!parameters->options().relocatable()) + { + const char* entry_sym = parameters->entry(); + if (entry_sym != NULL && strcmp(sym_name, entry_sym) == 0) + { + *why = "entry symbol "; + *why += sym_name; + return Library_base::SHOULD_INCLUDE_YES; + } + } + + return Library_base::SHOULD_INCLUDE_UNKNOWN; +} + // The header of an entry in the archive. This is all readable text, -// padded with spaces where necesary. If the contents of an archive +// padded with spaces where necessary. If the contents of an archive // are all text file, the entire archive is readable. struct Archive::Archive_header @@ -83,6 +193,20 @@ const char Archive::armagt[sarmag] = const char Archive::arfmag[2] = { '`', '\n' }; +const char Archive::sym64name[7] = { '/', 'S', 'Y', 'M', '6', '4', '/' }; + +Archive::Archive(const std::string& name, Input_file* input_file, + bool is_thin_archive, Dirsearch* dirpath, Task* task) + : Library_base(task), name_(name), input_file_(input_file), armap_(), + armap_names_(), extended_names_(), armap_checked_(), seen_offsets_(), + members_(), is_thin_archive_(is_thin_archive), included_member_(false), + nested_archives_(), dirpath_(dirpath), num_members_(0), + included_all_members_(false) +{ + this->no_export_ = + parameters->options().check_excluded_libs(input_file->found_name()); +} + // Set up the archive: read the symbol map and the extended name // table. @@ -95,13 +219,20 @@ Archive::setup() // The first member of the archive should be the symbol table. std::string armap_name; - section_size_type armap_size = - convert_to_section_size_type(this->read_header(sarmag, false, - &armap_name, NULL)); + off_t header_size = this->read_header(sarmag, false, &armap_name, NULL); + if (header_size == -1) + return; + + section_size_type armap_size = convert_to_section_size_type(header_size); off_t off = sarmag; if (armap_name.empty()) { - this->read_armap(sarmag + sizeof(Archive_header), armap_size); + this->read_armap<32>(sarmag + sizeof(Archive_header), armap_size); + off = sarmag + sizeof(Archive_header) + armap_size; + } + else if (armap_name == "/SYM64/") + { + this->read_armap<64>(sarmag + sizeof(Archive_header), armap_size); off = sarmag + sizeof(Archive_header) + armap_size; } else if (!this->input_file_->options().whole_archive()) @@ -114,8 +245,11 @@ Archive::setup() if ((off & 1) != 0) ++off; std::string xname; - section_size_type extended_size = - convert_to_section_size_type(this->read_header(off, true, &xname, NULL)); + header_size = this->read_header(off, true, &xname, NULL); + if (header_size == -1) + return; + + section_size_type extended_size = convert_to_section_size_type(header_size); if (xname == "/") { const unsigned char* p = this->get_view(off + sizeof(Archive_header), @@ -150,6 +284,7 @@ Archive::unlock_nested_archives() // Read the archive symbol map. +template void Archive::read_armap(off_t start, section_size_type size) { @@ -163,8 +298,10 @@ Archive::read_armap(off_t start, section_size_type size) const unsigned char* p = this->get_view(start, size, true, false); // Numbers in the armap are always big-endian. - const elfcpp::Elf_Word* pword = reinterpret_cast(p); - unsigned int nsyms = elfcpp::Swap<32, true>::readval(pword); + typedef typename elfcpp::Elf_types::Elf_Addr Entry_type; + const Entry_type* pword = reinterpret_cast(p); + unsigned long nsyms = convert_types( + elfcpp::Swap::readval(pword)); ++pword; // Note that the addition is in units of sizeof(elfcpp::Elf_Word). @@ -176,10 +313,11 @@ Archive::read_armap(off_t start, section_size_type size) this->armap_.resize(nsyms); section_offset_type name_offset = 0; - for (unsigned int i = 0; i < nsyms; ++i) + for (unsigned long i = 0; i < nsyms; ++i) { this->armap_[i].name_offset = name_offset; - this->armap_[i].file_offset = elfcpp::Swap<32, true>::readval(pword); + this->armap_[i].file_offset = convert_types( + elfcpp::Swap::readval(pword)); name_offset += strlen(pnames + name_offset) + 1; ++pword; if (this->armap_[i].file_offset != last_seen_offset) @@ -213,8 +351,8 @@ Archive::read_header(off_t off, bool cache, std::string* pname, } // Interpret the header of HDR, the header of the archive member at -// file offset OFF. Fail if something goes wrong. Return the size of -// the member. Set *PNAME to the name of the member. +// file offset OFF. Return the size of the member, or -1 if something +// has gone wrong. Set *PNAME to the name of the member. off_t Archive::interpret_header(const Archive_header* hdr, off_t off, @@ -224,7 +362,7 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, { gold_error(_("%s: malformed archive header at %zu"), this->name().c_str(), static_cast(off)); - return this->input_file_->file().filesize() - off; + return -1; } const int size_string_size = sizeof hdr->ar_size; @@ -244,7 +382,7 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, { gold_error(_("%s: malformed archive header size at %zu"), this->name().c_str(), static_cast(off)); - return this->input_file_->file().filesize() - off; + return -1; } if (hdr->ar_name[0] != '/') @@ -255,7 +393,7 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, { gold_error(_("%s: malformed archive header name at %zu"), this->name().c_str(), static_cast(off)); - return this->input_file_->file().filesize() - off; + return -1; } pname->assign(hdr->ar_name, name_end - hdr->ar_name); if (nested_off != NULL) @@ -264,7 +402,13 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, else if (hdr->ar_name[1] == ' ') { // This is the symbol table. - pname->clear(); + if (!pname->empty()) + pname->clear(); + } + else if (memcmp(hdr->ar_name, sym64name, sizeof sym64name) == 0) + { + // This is the symbol table, 64-bit version. + pname->assign(sym64name, sizeof sym64name); } else if (hdr->ar_name[1] == '/') { @@ -285,7 +429,7 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, { gold_error(_("%s: bad extended name index at %zu"), this->name().c_str(), static_cast(off)); - return this->input_file_->file().filesize() - off; + return -1; } const char* name = this->extended_names_.data() + x; @@ -295,7 +439,7 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, { gold_error(_("%s: bad extended name entry at header %zu"), this->name().c_str(), static_cast(off)); - return this->input_file_->file().filesize() - off; + return -1; } pname->assign(name, name_end - 1 - name); if (nested_off != NULL) @@ -403,13 +547,22 @@ Archive::const_iterator::read_next_header() this->archive_->file().read(this->off_, sizeof(Archive_header), buf); const Archive_header* hdr = reinterpret_cast(buf); - this->header_.size = - this->archive_->interpret_header(hdr, this->off_, &this->header_.name, - &this->header_.nested_off); + off_t size = this->archive_->interpret_header(hdr, this->off_, + &this->header_.name, + &this->header_.nested_off); + if (size == -1) + { + this->header_.off = filesize; + return; + } + + this->header_.size = size; this->header_.off = this->off_; // Skip special members. - if (!this->header_.name.empty() && this->header_.name != "/") + if (!this->header_.name.empty() + && this->header_.name != "/" + && this->header_.name != "/SYM64/") return; this->off_ += sizeof(Archive_header) + this->header_.size; @@ -447,6 +600,8 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, off_t nested_off; *memsize = this->read_header(off, false, member_name, &nested_off); + if (*memsize == -1) + return false; *input_file = this->input_file_; *memoff = off + static_cast(sizeof(Archive_header)); @@ -478,8 +633,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, else { Input_file_argument* input_file_arg = - new Input_file_argument(member_name->c_str(), false, "", false, - parameters->options()); + new Input_file_argument(member_name->c_str(), + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, parameters->options()); *input_file = new Input_file(input_file_arg); int dummy = 0; if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy)) @@ -498,8 +654,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, // This is an external member of a thin archive. Open the // file as a regular relocatable object file. Input_file_argument* input_file_arg = - new Input_file_argument(member_name->c_str(), false, "", false, - this->input_file_->options()); + new Input_file_argument(member_name->c_str(), + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, this->input_file_->options()); *input_file = new Input_file(input_file_arg); int dummy = 0; if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy)) @@ -510,14 +667,16 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, return true; } -// Return an ELF object for the member at offset OFF. If the ELF -// object has an unsupported target type, set *PUNCONFIGURED to true -// and return NULL. +// Return an ELF object for the member at offset OFF. If +// PUNCONFIGURED is not NULL, then if the ELF object has an +// unsupported target type, set *PUNCONFIGURED to true and return +// NULL. Object* Archive::get_elf_object_for_member(off_t off, bool* punconfigured) { - *punconfigured = false; + if (punconfigured != NULL) + *punconfigured = false; Input_file* input_file; off_t memoff; @@ -527,50 +686,58 @@ Archive::get_elf_object_for_member(off_t off, bool* punconfigured) &member_name)) return NULL; + const unsigned char* ehdr; + int read_size; + Object *obj = NULL; + bool is_elf_obj = false; + bool unclaimed = false; + + if (is_elf_object(input_file, memoff, &ehdr, &read_size)) + { + obj = make_elf_object((std::string(this->input_file_->filename()) + + "(" + member_name + ")"), + input_file, memoff, ehdr, read_size, + punconfigured); + is_elf_obj = true; + } + if (parameters->options().has_plugins()) { - Object* obj = parameters->options().plugins()->claim_file(input_file, - memoff, - memsize); - if (obj != NULL) + Object* plugin_obj + = parameters->options().plugins()->claim_file(input_file, + memoff, + memsize, + obj); + if (plugin_obj != NULL) { // The input file was claimed by a plugin, and its symbols // have been provided by the plugin. - return obj; + // Delete its elf object. + if (obj != NULL) + delete obj; + return plugin_obj; } - } - - off_t filesize = input_file->file().filesize(); - int read_size = elfcpp::Elf_sizes<64>::ehdr_size; - if (filesize - memoff < read_size) - read_size = filesize - memoff; - if (read_size < 4) - { - gold_error(_("%s: member at %zu is not an ELF object"), - this->name().c_str(), static_cast(off)); - return NULL; + unclaimed = true; } - const unsigned char* ehdr = input_file->file().get_view(memoff, 0, read_size, - true, false); - - static unsigned char elfmagic[4] = + if (!is_elf_obj) { - elfcpp::ELFMAG0, elfcpp::ELFMAG1, - elfcpp::ELFMAG2, elfcpp::ELFMAG3 - }; - if (memcmp(ehdr, elfmagic, 4) != 0) - { - gold_error(_("%s: member at %zu is not an ELF object"), - this->name().c_str(), static_cast(off)); + if (unclaimed) + gold_error(_("%s: plugin failed to claim member %s at %zu"), + this->name().c_str(), member_name.c_str(), + static_cast(off)); + else + gold_error(_("%s: member %s at %zu is not an ELF object"), + this->name().c_str(), member_name.c_str(), + static_cast(off)); return NULL; } - return make_elf_object((std::string(this->input_file_->filename()) - + "(" + member_name + ")"), - input_file, memoff, ehdr, read_size, - punconfigured); + if (obj == NULL) + return NULL; + obj->set_no_export(this->no_export()); + return obj; } // Read the symbols from all the archive members in the link. @@ -590,9 +757,7 @@ Archive::read_all_symbols() void Archive::read_symbols(off_t off) { - bool dummy; - Object* obj = this->get_elf_object_for_member(off, &dummy); - + Object* obj = this->get_elf_object_for_member(off, NULL); if (obj == NULL) return; @@ -635,6 +800,8 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, // Track which symbols in the symbol table we've already found to be // defined. + char* tmpbuf = NULL; + size_t tmpbuflen = 0; bool added_new_object; do { @@ -658,53 +825,95 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, const char* sym_name = (this->armap_names_.data() + this->armap_[i].name_offset); - Symbol* sym = symtab->lookup(sym_name); - if (sym == NULL) - { - // Check whether the symbol was named in a -u option. - if (!parameters->options().is_undefined(sym_name)) - continue; - } - else if (!sym->is_undefined()) - { - this->armap_checked_[i] = true; - continue; - } - else if (sym->binding() == elfcpp::STB_WEAK) + + Symbol* sym; + std::string why; + Archive::Should_include t = + Archive::should_include_member(symtab, layout, sym_name, &sym, + &why, &tmpbuf, &tmpbuflen); + + if (t == Archive::SHOULD_INCLUDE_NO + || t == Archive::SHOULD_INCLUDE_YES) + this->armap_checked_[i] = true; + + if (t != Archive::SHOULD_INCLUDE_YES) continue; // We want to include this object in the link. last_seen_offset = this->armap_[i].file_offset; this->seen_offsets_.insert(last_seen_offset); - this->armap_checked_[i] = true; - std::string why; - if (sym == NULL) - { - why = "-u "; - why += sym_name; - } if (!this->include_member(symtab, layout, input_objects, last_seen_offset, mapfile, sym, why.c_str())) - return false; + { + if (tmpbuf != NULL) + free(tmpbuf); + return false; + } added_new_object = true; } } while (added_new_object); + if (tmpbuf != NULL) + free(tmpbuf); + input_objects->archive_stop(this); return true; } +// Return whether the archive includes a member which defines the +// symbol SYM. + +bool +Archive::defines_symbol(Symbol* sym) const +{ + const char* symname = sym->name(); + size_t symname_len = strlen(symname); + size_t armap_size = this->armap_.size(); + for (size_t i = 0; i < armap_size; ++i) + { + if (this->armap_checked_[i]) + continue; + const char* archive_symname = (this->armap_names_.data() + + this->armap_[i].name_offset); + if (strncmp(archive_symname, symname, symname_len) != 0) + continue; + char c = archive_symname[symname_len]; + if (c == '\0' && sym->version() == NULL) + return true; + if (c == '@') + { + const char* ver = archive_symname + symname_len + 1; + if (*ver == '@') + { + if (sym->version() == NULL) + return true; + ++ver; + } + if (sym->version() != NULL && strcmp(sym->version(), ver) == 0) + return true; + } + } + return false; +} + // Include all the archive members in the link. This is for --whole-archive. bool Archive::include_all_members(Symbol_table* symtab, Layout* layout, Input_objects* input_objects, Mapfile* mapfile) { + // Don't include the same archive twice. This can happen if + // --whole-archive is nested inside --start-group (PR gold/12163). + if (this->included_all_members_) + return true; + + this->included_all_members_ = true; + input_objects->archive_start(this); if (this->members_.size() > 0) @@ -752,6 +961,32 @@ Archive::count_members() return ret; } +// RAII class to ensure we unlock the object if it's a member of a +// thin archive. We can't use Task_lock_obj in Archive::include_member +// because the object file is already locked when it's opened by +// get_elf_object_for_member. + +class Thin_archive_object_unlocker +{ + public: + Thin_archive_object_unlocker(const Task *task, Object* obj) + : task_(task), obj_(obj) + { } + + ~Thin_archive_object_unlocker() + { + if (this->obj_->offset() == 0) + this->obj_->unlock(this->task_); + } + + private: + Thin_archive_object_unlocker(const Thin_archive_object_unlocker&); + Thin_archive_object_unlocker& operator=(const Thin_archive_object_unlocker&); + + const Task* task_; + Object* obj_; +}; + // Include an archive member in the link. OFF is the file offset of // the member header. WHY is the reason we are including this member. // Return true if we added the member or if we had an error, return @@ -768,14 +1003,9 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, std::map::const_iterator p = this->members_.find(off); if (p != this->members_.end()) { - Object *obj = p->second.obj_; + Object* obj = p->second.obj_; - if (!this->included_member_ - && this->searched_for() - && !parameters->is_compatible_target(obj->target())) - return false; - - Read_symbols_data *sd = p->second.sd_; + Read_symbols_data* sd = p->second.sd_; if (mapfile != NULL) mapfile->report_include_archive_member(obj->name(), sym, why); if (input_objects->add_object(obj)) @@ -788,22 +1018,26 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, return true; } - bool unconfigured; - Object* obj = this->get_elf_object_for_member(off, &unconfigured); + // If this is the first object we are including from this archive, + // and we searched for this archive, most likely because it was + // found via a -l option, then if the target is incompatible we want + // to move on to the next archive found in the search path. + bool unconfigured = false; + bool* punconfigured = NULL; + if (!this->included_member_ && this->searched_for()) + punconfigured = &unconfigured; - if (!this->included_member_ - && this->searched_for() - && (obj == NULL - ? unconfigured - : !parameters->is_compatible_target(obj->target()))) + Object* obj = this->get_elf_object_for_member(off, punconfigured); + if (obj == NULL) { - if (obj != NULL) - delete obj; - return false; + // Return false to search for another archive, true if we found + // an error. + return unconfigured ? false : true; } - if (obj == NULL) - return true; + // If the object is an external member of a thin archive, + // unlock it when we're done here. + Thin_archive_object_unlocker unlocker(this->task_, obj); if (mapfile != NULL) mapfile->report_include_archive_member(obj->name(), sym, why); @@ -817,25 +1051,40 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, } if (!input_objects->add_object(obj)) - delete obj; - else { - Read_symbols_data sd; - obj->read_symbols(&sd); - obj->layout(symtab, layout, &sd); - obj->add_symbols(symtab, &sd, layout); + delete obj; + return true; + } - // If this is an external member of a thin archive, unlock the file - // for the next task. - if (obj->offset() == 0) - obj->unlock(this->task_); + if (layout->incremental_inputs() != NULL) + layout->incremental_inputs()->report_object(obj, 0, this, NULL); - this->included_member_ = true; - } + { + Read_symbols_data sd; + obj->read_symbols(&sd); + obj->layout(symtab, layout, &sd); + obj->add_symbols(symtab, &sd, layout); + } + this->included_member_ = true; return true; } +// Iterate over all unused symbols, and call the visitor class V for each. + +void +Archive::do_for_all_unused_symbols(Symbol_visitor_base* v) const +{ + for (std::vector::const_iterator p = this->armap_.begin(); + p != this->armap_.end(); + ++p) + { + if (this->seen_offsets_.find(p->file_offset) + == this->seen_offsets_.end()) + v->visit(this->armap_names_.data() + p->name_offset); + } +} + // Print statistical information to stderr. This is used for --stats. void @@ -880,6 +1129,16 @@ Add_archive_symbols::locks(Task_locker* tl) void Add_archive_symbols::run(Workqueue* workqueue) { + // For an incremental link, begin recording layout information. + Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); + if (incremental_inputs != NULL) + { + unsigned int arg_serial = this->input_argument_->file().arg_serial(); + Script_info* script_info = this->input_argument_->script_info(); + incremental_inputs->report_archive_begin(this->archive_, arg_serial, + script_info); + } + bool added = this->archive_->add_symbols(this->symtab_, this->layout_, this->input_objects_, this->mapfile_); @@ -906,10 +1165,209 @@ Add_archive_symbols::run(Workqueue* workqueue) this->input_group_->add_archive(this->archive_); else { - // We no longer need to know about this archive. - delete this->archive_; + // For an incremental link, finish recording the layout information. + if (incremental_inputs != NULL) + incremental_inputs->report_archive_end(this->archive_); + + if (!parameters->options().has_plugins() + || this->archive_->input_file()->options().whole_archive()) + { + // We no longer need to know about this archive. + delete this->archive_; + } + else + { + // The plugin interface may want to rescan this archive. + parameters->options().plugins()->save_archive(this->archive_); + } + this->archive_ = NULL; } } +// 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) + : Library_base(task), members_() +{ + this->members_.resize(lib->size()); +} + +const std::string& +Lib_group::do_filename() const +{ + std::string *filename = new std::string("/group/"); + return *filename; +} + +// Select members from the lib group and add them to the link. We walk +// through 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, + layout, + 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) + { + // The file must be locked in order to destroy the views + // associated with it. + gold_assert(obj != NULL); + obj->lock(this->task_); + delete member.sd_; + obj->unlock(this->task_); + } + } + + 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)) + { + if (layout->incremental_inputs() != NULL) + layout->incremental_inputs()->report_object(obj, member.arg_serial_, + this, NULL); + obj->layout(symtab, layout, sd); + obj->add_symbols(symtab, sd, layout); + } + delete sd; + // Unlock the file for the next task. + obj->unlock(this->task_); +} + +// Iterate over all unused symbols, and call the visitor class V for each. + +void +Lib_group::do_for_all_unused_symbols(Symbol_visitor_base* v) const +{ + // Files are removed from the members list when used, so all the + // files remaining on the list are unused. + for (std::vector::const_iterator p = this->members_.begin(); + p != this->members_.end(); + ++p) + { + Object* obj = p->obj_; + obj->for_all_global_symbols(p->sd_, v); + } +} + +// 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->readsyms_blocker_ != NULL && this->readsyms_blocker_->is_blocked()) + return this->readsyms_blocker_; + 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*) +{ + // For an incremental link, begin recording layout information. + Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); + if (incremental_inputs != NULL) + incremental_inputs->report_archive_begin(this->lib_, 0, NULL); + + this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_); + + if (incremental_inputs != NULL) + incremental_inputs->report_archive_end(this->lib_); +} + +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.