PR binutils/12523
[deliverable/binutils-gdb.git] / gold / archive.cc
index f1000a195de25c38588ae3960188767cc7fae337..89fc422f05fcb5d8ec439fb2e179a659af15c0fc 100644 (file)
@@ -1,6 +1,6 @@
 // archive.cc -- archive support for gold
 
-// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
 #include "layout.h"
 #include "archive.h"
 #include "plugin.h"
+#include "incremental.h"
 
 namespace gold
 {
 
 // The header of an entry in the archive.  This is all readable text,
-// padded with spaces where necesary.  If the contents of an archive
+// padded with spaces where necessary.  If the contents of an archive
 // are all text file, the entire archive is readable.
 
 struct Archive::Archive_header
@@ -89,7 +90,8 @@ Archive::Archive(const std::string& name, Input_file* input_file,
   : name_(name), input_file_(input_file), armap_(), armap_names_(),
     extended_names_(), armap_checked_(), seen_offsets_(), members_(),
     is_thin_archive_(is_thin_archive), included_member_(false),
-    nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0)
+    nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0),
+    incremental_info_(NULL)
 {
   this->no_export_ =
     parameters->options().check_excluded_libs(input_file->found_name());
@@ -525,14 +527,16 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff,
   return true;
 }
 
-// Return an ELF object for the member at offset OFF.  If the ELF
-// object has an unsupported target type, set *PUNCONFIGURED to true
-// and return NULL.
+// Return an ELF object for the member at offset OFF.  If
+// PUNCONFIGURED is not NULL, then if the ELF object has an
+// unsupported target type, set *PUNCONFIGURED to true and return
+// NULL.
 
 Object*
 Archive::get_elf_object_for_member(off_t off, bool* punconfigured)
 {
-  *punconfigured = false;
+  if (punconfigured != NULL)
+    *punconfigured = false;
 
   Input_file* input_file;
   off_t memoff;
@@ -564,7 +568,7 @@ Archive::get_elf_object_for_member(off_t off, bool* punconfigured)
       return NULL;
     }
 
-  Object *obj = make_elf_object((std::string(this->input_file_->filename())
+  Objectobj = make_elf_object((std::string(this->input_file_->filename())
                                 + "(" + member_name + ")"),
                                input_file, memoff, ehdr, read_size,
                                punconfigured);
@@ -591,9 +595,7 @@ Archive::read_all_symbols()
 void
 Archive::read_symbols(off_t off)
 {
-  bool dummy;
-  Object* obj = this->get_elf_object_for_member(off, &dummy);
-
+  Object* obj = this->get_elf_object_for_member(off, NULL);
   if (obj == NULL)
     return;
 
@@ -669,6 +671,10 @@ Archive::should_include_member(Symbol_table* symtab, Layout* layout,
     }
   else if (!sym->is_undefined())
     return Archive::SHOULD_INCLUDE_NO;
+  // PR 12001: Do not include an archive when the undefined
+  // symbol has actually been defined on the command line.
+  else if (layout->script_options()->is_pending_assignment(sym_name))
+    return Archive::SHOULD_INCLUDE_NO;
   else if (sym->binding() == elfcpp::STB_WEAK)
     return Archive::SHOULD_INCLUDE_UNKNOWN;
 
@@ -773,6 +779,42 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
   return true;
 }
 
+// Return whether the archive includes a member which defines the
+// symbol SYM.
+
+bool
+Archive::defines_symbol(Symbol* sym) const
+{
+  const char* symname = sym->name();
+  size_t symname_len = strlen(symname);
+  size_t armap_size = this->armap_.size();
+  for (size_t i = 0; i < armap_size; ++i)
+    {
+      if (this->armap_checked_[i])
+       continue;
+      const char* archive_symname = (this->armap_names_.data()
+                                    + this->armap_[i].name_offset);
+      if (strncmp(archive_symname, symname, symname_len) != 0)
+       continue;
+      char c = archive_symname[symname_len];
+      if (c == '\0' && sym->version() == NULL)
+       return true;
+      if (c == '@')
+       {
+         const char* ver = archive_symname + symname_len + 1;
+         if (*ver == '@')
+           {
+             if (sym->version() == NULL)
+               return true;
+             ++ver;
+           }
+         if (sym->version() != NULL && strcmp(sym->version(), ver) == 0)
+           return true;
+       }
+    }
+  return false;
+}
+
 // Include all the archive members in the link.  This is for --whole-archive.
 
 bool
@@ -842,9 +884,9 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
   std::map<off_t, Archive_member>::const_iterator p = this->members_.find(off);
   if (p != this->members_.end())
     {
-      Object *obj = p->second.obj_;
+      Objectobj = p->second.obj_;
 
-      Read_symbols_data *sd = p->second.sd_;
+      Read_symbols_datasd = p->second.sd_;
       if (mapfile != NULL)
         mapfile->report_include_archive_member(obj->name(), sym, why);
       if (input_objects->add_object(obj))
@@ -857,17 +899,22 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
       return true;
     }
 
-  bool unconfigured;
-  Object* obj = this->get_elf_object_for_member(off, &unconfigured);
-
-  if (!this->included_member_
-      && this->searched_for()
-      && obj == NULL
-      && unconfigured)
-    return false;
+  // If this is the first object we are including from this archive,
+  // and we searched for this archive, most likely because it was
+  // found via a -l option, then if the target is incompatible we want
+  // to move on to the next archive found in the search path.
+  bool unconfigured = false;
+  bool* punconfigured = NULL;
+  if (!this->included_member_ && this->searched_for())
+    punconfigured = &unconfigured;
 
+  Object* obj = this->get_elf_object_for_member(off, punconfigured);
   if (obj == NULL)
-    return true;
+    {
+      // Return false to search for another archive, true if we found
+      // an error.
+      return unconfigured ? false : true;
+    }
 
   if (mapfile != NULL)
     mapfile->report_include_archive_member(obj->name(), sym, why);
@@ -891,6 +938,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
   else
     {
       {
+       if (layout->incremental_inputs() != NULL)
+         layout->incremental_inputs()->report_object(obj, this);
        Read_symbols_data sd;
        obj->read_symbols(&sd);
        obj->layout(symtab, layout, &sd);
@@ -952,6 +1001,11 @@ Add_archive_symbols::locks(Task_locker* tl)
 void
 Add_archive_symbols::run(Workqueue* workqueue)
 {
+  // For an incremental link, begin recording layout information.
+  Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+  if (incremental_inputs != NULL)
+    incremental_inputs->report_archive_begin(this->archive_);
+
   bool added = this->archive_->add_symbols(this->symtab_, this->layout_,
                                           this->input_objects_,
                                           this->mapfile_);
@@ -978,8 +1032,23 @@ Add_archive_symbols::run(Workqueue* workqueue)
     this->input_group_->add_archive(this->archive_);
   else
     {
-      // We no longer need to know about this archive.
-      delete this->archive_;
+      // For an incremental link, finish recording the layout information.
+      Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+      if (incremental_inputs != NULL)
+       incremental_inputs->report_archive_end(this->archive_);
+
+      if (!parameters->options().has_plugins()
+         || this->archive_->input_file()->options().whole_archive())
+       {
+         // We no longer need to know about this archive.
+         delete this->archive_;
+       }
+      else
+       {
+         // The plugin interface may want to rescan this archive.
+         parameters->options().plugins()->save_archive(this->archive_);
+       }
+
       this->archive_ = NULL;
     }
 }
@@ -996,7 +1065,7 @@ Lib_group::Lib_group(const Input_file_lib* lib, Task* task)
 }
 
 // Select members from the lib group and add them to the link.  We walk
-// through the the members, and check if each one up should be included.
+// through the members, and check if each one up should be included.
 // If the object says it should be included, we do so.  We have to do
 // this in a loop, since including one member may create new undefined
 // symbols which may be satisfied by other members.
@@ -1017,7 +1086,7 @@ Lib_group::add_symbols(Symbol_table* symtab, Layout* layout,
       while (i < this->members_.size())
        {
          const Archive_member& member = this->members_[i];
-         Object *obj = member.obj_;
+         Objectobj = member.obj_;
          std::string why;
 
           // Skip files with no symbols. Plugin objects have
@@ -1043,7 +1112,14 @@ Lib_group::add_symbols(Symbol_table* symtab, Layout* layout,
           else
             {
               if (member.sd_ != NULL)
-                delete member.sd_;
+               {
+                 // The file must be locked in order to destroy the views
+                 // associated with it.
+                 gold_assert(obj != NULL);
+                 obj->lock(this->task_);
+                 delete member.sd_;
+                 obj->unlock(this->task_);
+               }
             }
 
          this->members_[i] = this->members_.back();
@@ -1077,12 +1153,15 @@ Lib_group::include_member(Symbol_table* symtab, Layout* layout,
   obj->lock(this->task_);
   if (input_objects->add_object(obj))
     {
+      // FIXME: Record incremental link info for --start-lib/--end-lib.
+      if (layout->incremental_inputs() != NULL)
+       layout->incremental_inputs()->report_object(obj, NULL);
       obj->layout(symtab, layout, sd);
       obj->add_symbols(symtab, sd, layout);
-      // Unlock the file for the next task.
-      obj->unlock(this->task_);
     }
   delete sd;
+  // Unlock the file for the next task.
+  obj->unlock(this->task_);
 }
 
 // Print statistical information to stderr.  This is used for --stats.
@@ -1101,6 +1180,8 @@ Lib_group::print_stats()
 Task_token*
 Add_lib_group_symbols::is_runnable()
 {
+  if (this->readsyms_blocker_ != NULL && this->readsyms_blocker_->is_blocked())
+    return this->readsyms_blocker_;
   if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
     return this->this_blocker_;
   return NULL;
@@ -1116,6 +1197,8 @@ void
 Add_lib_group_symbols::run(Workqueue*)
 {
   this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_);
+
+  // FIXME: Record incremental link info for --start_lib/--end_lib.
 }
 
 Add_lib_group_symbols::~Add_lib_group_symbols()
This page took 0.026155 seconds and 4 git commands to generate.