Add icf_virtual_function_folding_test to check_PROGRAMS.
[binutils-gdb.git] / gold / archive.cc
index 8e809e25d1cce99fcfeba6422fdb48bd622062a4..36e4862871e28e105b27b4eca97d1ddb0e03490a 100644 (file)
@@ -1,6 +1,6 @@
 // archive.cc -- archive support for gold
 
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -275,7 +275,8 @@ Archive::interpret_header(const Archive_header* hdr, off_t off,
   else if (hdr->ar_name[1] == ' ')
     {
       // This is the symbol table.
-      pname->clear();
+      if (!pname->empty())
+       pname->clear();
     }
   else if (hdr->ar_name[1] == '/')
     {
@@ -489,8 +490,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff,
       else
         {
           Input_file_argument* input_file_arg =
-            new Input_file_argument(member_name->c_str(), false, "", false,
-                                    parameters->options());
+            new Input_file_argument(member_name->c_str(),
+                                    Input_file_argument::INPUT_FILE_TYPE_FILE,
+                                    "", false, parameters->options());
           *input_file = new Input_file(input_file_arg);
          int dummy = 0;
           if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
@@ -509,8 +511,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff,
   // This is an external member of a thin archive.  Open the
   // file as a regular relocatable object file.
   Input_file_argument* input_file_arg =
-      new Input_file_argument(member_name->c_str(), false, "", false,
-                              this->input_file_->options());
+      new Input_file_argument(member_name->c_str(),
+                              Input_file_argument::INPUT_FILE_TYPE_FILE,
+                              "", false, this->input_file_->options());
   *input_file = new Input_file(input_file_arg);
   int dummy = 0;
   if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
@@ -564,6 +567,8 @@ Archive::get_elf_object_for_member(off_t off, bool* punconfigured)
                                 + "(" + member_name + ")"),
                                input_file, memoff, ehdr, read_size,
                                punconfigured);
+  if (obj == NULL)
+    return NULL;
   obj->set_no_export(this->no_export());
   return obj;
 }
@@ -597,6 +602,68 @@ Archive::read_symbols(off_t off)
   this->members_[off] = member;
 }
 
+Archive::Should_include
+Archive::should_include_member(Symbol_table* symtab, const char* sym_name,
+                               Symbol** symp, std::string* why, char** tmpbufp,
+                               size_t* tmpbuflen)
+{
+  // In an object file, and therefore in an archive map, an
+  // '@' in the name separates the symbol name from the
+  // version name.  If there are two '@' characters, this is
+  // the default version.
+  char* tmpbuf = *tmpbufp;
+  const char* ver = strchr(sym_name, '@');
+  bool def = false;
+  if (ver != NULL)
+    {
+      size_t symlen = ver - sym_name;
+      if (symlen + 1 > *tmpbuflen)
+        {
+          tmpbuf = static_cast<char*>(xrealloc(tmpbuf, symlen + 1));
+          *tmpbufp = tmpbuf;
+          *tmpbuflen = symlen + 1;
+        }
+      memcpy(tmpbuf, sym_name, symlen);
+      tmpbuf[symlen] = '\0';
+      sym_name = tmpbuf;
+
+      ++ver;
+      if (*ver == '@')
+        {
+          ++ver;
+          def = true;
+        }
+    }
+
+  Symbol* sym = symtab->lookup(sym_name, ver);
+  if (def
+      && ver != NULL
+      && (sym == NULL
+          || !sym->is_undefined()
+          || sym->binding() == elfcpp::STB_WEAK))
+    sym = symtab->lookup(sym_name, NULL);
+
+  *symp = sym;
+
+  if (sym == NULL)
+    {
+      // Check whether the symbol was named in a -u option.
+      if (!parameters->options().is_undefined(sym_name))
+       return Archive::SHOULD_INCLUDE_UNKNOWN;
+      else
+        {
+          *why = "-u ";
+          *why += sym_name;
+        }
+    }
+  else if (!sym->is_undefined())
+    return Archive::SHOULD_INCLUDE_NO;
+  else if (sym->binding() == elfcpp::STB_WEAK)
+    return Archive::SHOULD_INCLUDE_UNKNOWN;
+
+  return Archive::SHOULD_INCLUDE_YES;
+}
+
 // Select members from the archive and add them to the link.  We walk
 // through the elements in the archive map, and look each one up in
 // the symbol table.  If it exists as a strong undefined symbol, we
@@ -656,64 +723,23 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
          const char* sym_name = (this->armap_names_.data()
                                  + this->armap_[i].name_offset);
 
-         // In an object file, and therefore in an archive map, an
-         // '@' in the name separates the symbol name from the
-         // version name.  If there are two '@' characters, this is
-         // the default version.
-         const char* ver = strchr(sym_name, '@');
-         bool def = false;
-         if (ver != NULL)
-           {
-             size_t symlen = ver - sym_name;
-             if (symlen + 1 > tmpbuflen)
-               {
-                 tmpbuf = static_cast<char*>(realloc(tmpbuf, symlen + 1));
-                 tmpbuflen = symlen + 1;
-               }
-             memcpy(tmpbuf, sym_name, symlen);
-             tmpbuf[symlen] = '\0';
-             sym_name = tmpbuf;
-
-             ++ver;
-             if (*ver == '@')
-               {
-                 ++ver;
-                 def = true;
-               }
-           }
+          Symbol* sym;
+          std::string why;
+          Archive::Should_include t =
+              Archive::should_include_member(symtab, sym_name, &sym, &why,
+                                             &tmpbuf, &tmpbuflen);
 
-         Symbol* sym = symtab->lookup(sym_name, ver);
-         if (def
-             && (sym == NULL
-                 || !sym->is_undefined()
-                 || sym->binding() == elfcpp::STB_WEAK))
-           sym = symtab->lookup(sym_name, NULL);
+         if (t == Archive::SHOULD_INCLUDE_NO
+              || t == Archive::SHOULD_INCLUDE_YES)
+           this->armap_checked_[i] = true;
 
-         if (sym == NULL)
-           {
-             // Check whether the symbol was named in a -u option.
-             if (!parameters->options().is_undefined(sym_name))
-               continue;
-           }
-         else if (!sym->is_undefined())
-           {
-              this->armap_checked_[i] = true;
-             continue;
-           }
-         else if (sym->binding() == elfcpp::STB_WEAK)
+         if (t != Archive::SHOULD_INCLUDE_YES)
            continue;
 
          // We want to include this object in the link.
          last_seen_offset = this->armap_[i].file_offset;
          this->seen_offsets_.insert(last_seen_offset);
-          this->armap_checked_[i] = true;
 
-         std::string why;
-         if (sym == NULL)
-           {
-             why = "-u ";
-             why += sym_name;
-           }
          if (!this->include_member(symtab, layout, input_objects,
                                    last_seen_offset, mapfile, sym,
                                    why.c_str()))
@@ -807,11 +833,6 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
     {
       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);
@@ -830,9 +851,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
 
   if (!this->included_member_
       && this->searched_for()
-      && (obj == NULL
-         ? unconfigured
-         : !parameters->is_compatible_target(obj->target())))
+      && obj == NULL
+      && unconfigured)
     {
       if (obj != NULL)
        delete obj;
@@ -857,10 +877,12 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
     delete obj;
   else
     {
-      Read_symbols_data sd;
-      obj->read_symbols(&sd);
-      obj->layout(symtab, layout, &sd);
-      obj->add_symbols(symtab, &sd, layout);
+      {
+       Read_symbols_data sd;
+       obj->read_symbols(&sd);
+       obj->layout(symtab, layout, &sd);
+       obj->add_symbols(symtab, &sd, layout);
+      }
 
       // If this is an external member of a thin archive, unlock the file
       // for the next task.
@@ -949,4 +971,145 @@ Add_archive_symbols::run(Workqueue* workqueue)
     }
 }
 
+// Class Lib_group static variables.
+unsigned int Lib_group::total_lib_groups;
+unsigned int Lib_group::total_members;
+unsigned int Lib_group::total_members_loaded;
+
+Lib_group::Lib_group(const Input_file_lib* lib, Task* task)
+  : lib_(lib), task_(task), members_()
+{
+  this->members_.resize(lib->size());
+}
+
+// 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.
+// 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.
+
+void
+Lib_group::add_symbols(Symbol_table* symtab, Layout* layout,
+                       Input_objects* input_objects)
+{
+  ++Lib_group::total_lib_groups;
+
+  Lib_group::total_members += this->members_.size();
+
+  bool added_new_object;
+  do
+    {
+      added_new_object = false;
+      unsigned int i = 0;
+      while (i < this->members_.size())
+       {
+         const Archive_member& member = this->members_[i];
+         Object *obj = member.obj_;
+         std::string why;
+
+          // Skip files with no symbols. Plugin objects have
+          // member.sd_ == NULL.
+          if (obj != NULL
+             && (member.sd_ == NULL || member.sd_->symbol_names != NULL))
+            {
+             Archive::Should_include t = obj->should_include_member(symtab,
+                                                                    member.sd_,
+                                                                    &why);
+
+             if (t != Archive::SHOULD_INCLUDE_YES)
+               {
+                 ++i;
+                 continue;
+               }
+
+             this->include_member(symtab, layout, input_objects, member);
+
+             added_new_object = true;
+           }
+          else
+            {
+              if (member.sd_ != NULL)
+                delete member.sd_;
+            }
+
+         this->members_[i] = this->members_.back();
+         this->members_.pop_back();
+       }
+    }
+  while (added_new_object);
+}
+
+// Include a lib group member in the link.
+
+void
+Lib_group::include_member(Symbol_table* symtab, Layout* layout,
+                         Input_objects* input_objects,
+                         const Archive_member& member)
+{
+  ++Lib_group::total_members_loaded;
+
+  Object* obj = member.obj_;
+  gold_assert(obj != NULL);
+
+  Pluginobj* pluginobj = obj->pluginobj();
+  if (pluginobj != NULL)
+    {
+      pluginobj->add_symbols(symtab, NULL, layout);
+      return;
+    }
+
+  Read_symbols_data* sd = member.sd_;
+  gold_assert(sd != NULL);
+  obj->lock(this->task_);
+  if (input_objects->add_object(obj))
+    {
+      obj->layout(symtab, layout, sd);
+      obj->add_symbols(symtab, sd, layout);
+      // Unlock the file for the next task.
+      obj->unlock(this->task_);
+    }
+  delete sd;
+}
+
+// Print statistical information to stderr.  This is used for --stats.
+
+void
+Lib_group::print_stats()
+{
+  fprintf(stderr, _("%s: lib groups: %u\n"),
+          program_name, Lib_group::total_lib_groups);
+  fprintf(stderr, _("%s: total lib groups members: %u\n"),
+          program_name, Lib_group::total_members);
+  fprintf(stderr, _("%s: loaded lib groups members: %u\n"),
+          program_name, Lib_group::total_members_loaded);
+}
+
+Task_token*
+Add_lib_group_symbols::is_runnable()
+{
+  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+    return this->this_blocker_;
+  return NULL;
+}
+
+void
+Add_lib_group_symbols::locks(Task_locker* tl)
+{
+  tl->add(this, this->next_blocker_);
+}
+
+void
+Add_lib_group_symbols::run(Workqueue*)
+{
+  this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_);
+}
+
+Add_lib_group_symbols::~Add_lib_group_symbols()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the next
+  // input file.
+}
+
 } // End namespace gold.