X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Farchive.cc;h=75ad5517b8bed814470f1ac8c9994e56da7c30ee;hb=07b76c2f0baf197ce44d66a153184d33047e7ba0;hp=8c34d5524b5814d9e86326fbb076ff70539926f4;hpb=09ec0418c0d4144afba5947499425e27900d953f;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/archive.cc b/gold/archive.cc index 8c34d5524b..75ad5517b8 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -1,6 +1,6 @@ // archive.cc -- archive support for gold -// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2006-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -44,8 +44,116 @@ 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 @@ -85,13 +193,15 @@ 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) - : 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), task_(task), num_members_(0), - incremental_info_(NULL) + : 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()); @@ -109,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()) @@ -128,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), @@ -164,6 +284,7 @@ Archive::unlock_nested_archives() // Read the archive symbol map. +template void Archive::read_armap(off_t start, section_size_type size) { @@ -177,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). @@ -190,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) @@ -227,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, @@ -238,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; @@ -258,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] != '/') @@ -269,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) @@ -281,6 +405,11 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, 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] == '/') { // This is the extended name table. @@ -300,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; @@ -310,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) @@ -418,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; @@ -462,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)); @@ -527,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; @@ -544,32 +686,54 @@ 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; } + + unclaimed = true; } - const unsigned char* ehdr; - int read_size; - if (!is_elf_object(input_file, memoff, &ehdr, &read_size)) + if (!is_elf_obj) { - 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; } - Object *obj = 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()); @@ -593,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; @@ -605,78 +767,6 @@ Archive::read_symbols(off_t off) this->members_[off] = member; } -Archive::Should_include -Archive::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) - { - // Check whether the symbol was named in a -u option. - if (parameters->options().is_undefined(sym_name)) - { - *why = "-u "; - *why += sym_name; - } - else 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; - } - else - return Archive::SHOULD_INCLUDE_UNKNOWN; - } - else if (!sym->is_undefined()) - return Archive::SHOULD_INCLUDE_NO; - else if (sym->binding() == elfcpp::STB_WEAK) - return Archive::SHOULD_INCLUDE_UNKNOWN; - - return Archive::SHOULD_INCLUDE_YES; -} - // Select members from the archive and add them to the link. We walk // through the elements in the archive map, and look each one up in // the symbol table. If it exists as a strong undefined symbol, we @@ -775,12 +865,55 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, 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) @@ -828,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 @@ -844,9 +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_; - 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)) @@ -859,17 +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->included_member_ - && this->searched_for() - && obj == NULL - && unconfigured) - return false; + // 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; + Object* obj = this->get_elf_object_for_member(off, punconfigured); if (obj == NULL) - return true; + { + // Return false to search for another archive, true if we found + // an error. + return unconfigured ? false : 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); @@ -884,34 +1052,39 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, if (!input_objects->add_object(obj)) { - // If this is an external member of a thin archive, unlock the - // file. - if (obj->offset() == 0) - obj->unlock(this->task_); delete obj; + return true; } - else - { - { - if (layout->incremental_inputs() != NULL) - layout->incremental_inputs()->report_object(obj, this); - Read_symbols_data sd; - obj->read_symbols(&sd); - obj->layout(symtab, layout, &sd); - obj->add_symbols(symtab, &sd, layout); - } - - // 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_); - this->included_member_ = true; - } + if (layout->incremental_inputs() != NULL) + layout->incremental_inputs()->report_object(obj, 0, this, NULL); + + { + 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 @@ -959,7 +1132,12 @@ 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) - incremental_inputs->report_archive_begin(this->archive_); + { + 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_, @@ -988,12 +1166,21 @@ Add_archive_symbols::run(Workqueue* workqueue) else { // For an incremental link, finish recording the layout information. - Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); if (incremental_inputs != NULL) incremental_inputs->report_archive_end(this->archive_); - // We no longer need to know about this archive. - delete 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; } } @@ -1004,13 +1191,20 @@ 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_() + : 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 the members, and check if each one up should be included. +// 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. @@ -1031,7 +1225,7 @@ Lib_group::add_symbols(Symbol_table* symtab, Layout* layout, while (i < this->members_.size()) { const Archive_member& member = this->members_[i]; - Object *obj = member.obj_; + Object* obj = member.obj_; std::string why; // Skip files with no symbols. Plugin objects have @@ -1057,7 +1251,14 @@ Lib_group::add_symbols(Symbol_table* symtab, Layout* layout, else { if (member.sd_ != NULL) - delete member.sd_; + { + // 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(); @@ -1091,15 +1292,31 @@ Lib_group::include_member(Symbol_table* symtab, Layout* layout, obj->lock(this->task_); if (input_objects->add_object(obj)) { - // FIXME: Record incremental link info for --start-lib/--end-lib. if (layout->incremental_inputs() != NULL) - layout->incremental_inputs()->report_object(obj, NULL); + layout->incremental_inputs()->report_object(obj, member.arg_serial_, + this, NULL); obj->layout(symtab, layout, sd); obj->add_symbols(symtab, sd, layout); - // Unlock the file for the next task. - obj->unlock(this->task_); } 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. @@ -1118,6 +1335,8 @@ Lib_group::print_stats() 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; @@ -1132,9 +1351,15 @@ Add_lib_group_symbols::locks(Task_locker* tl) 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_); - // FIXME: Record incremental link info for --start_lib/--end_lib. + if (incremental_inputs != NULL) + incremental_inputs->report_archive_end(this->lib_); } Add_lib_group_symbols::~Add_lib_group_symbols()