This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gold patch committed: Skip incompatible objects


When the GNU linker searches for an input file or an archive, if it
finds an incompatible file, it skips it and keeps searching.  An object
is incompatible if it is built for a target other than the one being
linked.  An archive is incompatible if it contains an incompatible
object.  A script is incompatible if it uses an OUTPUT_FORMAT command to
name a target other than the one being linked.  The GNU linker issues a
warning when it skips a file, unless --no-warn-search-mismatch is used.

I committed this patch to gold to implement the same functionality.  The
approach I used is to assume that the file is OK.  If we find out that
the file is not OK, we queue up a new task to find the next file with
the same name.  This means that this feature will not yield worse
performance for users who set up their builds correctly.

When the GNU linker is checking whether a linker script file is
compatible, it lexes the entire script and looks for an OUTPUT_FORMAT
command.  To avoid penalizing correct cases, gold uses a simpler
approach: the OUTPUT_FORMAT command must be found before anything which
changes the linker's global state.  Hopefully this difference will not
cause any trouble.

Ian


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.


Index: archive.cc
===================================================================
RCS file: /cvs/src/src/gold/archive.cc,v
retrieving revision 1.40
diff -p -u -r1.40 archive.cc
--- archive.cc	13 Mar 2009 21:30:06 -0000	1.40
+++ archive.cc	14 Mar 2009 05:35:02 -0000
@@ -87,7 +87,7 @@ const char Archive::arfmag[2] = { '`', '
 // 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_obje
     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, 
             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, 
       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, 
   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
     }
 
   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* inp
 // 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* symta
 	      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* symta
   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_tabl
            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_tabl
            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* sy
   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* sy
         {
           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* sy
   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* sy
       // 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* 
 }
 
 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: archive.h
===================================================================
RCS file: /cvs/src/src/gold/archive.h,v
retrieving revision 1.24
diff -p -u -r1.24 archive.h
--- archive.h	19 Sep 2008 22:54:57 -0000	1.24
+++ archive.h	14 Mar 2009 05:35:02 -0000
@@ -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: dirsearch.cc
===================================================================
RCS file: /cvs/src/src/gold/dirsearch.cc,v
retrieving revision 1.10
diff -p -u -r1.10 dirsearch.cc
--- dirsearch.cc	13 Mar 2008 21:04:21 -0000	1.10
+++ dirsearch.cc	14 Mar 2009 05:35:02 -0000
@@ -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* workque
     }
 }
 
-// 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, c
           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, c
 	}
     }
 
+  *pindex = -2;
   return std::string();
 }
 
Index: dirsearch.h
===================================================================
RCS file: /cvs/src/src/gold/dirsearch.h,v
retrieving revision 1.6
diff -p -u -r1.6 dirsearch.h
--- dirsearch.h	13 Mar 2008 21:04:21 -0000	1.6
+++ dirsearch.h	14 Mar 2009 05:35:02 -0000
@@ -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: fileread.cc
===================================================================
RCS file: /cvs/src/src/gold/fileread.cc,v
retrieving revision 1.49
diff -p -u -r1.49 fileread.cc
--- fileread.cc	13 Mar 2009 21:30:06 -0000	1.49
+++ fileread.cc	14 Mar 2009 05:35:02 -0000
@@ -718,7 +718,7 @@ Input_file::Input_file(const Task* task,
   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& dirpat
 	  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& dirpat
         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: fileread.h
===================================================================
RCS file: /cvs/src/src/gold/fileread.h,v
retrieving revision 1.34
diff -p -u -r1.34 fileread.h
--- fileread.h	13 Mar 2009 21:30:06 -0000	1.34
+++ fileread.h	14 Mar 2009 05:35:03 -0000
@@ -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: gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.62
diff -p -u -r1.62 gold.cc
--- gold.cc	13 Mar 2009 21:30:06 -0000	1.62
+++ gold.cc	14 Mar 2009 05:35:03 -0000
@@ -183,7 +183,7 @@ queue_initial_tasks(const General_option
       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: object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.88
diff -p -u -r1.88 object.cc
--- object.cc	1 Mar 2009 22:22:02 -0000	1.88
+++ object.cc	14 Mar 2009 05:35:03 -0000
@@ -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,
 	  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,
 	  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,
 	  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,
 	  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: object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.71
diff -p -u -r1.71 object.h
--- object.h	1 Mar 2009 22:22:02 -0000	1.71
+++ object.h	14 Mar 2009 05:35:03 -0000
@@ -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: options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.95
diff -p -u -r1.95 options.h
--- options.h	28 Feb 2009 04:39:57 -0000	1.95
+++ options.h	14 Mar 2009 05:35:03 -0000
@@ -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: parameters.cc
===================================================================
RCS file: /cvs/src/src/gold/parameters.cc,v
retrieving revision 1.25
diff -p -u -r1.25 parameters.cc
--- parameters.cc	13 Mar 2008 21:04:21 -0000	1.25
+++ parameters.cc	14 Mar 2009 05:35:03 -0000
@@ -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: parameters.h
===================================================================
RCS file: /cvs/src/src/gold/parameters.h,v
retrieving revision 1.25
diff -p -u -r1.25 parameters.h
--- parameters.h	13 Mar 2008 21:04:21 -0000	1.25
+++ parameters.h	14 Mar 2009 05:35:03 -0000
@@ -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: plugin.cc
===================================================================
RCS file: /cvs/src/src/gold/plugin.cc,v
retrieving revision 1.13
diff -p -u -r1.13 plugin.cc
--- plugin.cc	13 Mar 2009 21:30:06 -0000	1.13
+++ plugin.cc	14 Mar 2009 05:35:04 -0000
@@ -411,6 +411,7 @@ Plugin_manager::add_input_file(char *pat
                                                 this->symtab_,
                                                 this->layout_,
                                                 this->dirpath_,
+						0,
                                                 this->mapfile_,
                                                 input_argument,
                                                 NULL,
Index: readsyms.cc
===================================================================
RCS file: /cvs/src/src/gold/readsyms.cc,v
retrieving revision 1.34
diff -p -u -r1.34 readsyms.cc
--- readsyms.cc	13 Mar 2009 21:30:06 -0000	1.34
+++ readsyms.cc	14 Mar 2009 05:35:04 -0000
@@ -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*
     }
 
   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*
 	  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->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->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*
 	{
 	  // 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->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->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* workqu
       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()))
+    {
+      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_))
     {
-      // FIXME: We need to close the descriptor here.
+      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: readsyms.h
===================================================================
RCS file: /cvs/src/src/gold/readsyms.h,v
retrieving revision 1.17
diff -p -u -r1.17 readsyms.h
--- readsyms.h	13 Mar 2009 21:30:06 -0000	1.17
+++ readsyms.h	14 Mar 2009 05:35:04 -0000
@@ -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: script-c.h
===================================================================
RCS file: /cvs/src/src/gold/script-c.h,v
retrieving revision 1.12
diff -p -u -r1.12 script-c.h
--- script-c.h	13 Aug 2008 07:37:46 -0000	1.12
+++ script-c.h	14 Mar 2009 05:35:04 -0000
@@ -245,6 +245,13 @@ script_set_common_allocation(void* closu
 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: script.cc
===================================================================
RCS file: /cvs/src/src/gold/script.cc,v
retrieving revision 1.50
diff -p -u -r1.50 script.cc
--- script.cc	13 Mar 2009 21:30:06 -0000	1.50
+++ script.cc	14 Mar 2009 05:35:04 -0000
@@ -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, 
 			 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, 
 	  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, C
     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, C
 			 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
   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 
   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, Exp
 {
   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, cons
       // 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 ch
   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: script.h
===================================================================
RCS file: /cvs/src/src/gold/script.h,v
retrieving revision 1.23
diff -p -u -r1.23 script.h
--- script.h	13 Mar 2009 21:30:06 -0000	1.23
+++ script.h	14 Mar 2009 05:35:04 -0000
@@ -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: workqueue.cc
===================================================================
RCS file: /cvs/src/src/gold/workqueue.cc,v
retrieving revision 1.10
diff -p -u -r1.10 workqueue.cc
--- workqueue.cc	13 Mar 2008 21:04:21 -0000	1.10
+++ workqueue.cc	14 Mar 2009 05:35:04 -0000
@@ -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: workqueue.h
===================================================================
RCS file: /cvs/src/src/gold/workqueue.h,v
retrieving revision 1.10
diff -p -u -r1.10 workqueue.h
--- workqueue.h	13 Mar 2008 21:04:21 -0000	1.10
+++ workqueue.h	14 Mar 2009 05:35:04 -0000
@@ -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: yyscript.y
===================================================================
RCS file: /cvs/src/src/gold/yyscript.y,v
retrieving revision 1.18
diff -p -u -r1.18 yyscript.y
--- yyscript.y	9 Dec 2008 16:09:32 -0000	1.18
+++ yyscript.y	14 Mar 2009 05:35:04 -0000
@@ -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.  */
Index: testsuite/binary_unittest.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/binary_unittest.cc,v
retrieving revision 1.5
diff -p -u -r1.5 binary_unittest.cc
--- testsuite/binary_unittest.cc	19 Apr 2008 18:30:58 -0000	1.5
+++ testsuite/binary_unittest.cc	14 Mar 2009 05:35:04 -0000
@@ -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: testsuite/object_unittest.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/object_unittest.cc,v
retrieving revision 1.5
diff -p -u -r1.5 object_unittest.cc
--- testsuite/object_unittest.cc	13 Mar 2008 21:04:21 -0000	1.5
+++ testsuite/object_unittest.cc	14 Mar 2009 05:35:04 -0000
@@ -43,7 +43,7 @@ Sized_object_test(const unsigned char* t
   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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]