* elfcpp_file.h (class Elf_file): Add large_shndx_offset_ field.
authorIan Lance Taylor <ian@airs.com>
Sat, 19 Apr 2008 18:33:19 +0000 (18:33 +0000)
committerIan Lance Taylor <ian@airs.com>
Sat, 19 Apr 2008 18:33:19 +0000 (18:33 +0000)
(Elf_file::large_shndx_offset): New function.
(Elf_file::construct): Initialize large_shndx_offset_.
(Elf_File::initialize_shnum): If necessary, adjust shstrndx_ and
set large_shndx_offset_.

elfcpp/ChangeLog
elfcpp/elfcpp_file.h

index c543d830a14b47286b106374cc78fcc85a701a79..63e0ac02675faa1c1058f408c69106cdd6f8a39e 100644 (file)
@@ -1,3 +1,11 @@
+2008-04-19  Ian Lance Taylor  <iant@google.com>
+
+       * elfcpp_file.h (class Elf_file): Add large_shndx_offset_ field.
+       (Elf_file::large_shndx_offset): New function.
+       (Elf_file::construct): Initialize large_shndx_offset_.
+       (Elf_File::initialize_shnum): If necessary, adjust shstrndx_ and
+       set large_shndx_offset_.
+
 2008-04-16  David S. Miller  <davem@davemloft.net>
 
        * elfcpp.h (DF_1_NOW, DF_1_GLOBAL, DF_1_GROUP,
index 431f8efabeef8aa7365a1f626c09b0e905dbeac8..f1f4423a14e88f790b025f732105a3f4d7cfa171 100644 (file)
@@ -115,6 +115,15 @@ class Elf_file
     return this->shstrndx_;
   }
 
+  // Return the value to subtract from section indexes >=
+  // SHN_LORESERVE.  See the comment in initialize_shnum.
+  int
+  large_shndx_offset()
+  {
+    this->initialize_shnum();
+    return this->large_shndx_offset_;
+  }
+
   // Return the location of the header of section SHNDX.
   typename File::Location
   section_header(unsigned int shndx)
@@ -180,6 +189,8 @@ class Elf_file
   unsigned int shnum_;
   // The section index of the section name string table.
   unsigned int shstrndx_;
+  // Offset to add to sections larger than SHN_LORESERVE.
+  int large_shndx_offset_;
 };
 
 // Template function definitions.
@@ -194,6 +205,7 @@ Elf_file<size, big_endian, File>::construct(File* file, const Ef_ehdr& ehdr)
   this->shoff_ = ehdr.get_e_shoff();
   this->shnum_ = ehdr.get_e_shnum();
   this->shstrndx_ = ehdr.get_e_shstrndx();
+  this->large_shndx_offset_ = 0;
   if (ehdr.get_e_ehsize() != This::ehdr_size)
     file->error(_("bad e_ehsize (%d != %d)"),
                ehdr.get_e_ehsize(), This::ehdr_size);
@@ -223,10 +235,37 @@ Elf_file<size, big_endian, File>::initialize_shnum()
     {
       typename File::View v(this->file_->view(this->shoff_, This::shdr_size));
       Ef_shdr shdr(v.data());
+
       if (this->shnum_ == 0)
        this->shnum_ = shdr.get_sh_size();
+
       if (this->shstrndx_ == SHN_XINDEX)
-       this->shstrndx_ = shdr.get_sh_link();
+       {
+         this->shstrndx_ = shdr.get_sh_link();
+
+         // Versions of the GNU binutils between 2.12 and 2.18 did
+         // not handle objects with more than SHN_LORESERVE sections
+         // correctly.  All large section indexes were offset by
+         // 0x100.  Some information can be found here:
+         // http://sourceware.org/bugzilla/show_bug.cgi?id=5900 .
+         // Fortunately these object files are easy to detect, as the
+         // GNU binutils always put the section header string table
+         // near the end of the list of sections.  Thus if the
+         // section header string table index is larger than the
+         // number of sections, then we know we have to subtract
+         // 0x100 to get the real section index.
+         if (this->shstrndx_ >= this->shnum_)
+           {
+             if (this->shstrndx_ >= elfcpp::SHN_LORESERVE + 0x100)
+               {
+                 this->large_shndx_offset_ = - 0x100;
+                 this->shstrndx_ -= 0x100;
+               }
+             if (this->shstrndx_ >= this->shnum_)
+               this->file_->error(_("bad shstrndx: %u >= %u"),
+                                  this->shstrndx_, this->shnum_);
+           }
+       }
     }
 }