Add 64-bit archive support.
authorMarcin Kościelnicki <koriakin@0x04.net>
Mon, 5 Oct 2015 14:57:12 +0000 (16:57 +0200)
committerCary Coutant <ccoutant@gmail.com>
Wed, 28 Oct 2015 23:46:07 +0000 (16:46 -0700)
gold/
* archive.cc (Archive::sym64name): New const.
(Archive::setup): Add support for SYM64 armap.
(Archive::read_armap): Likewise.
(Archive::interpret_header): Likewise.
(Archive::const_iterator::read_next_header): Likewise.
* archive.h (Archive::sym64name): New const.
(Archive::read_armap): Add mapsize template parameter.

gold/ChangeLog
gold/archive.cc
gold/archive.h

index e4558a8dcac294a76657fd313f0c3fcc4b9daea6..0957c53a94815cad37c0ef4bfc59a0f62b95f931 100644 (file)
@@ -1,3 +1,13 @@
+2015-10-28  Marcin Kościelnicki  <koriakin@0x04.net>
+
+       * archive.cc (Archive::sym64name): New const.
+       (Archive::setup): Add support for SYM64 armap.
+       (Archive::read_armap): Likewise.
+       (Archive::interpret_header): Likewise.
+       (Archive::const_iterator::read_next_header): Likewise.
+       * archive.h (Archive::sym64name): New const.
+       (Archive::read_armap): Add mapsize template parameter.
+
 2015-10-28  Marcin Kościelnicki  <koriakin@0x04.net>
 
        * dynobj.cc (Dynobj::create_elf_hash_table): Create hash table with
index cc69c40fb9887adea97a35dda4857c4a3783a959..9c001c20bad64fe3f5e2d8222dcef0b7dcd76ed8 100644 (file)
@@ -193,6 +193,8 @@ const char Archive::armagt[sarmag] =
 
 const char Archive::arfmag[2] = { '`', '\n' };
 
+const char Archive::sym64name[7] = { '/', 'S', 'Y', 'M', '6', '4', '/' };
+
 Archive::Archive(const std::string& name, Input_file* input_file,
                  bool is_thin_archive, Dirsearch* dirpath, Task* task)
   : Library_base(task), name_(name), input_file_(input_file), armap_(),
@@ -225,7 +227,12 @@ Archive::setup()
   off_t off = sarmag;
   if (armap_name.empty())
     {
-      this->read_armap(sarmag + sizeof(Archive_header), armap_size);
+      this->read_armap<32>(sarmag + sizeof(Archive_header), armap_size);
+      off = sarmag + sizeof(Archive_header) + armap_size;
+    }
+  else if (armap_name == "/SYM64/")
+    {
+      this->read_armap<64>(sarmag + sizeof(Archive_header), armap_size);
       off = sarmag + sizeof(Archive_header) + armap_size;
     }
   else if (!this->input_file_->options().whole_archive())
@@ -277,6 +284,7 @@ Archive::unlock_nested_archives()
 
 // Read the archive symbol map.
 
+template<int mapsize>
 void
 Archive::read_armap(off_t start, section_size_type size)
 {
@@ -290,8 +298,10 @@ Archive::read_armap(off_t start, section_size_type size)
   const unsigned char* p = this->get_view(start, size, true, false);
 
   // Numbers in the armap are always big-endian.
-  const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
-  unsigned int nsyms = elfcpp::Swap<32, true>::readval(pword);
+  typedef typename elfcpp::Elf_types<mapsize>::Elf_Addr Entry_type;
+  const Entry_type* pword = reinterpret_cast<const Entry_type*>(p);
+  unsigned long nsyms = convert_types<unsigned long, Entry_type>(
+    elfcpp::Swap<mapsize, true>::readval(pword));
   ++pword;
 
   // Note that the addition is in units of sizeof(elfcpp::Elf_Word).
@@ -303,10 +313,11 @@ Archive::read_armap(off_t start, section_size_type size)
   this->armap_.resize(nsyms);
 
   section_offset_type name_offset = 0;
-  for (unsigned int i = 0; i < nsyms; ++i)
+  for (unsigned long i = 0; i < nsyms; ++i)
     {
       this->armap_[i].name_offset = name_offset;
-      this->armap_[i].file_offset = elfcpp::Swap<32, true>::readval(pword);
+      this->armap_[i].file_offset = convert_types<off_t, Entry_type>(
+        elfcpp::Swap<mapsize, true>::readval(pword));
       name_offset += strlen(pnames + name_offset) + 1;
       ++pword;
       if (this->armap_[i].file_offset != last_seen_offset)
@@ -394,6 +405,11 @@ Archive::interpret_header(const Archive_header* hdr, off_t off,
       if (!pname->empty())
        pname->clear();
     }
+  else if (memcmp(hdr->ar_name, sym64name, sizeof sym64name) == 0)
+    {
+      // This is the symbol table, 64-bit version.
+      pname->assign(sym64name, sizeof sym64name);
+    }
   else if (hdr->ar_name[1] == '/')
     {
       // This is the extended name table.
@@ -544,7 +560,9 @@ Archive::const_iterator::read_next_header()
       this->header_.off = this->off_;
 
       // Skip special members.
-      if (!this->header_.name.empty() && this->header_.name != "/")
+      if (!this->header_.name.empty()
+         && this->header_.name != "/"
+         && this->header_.name != "/SYM64/")
        return;
 
       this->off_ += sizeof(Archive_header) + this->header_.size;
index 18cd899e9d86fa2299c5d69f0cd936327390f35e..66e4b2cee99e066468657ab0b6f44db0a6496fb6 100644 (file)
@@ -175,6 +175,9 @@ class Archive : public Library_base
   // The string expected at the end of an archive member header.
   static const char arfmag[2];
 
+  // Name of 64-bit symbol table member.
+  static const char sym64name[7];
+
   // The name of the object.  This is the name used on the command
   // line; e.g., if "-lgcc" is on the command line, this will be
   // "gcc".
@@ -290,6 +293,7 @@ class Archive : public Library_base
   { return this->input_file_->file().get_view(0, start, size, aligned, cache); }
 
   // Read the archive symbol map.
+  template<int mapsize>
   void
   read_armap(off_t start, section_size_type size);