Implement --whole-archive.
[deliverable/binutils-gdb.git] / gold / archive.cc
index 601932520412d6705d287b7fa31f598a067d09d6..51a0f484453c052c6a4b9ea85d1a1d81cab02422 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "elfcpp.h"
 #include "fileread.h"
+#include "readsyms.h"
 #include "symtab.h"
 #include "object.h"
 #include "archive.h"
@@ -47,14 +48,6 @@ const char Archive::armag[sarmag] =
 
 const char Archive::arfmag[2] = { '`', '\n' };
 
-// Get a view into the underlying file.
-
-const unsigned char*
-Archive::get_view(off_t start, off_t size)
-{
-  return this->input_file_->file().get_view(start, size);
-}
-
 // Set up the archive: read the symbol map and the extended name
 // table.
 
@@ -64,20 +57,49 @@ Archive::setup()
   // The first member of the archive should be the symbol table.
   std::string armap_name;
   off_t armap_size = this->read_header(sarmag, &armap_name);
-  if (!armap_name.empty())
+  off_t off;
+  if (armap_name.empty())
+    {
+      this->read_armap(sarmag + sizeof(Archive_header), armap_size);
+      off = sarmag + sizeof(Archive_header) + armap_size;
+    }
+  else if (!this->input_file_->options().include_whole_archive())
     {
       fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
              program_name, this->name().c_str());
       gold_exit(false);
     }
+  else
+    off = sarmag;
 
+  // See if there is an extended name table.
+  if ((off & 1) != 0)
+    ++off;
+  std::string xname;
+  off_t extended_size = this->read_header(off, &xname);
+  if (xname == "/")
+    {
+      const unsigned char* p = this->get_view(off + sizeof(Archive_header),
+                                              extended_size);
+      const char* px = reinterpret_cast<const char*>(p);
+      this->extended_names_.assign(px, extended_size);
+    }
+
+  // Opening the file locked it.  Unlock it now.
+  this->input_file_->file().unlock();
+}
+
+// Read the archive symbol map.
+
+void
+Archive::read_armap(off_t start, off_t size)
+{
   // Read in the entire armap.
-  const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
-                                         armap_size);
+  const unsigned char* p = this->get_view(start, size);
 
   // Numbers in the armap are always big-endian.
   const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
-  unsigned int nsyms = elfcpp::read_elf_word<true>(pword);
+  unsigned int nsyms = elfcpp::Swap<32, true>::readval(pword);
   ++pword;
 
   // Note that the addition is in units of sizeof(elfcpp::Elf_Word).
@@ -88,33 +110,21 @@ Archive::setup()
   for (unsigned int i = 0; i < nsyms; ++i)
     {
       this->armap_[i].name = pnames;
-      this->armap_[i].offset = elfcpp::read_elf_word<true>(pword);
+      this->armap_[i].offset = elfcpp::Swap<32, true>::readval(pword);
       pnames += strlen(pnames) + 1;
       ++pword;
     }
 
-  if (reinterpret_cast<const unsigned char*>(pnames) - p > armap_size)
+  if (reinterpret_cast<const unsigned char*>(pnames) - p > size)
     {
       fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
              program_name, this->name().c_str());
       gold_exit(false);
     }
 
-  // See if there is an extended name table.
-  off_t off = sarmag + sizeof(Archive_header) + armap_size;
-  if ((off & 1) != 0)
-    ++off;
-  std::string xname;
-  off_t extended_size = this->read_header(off, &xname);
-  if (xname == "/")
-    {
-      p = this->get_view(off + sizeof(Archive_header), extended_size);
-      const char* px = reinterpret_cast<const char*>(p);
-      this->extended_names_.assign(px, extended_size);
-    }
-
-  // Opening the file locked it.  Unlock it now.
-  this->input_file_->file().unlock();
+  // This array keeps track of which symbols are for archive elements
+  // which we have already included in the link.
+  this->seen_.resize(nsyms);
 }
 
 // Read the header of an archive member at OFF.  Fail if something
@@ -126,7 +136,17 @@ Archive::read_header(off_t off, std::string* pname)
 {
   const unsigned char* p = this->get_view(off, sizeof(Archive_header));
   const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
+  return this->interpret_header(hdr, off,  pname);
+}
+
+// Interpret the header of HDR, the header of the archive member at
+// file offset OFF.  Fail if something goes wrong.  Return the size of
+// the member.  Set *PNAME to the name of the member.
 
+off_t
+Archive::interpret_header(const Archive_header* hdr, off_t off,
+                          std::string* pname)
+{
   if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
     {
       fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
@@ -218,12 +238,13 @@ Archive::read_header(off_t off, std::string* pname)
 // may be satisfied by other objects in the archive.
 
 void
-Archive::add_symbols(Symbol_table* symtab, Input_objects* input_objects)
+Archive::add_symbols(const General_options& options, Symbol_table* symtab,
+                    Layout* layout, Input_objects* input_objects)
 {
-  size_t armap_size = this->armap_.size();
-  std::vector<bool> seen;
-  seen.resize(this->armap_.size());
-  seen.clear();
+  if (this->input_file_->options().include_whole_archive())
+    return this->include_all_members(options, symtab, layout, input_objects);
+
+  const size_t armap_size = this->armap_.size();
 
   bool added_new_object;
   do
@@ -232,20 +253,20 @@ Archive::add_symbols(Symbol_table* symtab, Input_objects* input_objects)
       off_t last = -1;
       for (size_t i = 0; i < armap_size; ++i)
        {
-         if (seen[i])
+         if (this->seen_[i])
            continue;
          if (this->armap_[i].offset == last)
            {
-             seen[i] = true;
+             this->seen_[i] = true;
              continue;
            }
 
          Symbol* sym = symtab->lookup(this->armap_[i].name);
          if (sym == NULL)
            continue;
-         else if (sym->shnum() != elfcpp::SHN_UNDEF)
+         else if (!sym->is_undefined())
            {
-             seen[i] = true;
+             this->seen_[i] = true;
              continue;
            }
          else if (sym->binding() == elfcpp::STB_WEAK)
@@ -253,18 +274,66 @@ Archive::add_symbols(Symbol_table* symtab, Input_objects* input_objects)
 
          // We want to include this object in the link.
          last = this->armap_[i].offset;
-         this->include_member(symtab, input_objects, last);
+         this->include_member(options, symtab, layout, input_objects, last);
+         this->seen_[i] = true;
          added_new_object = true;
        }
     }
   while (added_new_object);
 }
 
+// Include all the archive members in the link.  This is for --whole-archive.
+
+void
+Archive::include_all_members(const General_options& options,
+                             Symbol_table* symtab, Layout* layout,
+                             Input_objects* input_objects)
+{
+  off_t off = sarmag;
+  while (true)
+    {
+      off_t bytes;
+      const unsigned char* p = this->get_view(off, sizeof(Archive_header),
+                                              &bytes);
+      if (bytes < sizeof(Archive_header))
+        {
+          if (bytes != 0)
+            {
+              fprintf(stderr, _("%s: %s: short archive header at %ld\n"),
+                      program_name, this->name().c_str(),
+                      static_cast<long>(off));
+              gold_exit(false);
+            }
+
+          break;
+        }
+
+      const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
+      std::string name;
+      off_t size = this->interpret_header(hdr, off, &name);
+      if (name.empty())
+        {
+          // Symbol table.
+        }
+      else if (name == "/")
+        {
+          // Extended name table.
+        }
+      else
+        this->include_member(options, symtab, layout, input_objects, off);
+
+      off += sizeof(Archive_header) + size;
+      if ((off & 1) != 0)
+        ++off;
+    }
+}
+
 // Include an archive member in the link.  OFF is the file offset of
 // the member header.
 
 void
-Archive::include_member(Symbol_table* symtab, Input_objects* input_objects,
+Archive::include_member(const General_options& options, Symbol_table* symtab,
+                       Layout* layout, Input_objects* input_objects,
                        off_t off)
 {
   std::string n;
@@ -299,14 +368,16 @@ Archive::include_member(Symbol_table* symtab, Input_objects* input_objects,
       gold_exit(false);
     }
 
-  Object* obj = make_elf_object((std::string(this->input_file_->name())
+  Object* obj = make_elf_object((std::string(this->input_file_->filename())
                                 + "(" + n + ")"),
                                this->input_file_, memoff, p, bytes);
 
   input_objects->add_object(obj);
 
-  Read_symbols_data sd = obj->read_symbols();
-  obj->add_symbols(symtab, sd);
+  Read_symbols_data sd;
+  obj->read_symbols(&sd);
+  obj->layout(options, symtab, layout, &sd);
+  obj->add_symbols(symtab, &sd);
 }
 
 // Add_archive_symbols methods.
@@ -334,13 +405,13 @@ class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
 {
  public:
   Add_archive_symbols_locker(Task_token& token, Workqueue* workqueue,
-                            Archive* archive)
-    : blocker_(token, workqueue), archlock_(*archive)
+                            File_read& file)
+    : blocker_(token, workqueue), filelock_(file)
   { }
 
  private:
   Task_locker_block blocker_;
-  Task_locker_obj<Archive> archlock_;                       
+  Task_locker_obj<File_read> filelock_;
 };
 
 Task_locker*
@@ -348,13 +419,22 @@ Add_archive_symbols::locks(Workqueue* workqueue)
 {
   return new Add_archive_symbols_locker(*this->next_blocker_,
                                        workqueue,
-                                       this->archive_);
+                                       this->archive_->file());
 }
 
 void
 Add_archive_symbols::run(Workqueue*)
 {
-  this->archive_->add_symbols(this->symtab_, this->input_objects_);
+  this->archive_->add_symbols(this->options_, this->symtab_, this->layout_,
+                              this->input_objects_);
+
+  if (this->input_group_ != NULL)
+    this->input_group_->add_archive(this->archive_);
+  else
+    {
+      // We no longer need to know about this archive.
+      delete this->archive_;
+    }
 }
 
 } // End namespace gold.
This page took 0.048861 seconds and 4 git commands to generate.