* readsyms.cc (Read_symbols::incompatible_warning): New function.
authorIan Lance Taylor <ian@airs.com>
Sat, 14 Mar 2009 05:56:46 +0000 (05:56 +0000)
committerIan Lance Taylor <ian@airs.com>
Sat, 14 Mar 2009 05:56:46 +0000 (05:56 +0000)
(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.

24 files changed:
gold/ChangeLog
gold/archive.cc
gold/archive.h
gold/dirsearch.cc
gold/dirsearch.h
gold/fileread.cc
gold/fileread.h
gold/gold.cc
gold/object.cc
gold/object.h
gold/options.h
gold/parameters.cc
gold/parameters.h
gold/plugin.cc
gold/readsyms.cc
gold/readsyms.h
gold/script-c.h
gold/script.cc
gold/script.h
gold/testsuite/binary_unittest.cc
gold/testsuite/object_unittest.cc
gold/workqueue.cc
gold/workqueue.h
gold/yyscript.y

index 4e20de0f5b4a7d0caf2ebcdf78f93a2d46d1e0d5..4a08b4778a37a24a3121aa6de95703e72edabd39 100644 (file)
@@ -1,5 +1,80 @@
 2009-03-13  Ian Lance Taylor  <iant@google.com>
 
+       * 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.
index 33a752e6348b87af4e8ace4c7e3ffd20fe6c1636..73fa6767ba9e838ce086025efe32c53398c28ee9 100644 (file)
@@ -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<Nested_archive_table::iterator, bool> 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
index 6b99aed1e80168a3a87c6bcd195e1f298453922d..e1d0262d42a7f760c3786a380c6c58de24562525 100644 (file)
@@ -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<off_t, Archive_member> 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_;
index eb57f996fee1b84948f41946ab5809428295e76c..84e1b32c00ae4fd12716cce2b7a7aaf6a6e2f744 100644 (file)
@@ -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<unsigned int>(*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();
 }
 
index 639d49e2bb8dfb3888fa2f12630a6848645784d1..f14b5ed7d19b44d29af0ad973ad7f25965313363 100644 (file)
@@ -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*
index 98ba3be7a2c2b5dddaa1e5a69c7f6e076c7deafa..a183bd69f0c69f87a30695aeb99ea9e24b2c491c 100644 (file)
@@ -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();
     }
index 365e7addadde298656b8a57434575e8eb35b3c5a..4d19824f04174e181fc29d70ee726e92cf6a6a3e 100644 (file)
@@ -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*
index 5afdcb00cfe3294479ba02735b3d54dcc3c3547e..93d03586c01361c7c3ac8ab5a20fdc1569d5de1d 100644 (file)
@@ -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;
     }
index 9cea076a0b84a772e6cedc0b2d58a74fa7b0e925..d1e16727032d83f6f69a6bcd5bed30b676ba20b9 100644 (file)
@@ -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
        }
index 2e49fd0f65af1602b0fd1781af93e08ec532e294..53d19444cf993d34c19280caa60ae910b9dcd9bf 100644 (file)
@@ -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
 
index 7fd9a00bca1345d854b45018837b7bbd3838a486..904743e9c8759dfe1c5a5d0e4d33a5f26ce7a08d 100644 (file)
@@ -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"));
index 729305116aad78086d58ac1cff81c0abb17a312d..6b4e81fd694a3ed0d35fb53b5e4869413272cb05 100644 (file)
@@ -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
 {
index ce165dd9d14e88d9b418bee0708f2411f522d87f..921a990efa46e13be2255d93e3c867378f25303c 100644 (file)
@@ -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
   {
index 392407c0239fc8205b62e3351b846845f2fe7d99..3c4d4aef50285fd56dcfbabc54a343e6a69bdfb9 100644 (file)
@@ -411,6 +411,7 @@ Plugin_manager::add_input_file(char *pathname)
                                                 this->symtab_,
                                                 this->layout_,
                                                 this->dirpath_,
+                                               0,
                                                 this->mapfile_,
                                                 input_argument,
                                                 NULL,
index 4e126e78747703697a7bbb678ea0061ac63213f8..dc85898c0b2d02862459a2a3a56d8a1a0eea1374 100644 (file)
@@ -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))
index c8ac6cc7b16ff5ae33cfbcda7c1445c73bb778df..c054b57d7c6c59d405f83a7e5286da8893db2298 100644 (file)
@@ -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_;
index d94ba51276be5ef1d9b6f41ff8081f64a1bf66b1..13c789a93f201a0567216f064b4c01b02f4ddf15 100644 (file)
@@ -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
index 4462c9589f170acaed86a5182bf23706c5d92ba6..44e43f7bd2ea1935609a81668c18161784b03291 100644 (file)
@@ -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<Parser_closure*>(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<Parser_closure*>(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<Parser_closure*>(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.
index b141f6e98e4fb0b494dcec9799b292528513fbea..e4554d0dcaca359e23b93729928fd394ea9019b4 100644 (file)
@@ -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);
index 44db01ecb78f413209933d024c14acdfb8ddb225..2645e0b91575b359fc637f84be78d688b164e42c 100644 (file)
@@ -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;
index 93d46361a7a199a005a9e4e40e5f45f6bbc579af..b36997e597e2716710815a46af8bc57ec68146e8 100644 (file)
@@ -43,7 +43,7 @@ Sized_object_test(const unsigned char* test_file, unsigned int test_file_size,
   const Task* task = reinterpret_cast<const Task*>(-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);
index 42182eabfb38b52b27bb545085564dd8d366b078..18c39003abdadbbd04bcc9cec1c5ac239e4c7690 100644 (file)
@@ -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.
index 3b7a764d73796b10890e7db16781fd35726c8a72..75452241d80515f3d3dc6f2eff810c4ad25cf91c 100644 (file)
@@ -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&);
index 52493202695f0c9a48085f77db3e4460193a8097..b01800579d62a27a01338e7eeb3c6c53db115466 100644 (file)
@@ -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.  */