From 15f8229bbf3f6fff866cbc04b07ddde9f6e41941 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 14 Mar 2009 05:56:46 +0000 Subject: [PATCH] * readsyms.cc (Read_symbols::incompatible_warning): New function. (Read_symbols::requeue): New function. (Read_symbols::do_read_symbols): If make_elf_object fails because the target type is not configured, and the file was searched for, issue a warning and retry with the next directory. (Add_symbols::run): If the file has an incompatible format, and it was searched for, requeue the Read_symbols task. On error, release the object. * readsyms.h (class Read_symbols): Add dirindex_ field. Add dirindex parameter to constructor. Change all callers. Declare incompatible_warning and requeue. (class Add_symbols): Add dirpath_, dirindex_, mapfile_, input_argument_ and input_group_ fields. Add them to constructor. Change all callers. (class Read_script): Add dirindex_ field. Add it to constructor. Change all callers. * archive.cc (Archive::setup): Remove input_objects parameter. Change all callers. (Archive::get_file_and_offset): Likewise. (Archive::read_all_symbols): Likewise. (Archive::read_symbols): Likewise. (Archive::get_elf_object_for_member): Remove input_objects parameter. Add punconfigured parameter. Change all callers. (Archive::add_symbols): Change return type to bool. Check return value of include_member. (Archive::include_all_members): Likewise. (Archive::include_member): Change return type to bool. Return false if first included object has incompatible target. Set included_member_ field. (Add_archive_symbols::run): If add_symbols returns false, requeue Read_symbols task. * archive.h (class Archive): Add included_member_ field. Initialize it in constructor. Add input_file and searched_for methods. Update declarations. (class Add_archive_symbols): Add dirpath_, dirindex_, and input_argument_ fields. Add them to constructor. Change all callers. * script.cc: Include "target-select.h". (class Parser_closure): Add skip_on_incompatible_target_ and found_incompatible_target_ fields. Add skip_on_incompatible_target parameter to constructor. Change all callers. Add methods skip_on_incompatible_target, clear_skip_on_incompatible_target, found_incompatible_target, and set_found_incompatible_target. (read_input_script): Add dirindex parameter. Change all callers. If parser finds an incompatible target, requeue Read_symbols task. (script_set_symbol): Clear skip_on_incompatible_target in closure. (script_add_assertion, script_parse_option): Likewise. (script_start_sections, script_add_phdr): Likewise. (script_check_output_format): New function. * script.h (read_input_script): Update declaration. * script-c.h (script_check_output_format): Declare. * yyscript.y (file_cmd): Handle OUTPUT_FORMAT. (ignore_cmd): Remove OUTPUT_FORMAT. * fileread.cc (Input_file::Input_file): Add explicit this. (Input_file::will_search_for): New function. (Input_file::open): Add pindex parameter. Change all callers. * fileread.h (class Input_file): Add input_file_argument method. Declare will_search_for. Update declarations. * object.cc (make_elf_object): Add punconfigured parameter. Change all callers. * object.h (class Object): Make input_file public. Add searched_for method. (make_elf_object): Update declaration. * dirsearch.cc (Dirsearch::find): Add pindex parameter. Use it to restart search. * dirsearch.h (class Dirsearch): Update declaration. * options.h (class General_options): Add --warn-search-mismatch. * parameters.cc (Parameters::is_compatible_target): New function. * parameters.h (class Parameters): Declare is_compatible_target. * workqueue.cc (Workqueue::add_blocker): New function. * workqueue.h (class Workqueue): Declare add_blocker. --- gold/ChangeLog | 75 +++++++++++++++ gold/archive.cc | 146 ++++++++++++++++++++---------- gold/archive.h | 50 ++++++---- gold/dirsearch.cc | 21 +++-- gold/dirsearch.h | 9 +- gold/fileread.cc | 27 ++++-- gold/fileread.h | 17 +++- gold/gold.cc | 2 +- gold/object.cc | 42 ++++++--- gold/object.h | 30 +++--- gold/options.h | 4 + gold/parameters.cc | 10 ++ gold/parameters.h | 4 + gold/plugin.cc | 1 + gold/readsyms.cc | 106 +++++++++++++++++++--- gold/readsyms.h | 39 ++++++-- gold/script-c.h | 7 ++ gold/script.cc | 98 ++++++++++++++++++-- gold/script.h | 2 +- gold/testsuite/binary_unittest.cc | 2 +- gold/testsuite/object_unittest.cc | 2 +- gold/workqueue.cc | 9 ++ gold/workqueue.h | 6 ++ gold/yyscript.y | 17 +++- 24 files changed, 587 insertions(+), 139 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 4e20de0f5b4..4a08b4778a3 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,80 @@ 2009-03-13 Ian Lance Taylor + * readsyms.cc (Read_symbols::incompatible_warning): New function. + (Read_symbols::requeue): New function. + (Read_symbols::do_read_symbols): If make_elf_object fails because + the target type is not configured, and the file was searched for, + issue a warning and retry with the next directory. + (Add_symbols::run): If the file has an incompatible format, and + it was searched for, requeue the Read_symbols task. On error, + release the object. + * readsyms.h (class Read_symbols): Add dirindex_ field. Add + dirindex parameter to constructor. Change all callers. Declare + incompatible_warning and requeue. + (class Add_symbols): Add dirpath_, dirindex_, mapfile_, + input_argument_ and input_group_ fields. Add them to + constructor. Change all callers. + (class Read_script): Add dirindex_ field. Add it to constructor. + Change all callers. + * archive.cc (Archive::setup): Remove input_objects parameter. + Change all callers. + (Archive::get_file_and_offset): Likewise. + (Archive::read_all_symbols): Likewise. + (Archive::read_symbols): Likewise. + (Archive::get_elf_object_for_member): Remove input_objects + parameter. Add punconfigured parameter. Change all callers. + (Archive::add_symbols): Change return type to bool. Check return + value of include_member. + (Archive::include_all_members): Likewise. + (Archive::include_member): Change return type to bool. Return + false if first included object has incompatible target. Set + included_member_ field. + (Add_archive_symbols::run): If add_symbols returns false, requeue + Read_symbols task. + * archive.h (class Archive): Add included_member_ field. + Initialize it in constructor. Add input_file and searched_for + methods. Update declarations. + (class Add_archive_symbols): Add dirpath_, dirindex_, and + input_argument_ fields. Add them to constructor. Change all + callers. + * script.cc: Include "target-select.h". + (class Parser_closure): Add skip_on_incompatible_target_ and + found_incompatible_target_ fields. Add + skip_on_incompatible_target parameter to constructor. Change all + callers. Add methods skip_on_incompatible_target, + clear_skip_on_incompatible_target, found_incompatible_target, and + set_found_incompatible_target. + (read_input_script): Add dirindex parameter. Change all callers. + If parser finds an incompatible target, requeue Read_symbols + task. + (script_set_symbol): Clear skip_on_incompatible_target in + closure. + (script_add_assertion, script_parse_option): Likewise. + (script_start_sections, script_add_phdr): Likewise. + (script_check_output_format): New function. + * script.h (read_input_script): Update declaration. + * script-c.h (script_check_output_format): Declare. + * yyscript.y (file_cmd): Handle OUTPUT_FORMAT. + (ignore_cmd): Remove OUTPUT_FORMAT. + * fileread.cc (Input_file::Input_file): Add explicit this. + (Input_file::will_search_for): New function. + (Input_file::open): Add pindex parameter. Change all callers. + * fileread.h (class Input_file): Add input_file_argument method. + Declare will_search_for. Update declarations. + * object.cc (make_elf_object): Add punconfigured parameter. + Change all callers. + * object.h (class Object): Make input_file public. Add + searched_for method. + (make_elf_object): Update declaration. + * dirsearch.cc (Dirsearch::find): Add pindex parameter. Use it to + restart search. + * dirsearch.h (class Dirsearch): Update declaration. + * options.h (class General_options): Add --warn-search-mismatch. + * parameters.cc (Parameters::is_compatible_target): New function. + * parameters.h (class Parameters): Declare is_compatible_target. + * workqueue.cc (Workqueue::add_blocker): New function. + * workqueue.h (class Workqueue): Declare add_blocker. + * fileread.cc (Input_file::open): Remove options parameter. Change all callers. (Input_file::open_binary): Likewise. diff --git a/gold/archive.cc b/gold/archive.cc index 33a752e6348..73fa6767ba9 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -87,7 +87,7 @@ const char Archive::arfmag[2] = { '`', '\n' }; // table. void -Archive::setup(Input_objects* input_objects) +Archive::setup() { // We need to ignore empty archives. if (this->input_file_->file().filesize() == sarmag) @@ -132,7 +132,7 @@ Archive::setup(Input_objects* input_objects) preread_syms = false; #endif if (preread_syms) - this->read_all_symbols(input_objects); + this->read_all_symbols(); } // Unlock any nested archives. @@ -441,8 +441,7 @@ Archive::end() // to the name of the archive member. Return TRUE on success. bool -Archive::get_file_and_offset(off_t off, Input_objects* input_objects, - Input_file** input_file, off_t* memoff, +Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, off_t* memsize, std::string* member_name) { off_t nested_off; @@ -482,17 +481,18 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects, new Input_file_argument(member_name->c_str(), false, "", false, parameters->options()); *input_file = new Input_file(input_file_arg); - if (!(*input_file)->open(*this->dirpath_, this->task_)) + int dummy = 0; + if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy)) return false; arch = new Archive(*member_name, *input_file, false, this->dirpath_, this->task_); - arch->setup(input_objects); + arch->setup(); std::pair ins = this->nested_archives_.insert(std::make_pair(*member_name, arch)); gold_assert(ins.second); } - return arch->get_file_and_offset(nested_off, input_objects, input_file, - memoff, memsize, member_name); + return arch->get_file_and_offset(nested_off, input_file, memoff, + memsize, member_name); } // This is an external member of a thin archive. Open the @@ -501,7 +501,8 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects, new Input_file_argument(member_name->c_str(), false, "", false, this->input_file_->options()); *input_file = new Input_file(input_file_arg); - if (!(*input_file)->open(*this->dirpath_, this->task_)) + int dummy = 0; + if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy)) return false; *memoff = 0; @@ -509,19 +510,21 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects, return true; } -// Return an ELF object for the member at offset OFF. Set *MEMBER_NAME to -// the name of the member. +// 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. Object* -Archive::get_elf_object_for_member(off_t off, Input_objects* input_objects) +Archive::get_elf_object_for_member(off_t off, bool* punconfigured) { - std::string member_name; + *punconfigured = false; + Input_file* input_file; off_t memoff; off_t memsize; - - if (!this->get_file_and_offset(off, input_objects, &input_file, &memoff, - &memsize, &member_name)) + std::string member_name; + if (!this->get_file_and_offset(off, &input_file, &memoff, &memsize, + &member_name)) return NULL; if (parameters->options().has_plugins()) @@ -565,28 +568,30 @@ Archive::get_elf_object_for_member(off_t off, Input_objects* input_objects) } return make_elf_object((std::string(this->input_file_->filename()) - + "(" + member_name + ")"), - input_file, memoff, ehdr, read_size); + + "(" + member_name + ")"), + input_file, memoff, ehdr, read_size, + punconfigured); } // Read the symbols from all the archive members in the link. void -Archive::read_all_symbols(Input_objects* input_objects) +Archive::read_all_symbols() { for (Archive::const_iterator p = this->begin(); p != this->end(); ++p) - this->read_symbols(input_objects, p->off); + this->read_symbols(p->off); } // Read the symbols from an archive member in the link. OFF is the file // offset of the member header. void -Archive::read_symbols(Input_objects* input_objects, off_t off) +Archive::read_symbols(off_t off) { - Object* obj = this->get_elf_object_for_member(off, input_objects); + bool dummy; + Object* obj = this->get_elf_object_for_member(off, &dummy); if (obj == NULL) return; @@ -602,9 +607,11 @@ Archive::read_symbols(Input_objects* input_objects, off_t off) // the symbol table. If it exists as a strong undefined symbol, we // pull in the corresponding element. We have to do this in a loop, // since pulling in one element may create new undefined symbols which -// may be satisfied by other objects in the archive. +// may be satisfied by other objects in the archive. Return true in +// the normal case, false if the first member we tried to add from +// this archive had an incompatible target. -void +bool Archive::add_symbols(Symbol_table* symtab, Layout* layout, Input_objects* input_objects, Mapfile* mapfile) { @@ -677,8 +684,10 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, why = "-u "; why += sym_name; } - this->include_member(symtab, layout, input_objects, - last_seen_offset, mapfile, sym, why.c_str()); + if (!this->include_member(symtab, layout, input_objects, + last_seen_offset, mapfile, sym, + why.c_str())) + return false; added_new_object = true; } @@ -686,11 +695,13 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, while (added_new_object); input_objects->archive_stop(this); + + return true; } // Include all the archive members in the link. This is for --whole-archive. -void +bool Archive::include_all_members(Symbol_table* symtab, Layout* layout, Input_objects* input_objects, Mapfile* mapfile) { @@ -703,8 +714,9 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout, p != this->members_.end(); ++p) { - this->include_member(symtab, layout, input_objects, p->first, - mapfile, NULL, "--whole-archive"); + if (!this->include_member(symtab, layout, input_objects, p->first, + mapfile, NULL, "--whole-archive")) + return false; ++Archive::total_members; } } @@ -714,13 +726,16 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout, p != this->end(); ++p) { - this->include_member(symtab, layout, input_objects, p->off, - mapfile, NULL, "--whole-archive"); + if (!this->include_member(symtab, layout, input_objects, p->off, + mapfile, NULL, "--whole-archive")) + return false; ++Archive::total_members; } } input_objects->archive_stop(this); + + return true; } // Return the number of members in the archive. This is only used for @@ -739,8 +754,11 @@ Archive::count_members() // 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 +// false if this was the first member we tried to add from this +// archive and it had an incompatible format. -void +bool Archive::include_member(Symbol_table* symtab, Layout* layout, Input_objects* input_objects, off_t off, Mapfile* mapfile, Symbol* sym, const char* why) @@ -751,6 +769,12 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, if (p != this->members_.end()) { 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_; if (mapfile != NULL) mapfile->report_include_archive_member(obj->name(), sym, why); @@ -758,14 +782,28 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, { obj->layout(symtab, layout, sd); obj->add_symbols(symtab, sd, layout); + this->included_member_ = true; } delete sd; - return; + return true; + } + + bool unconfigured; + Object* obj = this->get_elf_object_for_member(off, &unconfigured); + + if (!this->included_member_ + && this->searched_for() + && (obj == NULL + ? unconfigured + : !parameters->is_compatible_target(obj->target()))) + { + if (obj != NULL) + delete obj; + return false; } - Object* obj = this->get_elf_object_for_member(off, input_objects); if (obj == NULL) - return; + return true; if (mapfile != NULL) mapfile->report_include_archive_member(obj->name(), sym, why); @@ -774,10 +812,13 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, if (pluginobj != NULL) { pluginobj->add_symbols(symtab, NULL, layout); - return; + this->included_member_ = true; + return true; } - if (input_objects->add_object(obj)) + if (!input_objects->add_object(obj)) + delete obj; + else { Read_symbols_data sd; obj->read_symbols(&sd); @@ -788,12 +829,11 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, // for the next task. if (obj->offset() == 0) obj->unlock(this->task_); + + this->included_member_ = true; } - else - { - // FIXME: We need to close the descriptor here. - delete obj; - } + + return true; } // Print statistical information to stderr. This is used for --stats. @@ -838,16 +878,30 @@ Add_archive_symbols::locks(Task_locker* tl) } void -Add_archive_symbols::run(Workqueue*) +Add_archive_symbols::run(Workqueue* workqueue) { - this->archive_->add_symbols(this->symtab_, this->layout_, - this->input_objects_, this->mapfile_); - + bool added = this->archive_->add_symbols(this->symtab_, this->layout_, + this->input_objects_, + this->mapfile_); this->archive_->unlock_nested_archives(); this->archive_->release(); this->archive_->clear_uncached_views(); + if (!added) + { + // This archive holds object files which are incompatible with + // our output file. + Read_symbols::incompatible_warning(this->input_argument_, + this->archive_->input_file()); + Read_symbols::requeue(workqueue, this->input_objects_, this->symtab_, + this->layout_, this->dirpath_, this->dirindex_, + this->mapfile_, this->input_argument_, + this->input_group_, this->next_blocker_); + delete this->archive_; + return; + } + if (this->input_group_ != NULL) this->input_group_->add_archive(this->archive_); else diff --git a/gold/archive.h b/gold/archive.h index 6b99aed1e80..e1d0262d42a 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -33,6 +33,7 @@ namespace gold { class Task; +class Input_argument; class Input_file; class Input_objects; class Input_group; @@ -51,8 +52,8 @@ class Archive 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), nested_archives_(), - dirpath_(dirpath), task_(task), num_members_(0) + is_thin_archive_(is_thin_archive), included_member_(false), + nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0) { } // The length of the magic string at the start of an archive. @@ -72,6 +73,11 @@ class Archive name() const { return this->name_; } + // The input file. + const Input_file* + input_file() const + { return this->input_file_; } + // The file name. const std::string& filename() const @@ -79,7 +85,7 @@ class Archive // Set up the archive: read the symbol map. void - setup(Input_objects*); + setup(); // Get a reference to the underlying file. File_read& @@ -131,7 +137,7 @@ class Archive // Select members from the archive as needed and add them to the // link. - void + bool add_symbols(Symbol_table*, Layout*, Input_objects*, Mapfile*); // Dump statistical information to stderr. @@ -182,33 +188,36 @@ class Archive // within that file (0 if not a nested archive), and *MEMBER_NAME // to the name of the archive member. Return TRUE on success. bool - get_file_and_offset(off_t off, Input_objects* input_objects, - Input_file** input_file, off_t* memoff, + get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, off_t* memsize, std::string* member_name); - // Return an ELF object for the member at offset OFF. Set *MEMBER_NAME to - // the name of the member. + // Return an ELF object for the member at offset OFF. Object* - get_elf_object_for_member(off_t off, Input_objects* input_objects); + get_elf_object_for_member(off_t off, bool*); // Read the symbols from all the archive members in the link. void - read_all_symbols(Input_objects* input_objects); + read_all_symbols(); // Read the symbols from an archive member in the link. OFF is the file // offset of the member header. void - read_symbols(Input_objects* input_objects, off_t off); + read_symbols(off_t off); // Include all the archive members in the link. - void + bool include_all_members(Symbol_table*, Layout*, Input_objects*, Mapfile*); // Include an archive member in the link. - void + bool include_member(Symbol_table*, Layout*, Input_objects*, off_t off, Mapfile*, Symbol*, const char* why); + // Return whether we found this archive by searching a directory. + bool + searched_for() const + { return this->input_file_->will_search_for(); } + // Iterate over archive members. class const_iterator; @@ -274,6 +283,8 @@ class Archive std::map members_; // True if this is a thin archive. const bool is_thin_archive_; + // True if we have included at least one object from this archive. + bool included_member_; // Table of nested archives, indexed by filename. Nested_archive_table nested_archives_; // The directory search path. @@ -291,13 +302,17 @@ class Add_archive_symbols : public Task { public: Add_archive_symbols(Symbol_table* symtab, Layout* layout, - Input_objects* input_objects, Mapfile* mapfile, + Input_objects* input_objects, Dirsearch* dirpath, + int dirindex, Mapfile* mapfile, + const Input_argument* input_argument, Archive* archive, Input_group* input_group, Task_token* this_blocker, Task_token* next_blocker) : symtab_(symtab), layout_(layout), input_objects_(input_objects), - mapfile_(mapfile), archive_(archive), input_group_(input_group), - this_blocker_(this_blocker), next_blocker_(next_blocker) + dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile), + input_argument_(input_argument), archive_(archive), + input_group_(input_group), this_blocker_(this_blocker), + next_blocker_(next_blocker) { } ~Add_archive_symbols(); @@ -325,7 +340,10 @@ class Add_archive_symbols : public Task Symbol_table* symtab_; Layout* layout_; Input_objects* input_objects_; + Dirsearch* dirpath_; + int dirindex_; Mapfile* mapfile_; + const Input_argument* input_argument_; Archive* archive_; Input_group* input_group_; Task_token* this_blocker_; diff --git a/gold/dirsearch.cc b/gold/dirsearch.cc index eb57f996fee..84e1b32c00a 100644 --- a/gold/dirsearch.cc +++ b/gold/dirsearch.cc @@ -220,6 +220,8 @@ Dir_cache_task::run(gold::Workqueue*) namespace gold { +// Initialize. + void Dirsearch::initialize(Workqueue* workqueue, const General_options::Dir_list* directories) @@ -236,25 +238,28 @@ Dirsearch::initialize(Workqueue* workqueue, } } -// NOTE: we only log failed file-lookup attempts here. Successfully -// lookups will eventually get logged in File_read::open. +// Search for a file. NOTE: we only log failed file-lookup attempts +// here. Successfully lookups will eventually get logged in +// File_read::open. std::string Dirsearch::find(const std::string& n1, const std::string& n2, - bool *is_in_sysroot) const + bool* is_in_sysroot, int* pindex) const { gold_assert(!this->token_.is_blocked()); + gold_assert(*pindex >= 0); - for (General_options::Dir_list::const_iterator p = - this->directories_->begin(); - p != this->directories_->end(); - ++p) + for (unsigned int i = static_cast(*pindex); + i < this->directories_->size(); + ++i) { + const Search_directory* p = &this->directories_->at(i); Dir_cache* pdc = caches->lookup(p->name().c_str()); gold_assert(pdc != NULL); if (pdc->find(n1)) { *is_in_sysroot = p->is_in_sysroot(); + *pindex = i; return p->name() + '/' + n1; } else @@ -266,6 +271,7 @@ Dirsearch::find(const std::string& n1, const std::string& n2, if (pdc->find(n2)) { *is_in_sysroot = p->is_in_sysroot(); + *pindex = i; return p->name() + '/' + n2; } else @@ -274,6 +280,7 @@ Dirsearch::find(const std::string& n1, const std::string& n2, } } + *pindex = -2; return std::string(); } diff --git a/gold/dirsearch.h b/gold/dirsearch.h index 639d49e2bb8..f14b5ed7d19 100644 --- a/gold/dirsearch.h +++ b/gold/dirsearch.h @@ -53,9 +53,14 @@ class Dirsearch // second one may be empty). Return a full path name for the file, // or the empty string if it could not be found. This may only be // called if the token is not blocked. Set *IS_IN_SYSROOT if the - // file was found in a directory which is in the sysroot. + // file was found in a directory which is in the sysroot. *PINDEX + // should be set to zero the first time this is called; it will be + // updated with the index of the directory where the file is found, + // and that value plus one may be used to find the next file with + // the same name(s). std::string - find(const std::string&, const std::string& n2, bool *is_in_sysroot) const; + find(const std::string&, const std::string& n2, bool *is_in_sysroot, + int* pindex) const; // Return the blocker token which controls access. Task_token* diff --git a/gold/fileread.cc b/gold/fileread.cc index 98ba3be7a2c..a183bd69f0c 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -718,7 +718,7 @@ Input_file::Input_file(const Task* task, const char* name, this->input_argument_ = new Input_file_argument(name, false, "", false, Position_dependent_options()); - bool ok = file_.open(task, name, contents, size); + bool ok = this->file_.open(task, name, contents, size); gold_assert(ok); } @@ -756,6 +756,17 @@ Input_file::just_symbols() const return this->input_argument_->just_symbols(); } +// Return whether this is a file that we will search for in the list +// of directories. + +bool +Input_file::will_search_for() const +{ + return (!IS_ABSOLUTE_PATH(this->input_argument_->name()) + && (this->input_argument_->is_lib() + || this->input_argument_->extra_search_path() != NULL)); +} + // Open the file. // If the filename is not absolute, we assume it is in the current @@ -766,14 +777,14 @@ Input_file::just_symbols() const // the file location, rather than the current directory. bool -Input_file::open(const Dirsearch& dirpath, const Task* task) +Input_file::open(const Dirsearch& dirpath, const Task* task, int *pindex) { std::string name; // Case 1: name is an absolute file, just try to open it // Case 2: name is relative but is_lib is false and extra_search_path // is empty - if (IS_ABSOLUTE_PATH (this->input_argument_->name()) + if (IS_ABSOLUTE_PATH(this->input_argument_->name()) || (!this->input_argument_->is_lib() && this->input_argument_->extra_search_path() == NULL)) { @@ -796,7 +807,7 @@ Input_file::open(const Dirsearch& dirpath, const Task* task) n2 = n1 + ".a"; n1 += ".so"; } - name = dirpath.find(n1, n2, &this->is_in_sysroot_); + name = dirpath.find(n1, n2, &this->is_in_sysroot_, pindex); if (name.empty()) { gold_error(_("cannot find -l%s"), @@ -819,17 +830,21 @@ Input_file::open(const Dirsearch& dirpath, const Task* task) name += '/'; name += this->input_argument_->name(); struct stat dummy_stat; - if (::stat(name.c_str(), &dummy_stat) < 0) + if (*pindex > 0 || ::stat(name.c_str(), &dummy_stat) < 0) { // extra_search_path failed, so check the normal search-path. + int index = *pindex; + if (index > 0) + --index; name = dirpath.find(this->input_argument_->name(), "", - &this->is_in_sysroot_); + &this->is_in_sysroot_, &index); if (name.empty()) { gold_error(_("cannot find %s"), this->input_argument_->name()); return false; } + *pindex = index + 1; } this->found_name_ = this->input_argument_->name(); } diff --git a/gold/fileread.h b/gold/fileread.h index 365e7addadd..4d19824f041 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -431,10 +431,23 @@ class Input_file Input_file(const Task*, const char* name, const unsigned char* contents, off_t size); + // Return the command line argument. + const Input_file_argument* + input_file_argument() const + { return this->input_argument_; } + + // Return whether this is a file that we will search for in the list + // of directories. + bool + will_search_for() const; + // Open the file. If the open fails, this will report an error and - // return false. + // return false. If there is a search, it starts at directory + // *PINDEX. *PINDEX should be initialized to zero. It may be + // restarted to find the next file with a matching name by + // incrementing the result and calling this again. bool - open(const Dirsearch&, const Task*); + open(const Dirsearch&, const Task*, int *pindex); // Return the name given by the user. For -lc this will return "c". const char* diff --git a/gold/gold.cc b/gold/gold.cc index 5afdcb00cfe..93d03586c01 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -183,7 +183,7 @@ queue_initial_tasks(const General_options& options, Task_token* next_blocker = new Task_token(true); next_blocker->add_blocker(); workqueue->queue(new Read_symbols(input_objects, symtab, layout, - &search_path, mapfile, &*p, NULL, + &search_path, 0, mapfile, &*p, NULL, this_blocker, next_blocker)); this_blocker = next_blocker; } diff --git a/gold/object.cc b/gold/object.cc index 9cea076a0b8..d1e16727032 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -2104,8 +2104,12 @@ namespace gold Object* make_elf_object(const std::string& name, Input_file* input_file, off_t offset, - const unsigned char* p, section_offset_type bytes) + const unsigned char* p, section_offset_type bytes, + bool* punconfigured) { + if (punconfigured != NULL) + *punconfigured = false; + if (bytes < elfcpp::EI_NIDENT) { gold_error(_("%s: ELF file too short"), name.c_str()); @@ -2164,9 +2168,12 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, return make_elf_sized_object<32, true>(name, input_file, offset, ehdr); #else - gold_error(_("%s: not configured to support " - "32-bit big-endian object"), - name.c_str()); + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "32-bit big-endian object"), + name.c_str()); return NULL; #endif } @@ -2177,9 +2184,12 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, return make_elf_sized_object<32, false>(name, input_file, offset, ehdr); #else - gold_error(_("%s: not configured to support " - "32-bit little-endian object"), - name.c_str()); + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "32-bit little-endian object"), + name.c_str()); return NULL; #endif } @@ -2198,9 +2208,12 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, return make_elf_sized_object<64, true>(name, input_file, offset, ehdr); #else - gold_error(_("%s: not configured to support " - "64-bit big-endian object"), - name.c_str()); + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "64-bit big-endian object"), + name.c_str()); return NULL; #endif } @@ -2211,9 +2224,12 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, return make_elf_sized_object<64, false>(name, input_file, offset, ehdr); #else - gold_error(_("%s: not configured to support " - "64-bit little-endian object"), - name.c_str()); + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "64-bit little-endian object"), + name.c_str()); return NULL; #endif } diff --git a/gold/object.h b/gold/object.h index 2e49fd0f65a..53d19444cf9 100644 --- a/gold/object.h +++ b/gold/object.h @@ -227,6 +227,15 @@ class Object target() const { return this->target_; } + // Get the file. We pass on const-ness. + Input_file* + input_file() + { return this->input_file_; } + + const Input_file* + input_file() const + { return this->input_file_; } + // Lock the underlying file. void lock(const Task* t) @@ -449,6 +458,11 @@ class Object is_in_system_directory() const { return this->input_file()->is_in_system_directory(); } + // Return whether we found this object by searching a directory. + bool + searched_for() const + { return this->input_file()->will_search_for(); } + protected: // Returns NULL for Objects that are not plugin objects. This method // is overridden in the Pluginobj class. @@ -514,15 +528,6 @@ class Object virtual void do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const = 0; - // Get the file. We pass on const-ness. - Input_file* - input_file() - { return this->input_file_; } - - const Input_file* - input_file() const - { return this->input_file_; } - // Set the target. void set_target(int machine, int size, bool big_endian, int osabi, @@ -1917,12 +1922,15 @@ struct Relocate_info }; // Return an Object appropriate for the input file. P is BYTES long, -// and holds the ELF header. +// and holds the ELF header. If PUNCONFIGURED is not NULL, then if +// this sees an object the linker is not configured to support, it +// sets *PUNCONFIGURED to true and returns NULL without giving an +// error message. extern Object* make_elf_object(const std::string& name, Input_file*, off_t offset, const unsigned char* p, - section_offset_type bytes); + section_offset_type bytes, bool* punconfigured); } // end namespace gold diff --git a/gold/options.h b/gold/options.h index 7fd9a00bca1..904743e9c87 100644 --- a/gold/options.h +++ b/gold/options.h @@ -854,6 +854,10 @@ class General_options DEFINE_special(version_script, options::TWO_DASHES, '\0', N_("Read version script"), N_("FILE")); + DEFINE_bool(warn_search_mismatch, options::TWO_DASHES, '\0', true, + N_("Warn when skipping an incompatible library"), + N_("Don't warn when skipping an incompatible library")); + DEFINE_bool(whole_archive, options::TWO_DASHES, '\0', false, N_("Include all archive contents"), N_("Include only needed archive contents")); diff --git a/gold/parameters.cc b/gold/parameters.cc index 729305116aa..6b4e81fd694 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -97,6 +97,16 @@ Parameters::default_target() const return *target; } +// Return whether TARGET is compatible with the target we are using. + +bool +Parameters::is_compatible_target(const Target* target) const +{ + if (this->target_ == NULL) + return true; + return target == this->target_; +} + Parameters::Target_size_endianness Parameters::size_and_endianness() const { diff --git a/gold/parameters.h b/gold/parameters.h index ce165dd9d14..921a990efa4 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -103,6 +103,10 @@ class Parameters const Target& default_target() const; + // Return true if TARGET is compatible with the current target. + bool + is_compatible_target(const Target*) const; + bool doing_static_link() const { diff --git a/gold/plugin.cc b/gold/plugin.cc index 392407c0239..3c4d4aef502 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -411,6 +411,7 @@ Plugin_manager::add_input_file(char *pathname) this->symtab_, this->layout_, this->dirpath_, + 0, this->mapfile_, input_argument, NULL, diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 4e126e78747..dc85898c0b2 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -90,6 +90,44 @@ Read_symbols::~Read_symbols() // Add_symbols task. } +// If appropriate, issue a warning about skipping an incompatible +// file. + +void +Read_symbols::incompatible_warning(const Input_argument* input_argument, + const Input_file* input_file) +{ + if (parameters->options().warn_search_mismatch()) + gold_warning("skipping incompatible %s while searching for %s", + input_file->filename().c_str(), + input_argument->file().name()); +} + +// Requeue a Read_symbols task to search for the next object with the +// same name. + +void +Read_symbols::requeue(Workqueue* workqueue, 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* next_blocker) +{ + // Bump the directory search index. + ++dirindex; + + // We don't need to worry about this_blocker, since we already + // reached it. However, we are removing the blocker on next_blocker + // because the calling task is completing. So we need to add a new + // blocker. Since next_blocker may be shared by several tasks, we + // need to increment the count with the workqueue lock held. + workqueue->add_blocker(next_blocker); + + workqueue->queue(new Read_symbols(input_objects, symtab, layout, dirpath, + dirindex, mapfile, input_argument, + input_group, NULL, next_blocker)); +} + // Return whether a Read_symbols task is runnable. We can read an // ordinary input file immediately. For an archive specified using // -l, we have to wait until the search path is complete. @@ -139,7 +177,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) } Input_file* input_file = new Input_file(&this->input_argument_->file()); - if (!input_file->open(*this->dirpath_, this)) + if (!input_file->open(*this->dirpath_, this, &this->dirindex_)) return false; // Read enough of the file to pick up the entire ELF header. @@ -171,7 +209,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) Archive* arch = new Archive(this->input_argument_->file().name(), input_file, is_thin_archive, this->dirpath_, this); - arch->setup(this->input_objects_); + arch->setup(); // Unlock the archive so it can be used in the next task. arch->unlock(this); @@ -179,7 +217,10 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) workqueue->queue_next(new Add_archive_symbols(this->symtab_, this->layout_, this->input_objects_, + this->dirpath_, + this->dirindex_, this->mapfile_, + this->input_argument_, arch, this->input_group_, this->this_blocker_, @@ -203,7 +244,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) workqueue->queue_next(new Add_symbols(this->input_objects_, this->symtab_, this->layout_, - obj, NULL, + this->dirpath_, + this->dirindex_, + this->mapfile_, + this->input_argument_, + this->input_group_, + obj, + NULL, this->this_blocker_, this->next_blocker_)); return true; @@ -221,10 +268,24 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) { // This is an ELF object. + bool unconfigured; Object* obj = make_elf_object(input_file->filename(), - input_file, 0, ehdr, read_size); + input_file, 0, ehdr, read_size, + &unconfigured); if (obj == NULL) - return false; + { + if (unconfigured && input_file->will_search_for()) + { + Read_symbols::incompatible_warning(this->input_argument_, + input_file); + input_file->file().release(); + input_file->file().unlock(this); + delete input_file; + ++this->dirindex_; + return this->do_read_symbols(workqueue); + } + return false; + } Read_symbols_data* sd = new Read_symbols_data; obj->read_symbols(sd); @@ -244,7 +305,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) workqueue->queue_next(new Add_symbols(this->input_objects_, this->symtab_, this->layout_, - obj, sd, + this->dirpath_, + this->dirindex_, + this->mapfile_, + this->input_argument_, + this->input_group_, + obj, + sd, this->this_blocker_, this->next_blocker_)); @@ -261,6 +328,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) workqueue->queue_soon(new Read_script(this->symtab_, this->layout_, this->dirpath_, + this->dirindex_, this->input_objects_, this->mapfile_, this->input_group_, @@ -297,8 +365,8 @@ Read_symbols::do_group(Workqueue* workqueue) next_blocker->add_blocker(); workqueue->queue_soon(new Read_symbols(this->input_objects_, this->symtab_, this->layout_, - this->dirpath_, this->mapfile_, - arg, input_group, + this->dirpath_, this->dirindex_, + this->mapfile_, arg, input_group, this_blocker, next_blocker)); this_blocker = next_blocker; } @@ -376,7 +444,7 @@ Add_symbols::locks(Task_locker* tl) // Add the symbols in the object to the symbol table. void -Add_symbols::run(Workqueue*) +Add_symbols::run(Workqueue* workqueue) { Pluginobj* pluginobj = this->object_->pluginobj(); if (pluginobj != NULL) @@ -385,9 +453,23 @@ Add_symbols::run(Workqueue*) return; } - if (!this->input_objects_->add_object(this->object_)) + // If this file has an incompatible format, try for another file + // with the same name. + if (this->object_->searched_for() + && !parameters->is_compatible_target(this->object_->target())) { - // FIXME: We need to close the descriptor here. + Read_symbols::incompatible_warning(this->input_argument_, + this->object_->input_file()); + Read_symbols::requeue(workqueue, this->input_objects_, this->symtab_, + this->layout_, this->dirpath_, this->dirindex_, + this->mapfile_, this->input_argument_, + this->input_group_, this->next_blocker_); + this->object_->release(); + delete this->object_; + } + else if (!this->input_objects_->add_object(this->object_)) + { + this->object_->release(); delete this->object_; } else @@ -490,7 +572,7 @@ Read_script::run(Workqueue* workqueue) { bool used_next_blocker; if (!read_input_script(workqueue, this->symtab_, this->layout_, - this->dirpath_, this->input_objects_, + this->dirpath_, this->dirindex_, this->input_objects_, this->mapfile_, this->input_group_, this->input_argument_, this->input_file_, this->next_blocker_, &used_next_blocker)) diff --git a/gold/readsyms.h b/gold/readsyms.h index c8ac6cc7b16..c054b57d7c6 100644 --- a/gold/readsyms.h +++ b/gold/readsyms.h @@ -55,18 +55,30 @@ class Read_symbols : public Task // NEXT_BLOCKER is used to block the next input file from adding // symbols. Read_symbols(Input_objects* input_objects, Symbol_table* symtab, - Layout* layout, Dirsearch* dirpath, Mapfile* mapfile, - const Input_argument* input_argument, + 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_objects_(input_objects), symtab_(symtab), layout_(layout), - dirpath_(dirpath), mapfile_(mapfile), input_argument_(input_argument), - input_group_(input_group), this_blocker_(this_blocker), - next_blocker_(next_blocker) + dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile), + input_argument_(input_argument), input_group_(input_group), + this_blocker_(this_blocker), next_blocker_(next_blocker) { } ~Read_symbols(); + // If appropriate, issue a warning about skipping an incompatible + // object. + static void + incompatible_warning(const Input_argument*, const Input_file*); + + // Requeue a Read_symbols task to search for the next object with + // the same name. + static void + requeue(Workqueue*, Input_objects*, Symbol_table*, Layout*, Dirsearch*, + int dirindex, Mapfile*, const Input_argument*, Input_group*, + Task_token* next_blocker); + // The standard Task methods. Task_token* @@ -94,6 +106,7 @@ class Read_symbols : public Task Symbol_table* symtab_; Layout* layout_; Dirsearch* dirpath_; + int dirindex_; Mapfile* mapfile_; const Input_argument* input_argument_; Input_group* input_group_; @@ -112,10 +125,14 @@ class Add_symbols : public Task // one for the previous input file. NEXT_BLOCKER is used to prevent // the next task from running. Add_symbols(Input_objects* input_objects, Symbol_table* symtab, - Layout* layout, Object* object, + Layout* layout, Dirsearch* dirpath, int dirindex, + Mapfile* mapfile, const Input_argument* input_argument, + Input_group* input_group, Object* object, Read_symbols_data* sd, 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), object_(object), sd_(sd), this_blocker_(this_blocker), next_blocker_(next_blocker) { } @@ -141,6 +158,11 @@ private: Input_objects* input_objects_; Symbol_table* symtab_; Layout* layout_; + Dirsearch* dirpath_; + int dirindex_; + Mapfile* mapfile_; + const Input_argument* input_argument_; + Input_group* input_group_; Object* object_; Read_symbols_data* sd_; Task_token* this_blocker_; @@ -230,11 +252,11 @@ class Read_script : public Task { public: Read_script(Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, - Input_objects* input_objects, Mapfile* mapfile, + int dirindex, Input_objects* input_objects, Mapfile* mapfile, Input_group* input_group, const Input_argument* input_argument, Input_file* input_file, Task_token* this_blocker, Task_token* next_blocker) - : symtab_(symtab), layout_(layout), dirpath_(dirpath), + : symtab_(symtab), layout_(layout), dirpath_(dirpath), dirindex_(dirindex), input_objects_(input_objects), mapfile_(mapfile), input_group_(input_group), input_argument_(input_argument), input_file_(input_file), this_blocker_(this_blocker), @@ -261,6 +283,7 @@ class Read_script : public Task Symbol_table* symtab_; Layout* layout_; Dirsearch* dirpath_; + int dirindex_; Input_objects* input_objects_; Mapfile* mapfile_; Input_group* input_group_; diff --git a/gold/script-c.h b/gold/script-c.h index d94ba51276b..13c789a93f2 100644 --- a/gold/script-c.h +++ b/gold/script-c.h @@ -245,6 +245,13 @@ script_set_common_allocation(void* closure, int); extern void script_parse_option(void* closure, const char*, size_t); +/* Called by the bison parser to handle OUTPUT_FORMAT. This return 0 + if the parse should be aborted. */ + +extern int +script_check_output_format(void* closure, const char*, size_t, + const char*, size_t, const char*, size_t); + /* Called by the bison parser to handle SEARCH_DIR. */ extern void diff --git a/gold/script.cc b/gold/script.cc index 4462c9589f1..44e43f7bd2e 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -40,6 +40,7 @@ #include "parameters.h" #include "layout.h" #include "symtab.h" +#include "target-select.h" #include "script.h" #include "script-c.h" @@ -1162,9 +1163,12 @@ class Parser_closure bool in_group, bool is_in_sysroot, Command_line* command_line, Script_options* script_options, - Lex* lex) + Lex* lex, + bool skip_on_incompatible_target) : filename_(filename), posdep_options_(posdep_options), in_group_(in_group), is_in_sysroot_(is_in_sysroot), + skip_on_incompatible_target_(skip_on_incompatible_target), + found_incompatible_target_(false), command_line_(command_line), script_options_(script_options), version_script_info_(script_options->version_script_info()), lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL) @@ -1196,6 +1200,30 @@ class Parser_closure is_in_sysroot() const { return this->is_in_sysroot_; } + // Whether to skip to the next file with the same name if we find an + // incompatible target in an OUTPUT_FORMAT statement. + bool + skip_on_incompatible_target() const + { return this->skip_on_incompatible_target_; } + + // Stop skipping to the next flie on an incompatible target. This + // is called when we make some unrevocable change to the data + // structures. + void + clear_skip_on_incompatible_target() + { this->skip_on_incompatible_target_ = false; } + + // Whether we found an incompatible target in an OUTPUT_FORMAT + // statement. + bool + found_incompatible_target() const + { return this->found_incompatible_target_; } + + // Note that we found an incompatible target. + void + set_found_incompatible_target() + { this->found_incompatible_target_ = true; } + // Returns the Command_line structure passed in at constructor time. // This value may be NULL. The caller may modify this, which modifies // the passed-in Command_line object (not a copy). @@ -1296,6 +1324,12 @@ class Parser_closure bool in_group_; // Whether the script was found in a sysrooted directory. bool is_in_sysroot_; + // If this is true, then if we find an OUTPUT_FORMAT with an + // incompatible target, then we tell the parser to abort so that we + // can search for the next file with the same name. + bool skip_on_incompatible_target_; + // True if we found an OUTPUT_FORMAT with an incompatible target. + bool found_incompatible_target_; // May be NULL if the user chooses not to pass one in. Command_line* command_line_; // Options which may be set from any linker script. @@ -1322,8 +1356,9 @@ class Parser_closure bool read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout, - Dirsearch* dirsearch, Input_objects* input_objects, - Mapfile* mapfile, Input_group* input_group, + Dirsearch* dirsearch, int dirindex, + Input_objects* input_objects, Mapfile* mapfile, + Input_group* input_group, const Input_argument* input_argument, Input_file* input_file, Task_token* next_blocker, bool* used_next_blocker) @@ -1341,10 +1376,21 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout, input_file->is_in_sysroot(), NULL, layout->script_options(), - &lex); + &lex, + input_file->will_search_for()); if (yyparse(&closure) != 0) - return false; + { + if (closure.found_incompatible_target()) + { + Read_symbols::incompatible_warning(input_argument, input_file); + Read_symbols::requeue(workqueue, input_objects, symtab, layout, + dirsearch, dirindex, mapfile, input_argument, + input_group, next_blocker); + return true; + } + return false; + } if (!closure.saw_inputs()) return true; @@ -1363,7 +1409,7 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout, nb->add_blocker(); } workqueue->queue_soon(new Read_symbols(input_objects, symtab, - layout, dirsearch, mapfile, &*p, + layout, dirsearch, 0, mapfile, &*p, input_group, this_blocker, nb)); this_blocker = nb; } @@ -1397,7 +1443,8 @@ read_script_file(const char* filename, Command_line* cmdline, posdep.set_format_enum(General_options::OBJECT_FORMAT_ELF); Input_file_argument input_argument(filename, false, "", false, posdep); Input_file input_file(&input_argument); - if (!input_file.open(dirsearch, task)) + int dummy = 0; + if (!input_file.open(dirsearch, task, &dummy)) return false; std::string input_string; @@ -1412,7 +1459,8 @@ read_script_file(const char* filename, Command_line* cmdline, input_file.is_in_sysroot(), cmdline, script_options, - &lex); + &lex, + false); if (yyparse(&closure) != 0) { input_file.file().unlock(task); @@ -1471,7 +1519,7 @@ Script_options::define_symbol(const char* definition) Position_dependent_options posdep_options; Parser_closure closure("command line", posdep_options, false, false, NULL, - this, &lex); + this, &lex, false); if (yyparse(&closure) != 0) return false; @@ -2191,6 +2239,7 @@ script_set_symbol(void* closurev, const char* name, size_t length, const bool hidden = hiddeni != 0; closure->script_options()->add_symbol_assignment(name, length, value, provide, hidden); + closure->clear_skip_on_incompatible_target(); } // Called by the bison parser to add an assertion. @@ -2201,6 +2250,7 @@ script_add_assertion(void* closurev, Expression* check, const char* message, { Parser_closure* closure = static_cast(closurev); closure->script_options()->add_assertion(check, message, messagelen); + closure->clear_skip_on_incompatible_target(); } // Called by the bison parser to parse an OPTION. @@ -2230,6 +2280,34 @@ script_parse_option(void* closurev, const char* option, size_t length) // into mutable_option, so we can't free it. In cases the class // does not store such a pointer, this is a memory leak. Alas. :( } + closure->clear_skip_on_incompatible_target(); +} + +// Called by the bison parser to handle OUTPUT_FORMAT. OUTPUT_FORMAT +// takes either one or three arguments. In the three argument case, +// the format depends on the endianness option, which we don't +// currently support (FIXME). If we see an OUTPUT_FORMAT for the +// wrong format, then we want to search for a new file. Returning 0 +// here will cause the parser to immediately abort. + +extern "C" int +script_check_output_format(void* closurev, + const char* default_name, size_t default_length, + const char*, size_t, const char*, size_t) +{ + Parser_closure* closure = static_cast(closurev); + std::string name(default_name, default_length); + Target* target = select_target_by_name(name.c_str()); + if (target == NULL || !parameters->is_compatible_target(target)) + { + if (closure->skip_on_incompatible_target()) + { + closure->set_found_incompatible_target(); + return 0; + } + // FIXME: Should we warn about the unknown target? + } + return 1; } // Called by the bison parser to handle SEARCH_DIR. This is handled @@ -2388,6 +2466,7 @@ script_start_sections(void* closurev) { Parser_closure* closure = static_cast(closurev); closure->script_options()->script_sections()->start_sections(); + closure->clear_skip_on_incompatible_target(); } // Called by the bison parser to finish a SECTIONS clause. @@ -2580,6 +2659,7 @@ script_add_phdr(void* closurev, const char* name, size_t namelen, Script_sections* ss = closure->script_options()->script_sections(); ss->add_phdr(name, namelen, type, includes_filehdr, includes_phdrs, is_flags_valid, info->flags, info->load_address); + closure->clear_skip_on_incompatible_target(); } // Convert a program header string to a type. diff --git a/gold/script.h b/gold/script.h index b141f6e98e4..e4554d0dcac 100644 --- a/gold/script.h +++ b/gold/script.h @@ -389,7 +389,7 @@ class Script_options // whether the function took over NEXT_BLOCKER. bool -read_input_script(Workqueue*, Symbol_table*, Layout*, Dirsearch*, +read_input_script(Workqueue*, Symbol_table*, Layout*, Dirsearch*, int, Input_objects*, Mapfile*, Input_group*, const Input_argument*, Input_file*, Task_token* next_blocker, bool* used_next_blocker); diff --git a/gold/testsuite/binary_unittest.cc b/gold/testsuite/binary_unittest.cc index 44db01ecb78..2645e0b9157 100644 --- a/gold/testsuite/binary_unittest.cc +++ b/gold/testsuite/binary_unittest.cc @@ -67,7 +67,7 @@ Sized_binary_test(Target* target) binary.converted_size()); Object* object = make_elf_object("test.o", &input_file, 0, binary.converted_data(), - binary.converted_size()); + binary.converted_size(), NULL); CHECK(object != NULL); if (object == NULL) return false; diff --git a/gold/testsuite/object_unittest.cc b/gold/testsuite/object_unittest.cc index 93d46361a7a..b36997e597e 100644 --- a/gold/testsuite/object_unittest.cc +++ b/gold/testsuite/object_unittest.cc @@ -43,7 +43,7 @@ Sized_object_test(const unsigned char* test_file, unsigned int test_file_size, const Task* task = reinterpret_cast(-1); Input_file input_file(task, "test.o", test_file, test_file_size); Object* object = make_elf_object("test.o", &input_file, 0, - test_file, test_file_size); + test_file, test_file_size, NULL); CHECK(object->name() == "test.o"); CHECK(!object->is_dynamic()); CHECK(object->target() == target_test_pointer); diff --git a/gold/workqueue.cc b/gold/workqueue.cc index 42182eabfb3..18c39003abd 100644 --- a/gold/workqueue.cc +++ b/gold/workqueue.cc @@ -494,4 +494,13 @@ Workqueue::set_thread_count(int threads) this->condvar_.broadcast(); } +// Add a new blocker to an existing Task_token. + +void +Workqueue::add_blocker(Task_token* token) +{ + Hold_lock hl(this->lock_); + token->add_blocker(); +} + } // End namespace gold. diff --git a/gold/workqueue.h b/gold/workqueue.h index 3b7a764d737..75452241d80 100644 --- a/gold/workqueue.h +++ b/gold/workqueue.h @@ -227,6 +227,12 @@ class Workqueue void set_thread_count(int); + // Add a new blocker to an existing Task_token. This must be done + // with the workqueue lock held. This should not be done routinely, + // only in special circumstances. + void + add_blocker(Task_token*); + private: // This class can not be copied. Workqueue(const Workqueue&); diff --git a/gold/yyscript.y b/gold/yyscript.y index 52493202695..b01800579d6 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -245,6 +245,19 @@ file_cmd: | INPUT '(' input_list ')' | OPTION '(' string ')' { script_parse_option(closure, $3.value, $3.length); } + | OUTPUT_FORMAT '(' string ')' + { + if (!script_check_output_format(closure, $3.value, $3.length, + NULL, 0, NULL, 0)) + YYABORT; + } + | OUTPUT_FORMAT '(' string ',' string ',' string ')' + { + if (!script_check_output_format(closure, $3.value, $3.length, + $5.value, $5.length, + $7.value, $7.length)) + YYABORT; + } | PHDRS '{' phdrs_defs '}' | SEARCH_DIR '(' string ')' { script_add_search_dir(closure, $3.value, $3.length); } @@ -266,9 +279,7 @@ file_cmd: these is more-or-less OK since most scripts simply explicitly choose the default. */ ignore_cmd: - OUTPUT_FORMAT '(' string ')' - | OUTPUT_FORMAT '(' string ',' string ',' string ')' - | OUTPUT_ARCH '(' string ')' + OUTPUT_ARCH '(' string ')' ; /* A list of input file names. */ -- 2.39.2