Hash tables, dynamic section, i386 PLT, gold_assert.
authorIan Lance Taylor <iant@google.com>
Wed, 29 Nov 2006 17:56:40 +0000 (17:56 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 29 Nov 2006 17:56:40 +0000 (17:56 +0000)
33 files changed:
elfcpp/elfcpp.h
elfcpp/elfcpp_file.h
elfcpp/elfcpp_swap.h
gold/common.cc
gold/dirsearch.cc
gold/dynobj.cc
gold/dynobj.h
gold/fileread.cc
gold/gold-threads.cc
gold/gold.cc
gold/gold.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/po/gold.pot
gold/readsyms.cc
gold/reloc.cc
gold/reloc.h
gold/resolve.cc
gold/script.cc
gold/stringpool.cc
gold/stringpool.h
gold/symtab.cc
gold/symtab.h
gold/target-reloc.h
gold/target.h
gold/workqueue.cc

index afbd74d..ba85b3d 100644 (file)
@@ -1304,6 +1304,32 @@ class Dyn
   const internal::Dyn_data<size>* p_;
 };
 
+// Write class for an entry in the SHT_DYNAMIC section.
+
+template<int size, bool big_endian>
+class Dyn_write
+{
+ public:
+  Dyn_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Dyn_data<size>*>(p))
+  { }
+
+  void
+  put_d_tag(typename Elf_types<size>::Elf_Swxword v)
+  { this->p_->d_tag = Convert<size, big_endian>::convert_host(v); }
+
+  void
+  put_d_val(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->d_val = Convert<size, big_endian>::convert_host(v); }
+
+  void
+  put_d_ptr(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->d_val = Convert<size, big_endian>::convert_host(v); }
+
+ private:
+  internal::Dyn_data<size>* p_;
+};
+
 // Accessor classes for entries in the ELF SHT_GNU_verdef section.
 
 template<int size, bool big_endian>
index 043c269..c9563ee 100644 (file)
@@ -102,6 +102,10 @@ class Elf_file
   typename File::Location
   section_contents(unsigned int shndx);
 
+  // Return the flags of section SHNDX.
+  typename Elf_types<size>::Elf_WXword
+  section_flags(unsigned int shndx);
+
  private:
   // Shared constructor code.
   void
@@ -250,6 +254,25 @@ Elf_file<size, big_endian, File>::section_contents(unsigned int shndx)
   return typename File::Location(shdr.get_sh_offset(), shdr.get_sh_size());
 }
 
+// Return the section flags of section SHNDX.
+
+template<int size, bool big_endian, typename File>
+typename Elf_types<size>::Elf_WXword
+Elf_file<size, big_endian, File>::section_flags(unsigned int shndx)
+{
+  File* const file = this->file_;
+
+  if (shndx >= this->shnum())
+    file->error(_("section_flags: bad shndx %u >= %u"),
+               shndx, this->shnum());
+
+  typename File::View v(file->view(this->section_header_offset(shndx),
+                                  This::shdr_size));
+
+  Ef_shdr shdr(v.data());
+  return shdr.get_sh_flags();
+}
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFCPP_FILE_H)
index 979108e..71b02eb 100644 (file)
@@ -180,9 +180,9 @@ struct Swap<8, big_endian>
 
 // Swap_unaligned is a template based on size and on whether the
 // target is big endian.  It defines the type Valtype and the
-// functions readval_unaligned and writeval_unaligned.  The functions
-// read and write values of the appropriate size out of buffers which
-// may be misaligned.
+// functions readval and writeval.  The functions read and write
+// values of the appropriate size out of buffers which may be
+// misaligned.
 
 template<int size, bool big_endian>
 struct Swap_unaligned;
@@ -193,11 +193,11 @@ struct Swap_unaligned<8, big_endian>
   typedef typename Valtype_base<8>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   { return *wv; }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   { *wv = v; }
 };
 
@@ -207,13 +207,13 @@ struct Swap_unaligned<16, false>
   typedef Valtype_base<16>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   {
     return (wv[1] << 8) | wv[0];
   }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   {
     wv[1] = v >> 8;
     wv[0] = v;
@@ -226,13 +226,13 @@ struct Swap_unaligned<16, true>
   typedef Valtype_base<16>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   {
     return (wv[0] << 8) | wv[1];
   }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   {
     wv[0] = v >> 8;
     wv[1] = v;
@@ -245,13 +245,13 @@ struct Swap_unaligned<32, false>
   typedef Valtype_base<32>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   {
     return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
   }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   {
     wv[3] = v >> 24;
     wv[2] = v >> 16;
@@ -266,13 +266,13 @@ struct Swap_unaligned<32, true>
   typedef Valtype_base<32>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   {
     return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
   }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   {
     wv[0] = v >> 24;
     wv[1] = v >> 16;
@@ -287,7 +287,7 @@ struct Swap_unaligned<64, false>
   typedef Valtype_base<64>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   {
     return ((static_cast<Valtype>(wv[7]) << 56)
            | (static_cast<Valtype>(wv[6]) << 48)
@@ -300,7 +300,7 @@ struct Swap_unaligned<64, false>
   }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   {
     wv[7] = v >> 56;
     wv[6] = v >> 48;
@@ -319,7 +319,7 @@ struct Swap_unaligned<64, true>
   typedef Valtype_base<64>::Valtype Valtype;
 
   static inline Valtype
-  readval_unaligned(const unsigned char* wv)
+  readval(const unsigned char* wv)
   {
     return ((static_cast<Valtype>(wv[0]) << 56)
            | (static_cast<Valtype>(wv[1]) << 48)
@@ -332,7 +332,7 @@ struct Swap_unaligned<64, true>
   }
 
   static inline void
-  writeval_unaligned(unsigned char* wv, Valtype v)
+  writeval(unsigned char* wv, Valtype v)
   {
     wv[7] = v >> 56;
     wv[6] = v >> 48;
index 7ba8adc..e83219c 100644 (file)
@@ -120,7 +120,7 @@ Symbol_table::allocate_commons(const General_options& options, Layout* layout)
   else if (this->get_size() == 64)
     this->do_allocate_commons<64>(options, layout);
   else
-    abort();
+    gold_unreachable();
 }
 
 // Allocated the common symbols, sized version.
@@ -171,7 +171,7 @@ Symbol_table::do_allocate_commons(const General_options&,
 
   // Place them in a newly allocated .bss section.
 
-  Output_data_common *poc = new Output_data_common(addralign);
+  Output_data_space *poc = new Output_data_space(addralign);
 
   layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS,
                                  elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC,
@@ -202,7 +202,7 @@ Symbol_table::do_allocate_commons(const General_options&,
       off += symsize;
     }
 
-  poc->set_common_size(off);
+  poc->set_space_size(off);
 
   this->commons_.clear();
 }
index 5dec3f6..d1298d8 100644 (file)
@@ -3,7 +3,6 @@
 #include "gold.h"
 
 #include <cerrno>
-#include <cassert>
 #include <sys/types.h>
 #include <dirent.h>
 
@@ -125,7 +124,7 @@ Dir_caches::add(const char* dirname)
 
     std::pair<const char*, Dir_cache*> v(dirname, cache);
     std::pair<Cache_hash::iterator, bool> p = this->caches_.insert(v);
-    assert(p.second);
+    gold_assert(p.second);
   }
 }
 
@@ -217,14 +216,14 @@ Dirsearch::add(Workqueue* workqueue, const General_options::Dir_list& list)
 std::string
 Dirsearch::find(const std::string& n1, const std::string& n2) const
 {
-  assert(!this->token_.is_blocked());
+  gold_assert(!this->token_.is_blocked());
 
   for (std::list<const char*>::const_iterator p = this->directories_.begin();
        p != this->directories_.end();
        ++p)
     {
       Dir_cache* pdc = caches.lookup(*p);
-      assert(pdc != NULL);
+      gold_assert(pdc != NULL);
       if (pdc->find(n1))
        return std::string(*p) + '/' + n1;
       if (!n2.empty() && pdc->find(n2))
index ba1fb15..ac5a74b 100644 (file)
@@ -5,12 +5,25 @@
 #include <vector>
 #include <cstring>
 
+#include "elfcpp.h"
 #include "symtab.h"
 #include "dynobj.h"
 
 namespace gold
 {
 
+// Class Dynobj.
+
+// Return the string to use in a DT_NEEDED entry.
+
+const char*
+Dynobj::soname() const
+{
+  if (!this->soname_.empty())
+    return this->soname_.c_str();
+  return this->name().c_str();
+}
+
 // Class Sized_dynobj.
 
 template<int size, bool big_endian>
@@ -20,8 +33,7 @@ Sized_dynobj<size, big_endian>::Sized_dynobj(
     off_t offset,
     const elfcpp::Ehdr<size, big_endian>& ehdr)
   : Dynobj(name, input_file, offset),
-    elf_file_(this, ehdr),
-    soname_()
+    elf_file_(this, ehdr)
 {
 }
 
@@ -130,7 +142,7 @@ Sized_dynobj<size, big_endian>::read_dynsym_section(
 
   typename This::Shdr shdr(pshdrs + shndx * This::shdr_size);
 
-  assert(shdr.get_sh_type() == type);
+  gold_assert(shdr.get_sh_type() == type);
 
   if (shdr.get_sh_link() != link)
     {
@@ -146,11 +158,11 @@ Sized_dynobj<size, big_endian>::read_dynsym_section(
   *view_info = shdr.get_sh_info();
 }
 
-// Set soname_ if this shared object has a DT_SONAME tag.  PSHDRS
-// points to the section headers.  DYNAMIC_SHNDX is the section index
-// of the SHT_DYNAMIC section.  STRTAB_SHNDX, STRTAB, and STRTAB_SIZE
-// are the section index and contents of a string table which may be
-// the one associated with the SHT_DYNAMIC section.
+// Set the soname field if this shared object has a DT_SONAME tag.
+// PSHDRS points to the section headers.  DYNAMIC_SHNDX is the section
+// index of the SHT_DYNAMIC section.  STRTAB_SHNDX, STRTAB, and
+// STRTAB_SIZE are the section index and contents of a string table
+// which may be the one associated with the SHT_DYNAMIC section.
 
 template<int size, bool big_endian>
 void
@@ -161,7 +173,7 @@ Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
                                           off_t strtab_size)
 {
   typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size);
-  assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC);
+  gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC);
 
   const off_t dynamic_size = dynamicshdr.get_sh_size();
   const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(),
@@ -214,7 +226,7 @@ Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
            }
 
          const char* strtab = reinterpret_cast<const char*>(strtabu);
-         this->soname_ = std::string(strtab + val);
+         this->set_soname_string(strtab + val);
          return;
        }
 
@@ -259,7 +271,7 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
     {
       // Get the dynamic symbols.
       typename This::Shdr dynsymshdr(pshdrs + dynsym_shndx * This::shdr_size);
-      assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
+      gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
 
       sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(),
                                           dynsymshdr.get_sh_size());
@@ -380,7 +392,7 @@ Sized_dynobj<size, big_endian>::set_version_map(
     unsigned int ndx,
     const char* name) const
 {
-  assert(ndx < version_map->size());
+  gold_assert(ndx < version_map->size());
   if ((*version_map)[ndx] != NULL)
     {
       fprintf(stderr, _("%s: %s: duplicate definition for version %u\n"),
@@ -602,8 +614,9 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
 {
   if (sd->symbols == NULL)
     {
-      assert(sd->symbol_names == NULL);
-      assert(sd->versym == NULL && sd->verdef == NULL && sd->verneed == NULL);
+      gold_assert(sd->symbol_names == NULL);
+      gold_assert(sd->versym == NULL && sd->verdef == NULL
+                 && sd->verneed == NULL);
       return;
     }
 
@@ -652,6 +665,400 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
     }
 }
 
+// Given a vector of hash codes, compute the number of hash buckets to
+// use.
+
+unsigned int
+Dynobj::compute_bucket_count(const std::vector<uint32_t>& hashcodes,
+                            bool for_gnu_hash_table)
+{
+  // FIXME: Implement optional hash table optimization.
+
+  // Array used to determine the number of hash table buckets to use
+  // based on the number of symbols there are.  If there are fewer
+  // than 3 symbols we use 1 bucket, fewer than 17 symbols we use 3
+  // buckets, fewer than 37 we use 17 buckets, and so forth.  We never
+  // use more than 32771 buckets.  This is straight from the old GNU
+  // linker.
+  static const unsigned int buckets[] =
+  {
+    1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
+    16411, 32771
+  };
+  const int buckets_count = sizeof buckets / sizeof buckets[0];
+
+  unsigned int symcount = hashcodes.size();
+  unsigned int ret = 1;
+  for (int i = 0; i < buckets_count; ++i)
+    {
+      if (symcount < buckets[i])
+       break;
+      ret = buckets[i];
+    }
+
+  if (for_gnu_hash_table && ret < 2)
+    ret = 2;
+
+  return ret;
+}
+
+// The standard ELF hash function.  This hash function must not
+// change, as the dynamic linker uses it also.
+
+uint32_t
+Dynobj::elf_hash(const char* name)
+{
+  const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
+  uint32_t h = 0;
+  unsigned char c;
+  while ((c = *nameu++) != '\0')
+    {
+      h = (h << 4) + c;
+      uint32_t g = h & 0xf0000000;
+      if (g != 0)
+       {
+         h ^= g >> 24;
+         // The ELF ABI says h &= ~g, but using xor is equivalent in
+         // this case (since g was set from h) and may save one
+         // instruction.
+         h ^= g;
+       }
+    }
+  return h;
+}
+
+// Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
+// DYNSYMS is a vector with all the global dynamic symbols.
+// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic
+// symbol table.
+
+void
+Dynobj::create_elf_hash_table(const Target* target,
+                             const std::vector<Symbol*>& dynsyms,
+                             unsigned int local_dynsym_count,
+                             unsigned char** pphash,
+                             unsigned int* phashlen)
+{
+  unsigned int dynsym_count = dynsyms.size();
+
+  // Get the hash values for all the symbols.
+  std::vector<uint32_t> dynsym_hashvals(dynsym_count);
+  for (unsigned int i = 0; i < dynsym_count; ++i)
+    dynsym_hashvals[i] = Dynobj::elf_hash(dynsyms[i]->name());
+
+  const unsigned int bucketcount =
+    Dynobj::compute_bucket_count(dynsym_hashvals, false);
+
+  std::vector<uint32_t> bucket(bucketcount);
+  std::vector<uint32_t> chain(local_dynsym_count + dynsym_count);
+
+  for (unsigned int i = 0; i < dynsym_count; ++i)
+    {
+      unsigned int dynsym_index = dynsyms[i]->dynsym_index();
+      unsigned int bucketpos = dynsym_hashvals[i] % bucketcount;
+      chain[dynsym_index] = bucket[bucketpos];
+      bucket[bucketpos] = dynsym_index;
+    }
+
+  unsigned int hashlen = ((2
+                          + bucketcount
+                          + local_dynsym_count
+                          + dynsym_count)
+                         * 4);
+  unsigned char* phash = new unsigned char[hashlen];
+
+  if (target->is_big_endian())
+    Dynobj::sized_create_elf_hash_table<true>(bucket, chain, phash, hashlen);
+  else
+    Dynobj::sized_create_elf_hash_table<false>(bucket, chain, phash, hashlen);
+
+  *pphash = phash;
+  *phashlen = hashlen;
+}
+
+// Fill in an ELF hash table.
+
+template<bool big_endian>
+void
+Dynobj::sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
+                                   const std::vector<uint32_t>& chain,
+                                   unsigned char* phash,
+                                   unsigned int hashlen)
+{
+  unsigned char* p = phash;
+
+  const unsigned int bucketcount = bucket.size();
+  const unsigned int chaincount = chain.size();
+
+  elfcpp::Swap<32, big_endian>::writeval(p, bucketcount);
+  p += 4;
+  elfcpp::Swap<32, big_endian>::writeval(p, chaincount);
+  p += 4;
+
+  for (unsigned int i = 0; i < bucketcount; ++i)
+    {
+      elfcpp::Swap<32, big_endian>::writeval(p, bucket[i]);
+      p += 4;
+    }
+
+  for (unsigned int i = 0; i < chaincount; ++i)
+    {
+      elfcpp::Swap<32, big_endian>::writeval(p, chain[i]);
+      p += 4;
+    }
+
+  gold_assert(static_cast<unsigned int>(p - phash) == hashlen);
+}
+
+// The hash function used for the GNU hash table.  This hash function
+// must not change, as the dynamic linker uses it also.
+
+uint32_t
+Dynobj::gnu_hash(const char* name)
+{
+  const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
+  uint32_t h = 5381;
+  unsigned char c;
+  while ((c = *nameu++) != '\0')
+    h = (h << 5) + h + c;
+  return h;
+}
+
+// Create a GNU hash table, setting *PPHASH and *PHASHLEN.  GNU hash
+// tables are an extension to ELF which are recognized by the GNU
+// dynamic linker.  They are referenced using dynamic tag DT_GNU_HASH.
+// TARGET is the target.  DYNSYMS is a vector with all the global
+// symbols which will be going into the dynamic symbol table.
+// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic
+// symbol table.
+
+void
+Dynobj::create_gnu_hash_table(const Target* target,
+                             const std::vector<Symbol*>& dynsyms,
+                             unsigned int local_dynsym_count,
+                             unsigned char** pphash,
+                             unsigned int* phashlen)
+{
+  const unsigned int count = dynsyms.size();
+
+  // Sort the dynamic symbols into two vectors.  Symbols which we do
+  // not want to put into the hash table we store into
+  // UNHASHED_DYNSYMS.  Symbols which we do want to store we put into
+  // HASHED_DYNSYMS.  DYNSYM_HASHVALS is parallel to HASHED_DYNSYMS,
+  // and records the hash codes.
+
+  std::vector<Symbol*> unhashed_dynsyms;
+  unhashed_dynsyms.reserve(count);
+
+  std::vector<Symbol*> hashed_dynsyms;
+  hashed_dynsyms.reserve(count);
+
+  std::vector<uint32_t> dynsym_hashvals;
+  dynsym_hashvals.reserve(count);
+  
+  for (unsigned int i = 0; i < count; ++i)
+    {
+      Symbol* sym = dynsyms[i];
+
+      // FIXME: Should put on unhashed_dynsyms if the symbol is
+      // hidden.
+      if (sym->is_undefined())
+       unhashed_dynsyms.push_back(sym);
+      else
+       {
+         hashed_dynsyms.push_back(sym);
+         dynsym_hashvals.push_back(Dynobj::gnu_hash(sym->name()));
+       }
+    }
+
+  // Put the unhashed symbols at the start of the global portion of
+  // the dynamic symbol table.
+  const unsigned int unhashed_count = unhashed_dynsyms.size();
+  unsigned int unhashed_dynsym_index = local_dynsym_count;
+  for (unsigned int i = 0; i < unhashed_count; ++i)
+    {
+      unhashed_dynsyms[i]->set_dynsym_index(unhashed_dynsym_index);
+      ++unhashed_dynsym_index;
+    }
+
+  // For the actual data generation we call out to a templatized
+  // function.
+  int size = target->get_size();
+  bool big_endian = target->is_big_endian();
+  if (size == 32)
+    {
+      if (big_endian)
+       Dynobj::sized_create_gnu_hash_table<32, true>(hashed_dynsyms,
+                                                     dynsym_hashvals,
+                                                     unhashed_dynsym_index,
+                                                     pphash,
+                                                     phashlen);
+      else
+       Dynobj::sized_create_gnu_hash_table<32, false>(hashed_dynsyms,
+                                                      dynsym_hashvals,
+                                                      unhashed_dynsym_index,
+                                                      pphash,
+                                                      phashlen);
+    }
+  else if (size == 64)
+    {
+      if (big_endian)
+       Dynobj::sized_create_gnu_hash_table<64, true>(hashed_dynsyms,
+                                                     dynsym_hashvals,
+                                                     unhashed_dynsym_index,
+                                                     pphash,
+                                                     phashlen);
+      else
+       Dynobj::sized_create_gnu_hash_table<64, false>(hashed_dynsyms,
+                                                      dynsym_hashvals,
+                                                      unhashed_dynsym_index,
+                                                      pphash,
+                                                      phashlen);
+    }
+  else
+    gold_unreachable();
+}
+
+// Create the actual data for a GNU hash table.  This is just a copy
+// of the code from the old GNU linker.
+
+template<int size, bool big_endian>
+void
+Dynobj::sized_create_gnu_hash_table(
+    const std::vector<Symbol*>& hashed_dynsyms,
+    const std::vector<uint32_t>& dynsym_hashvals,
+    unsigned int unhashed_dynsym_count,
+    unsigned char** pphash,
+    unsigned int* phashlen)
+{
+  if (hashed_dynsyms.empty())
+    {
+      // Special case for the empty hash table.
+      unsigned int hashlen = 5 * 4 + size / 8;
+      unsigned char* phash = new unsigned char[hashlen];
+      // One empty bucket.
+      elfcpp::Swap<32, big_endian>::writeval(phash, 1);
+      // Symbol index above unhashed symbols.
+      elfcpp::Swap<32, big_endian>::writeval(phash + 4, unhashed_dynsym_count);
+      // One word for bitmask.
+      elfcpp::Swap<32, big_endian>::writeval(phash + 8, 1);
+      // Only bloom filter.
+      elfcpp::Swap<32, big_endian>::writeval(phash + 12, 0);
+      // No valid hashes.
+      elfcpp::Swap<size, big_endian>::writeval(phash + 16, 0);
+      // No hashes in only bucket.
+      elfcpp::Swap<32, big_endian>::writeval(phash + 16 + size / 8, 0);
+
+      *phashlen = hashlen;
+      *pphash = phash;
+
+      return;
+    }
+
+  const unsigned int bucketcount =
+    Dynobj::compute_bucket_count(dynsym_hashvals, true);
+
+  const unsigned int nsyms = hashed_dynsyms.size();
+
+  uint32_t maskbitslog2 = 1;
+  uint32_t x = nsyms >> 1;
+  while (x != 0)
+    {
+      ++maskbitslog2;
+      x >>= 1;
+    }
+  if (maskbitslog2 < 3)
+    maskbitslog2 = 5;
+  else if (((1U << (maskbitslog2 - 2)) & nsyms) != 0)
+    maskbitslog2 += 3;
+  else
+    maskbitslog2 += 2;
+
+  uint32_t shift1;
+  if (size == 32)
+    shift1 = 5;
+  else
+    {
+      if (maskbitslog2 == 5)
+       maskbitslog2 = 6;
+      shift1 = 6;
+    }
+  uint32_t mask = (1U << shift1) - 1U;
+  uint32_t shift2 = maskbitslog2;
+  uint32_t maskbits = 1U << maskbitslog2;
+  uint32_t maskwords = 1U << (maskbitslog2 - shift1);
+
+  typedef typename elfcpp::Elf_types<size>::Elf_WXword Word;
+  std::vector<Word> bitmask(maskwords);
+  std::vector<uint32_t> counts(bucketcount);
+  std::vector<uint32_t> indx(bucketcount);
+  uint32_t symindx = unhashed_dynsym_count;
+
+  // Count the number of times each hash bucket is used.
+  for (unsigned int i = 0; i < nsyms; ++i)
+    ++counts[dynsym_hashvals[i] % bucketcount];
+
+  unsigned int cnt = symindx;
+  for (unsigned int i = 0; i < bucketcount; ++i)
+    {
+      indx[i] = cnt;
+      cnt += counts[i];
+    }
+
+  unsigned int hashlen = (4 + bucketcount + nsyms) * 4;
+  hashlen += maskbits / 8;
+  unsigned char* phash = new unsigned char[hashlen];
+
+  elfcpp::Swap<32, big_endian>::writeval(phash, bucketcount);
+  elfcpp::Swap<32, big_endian>::writeval(phash + 4, symindx);
+  elfcpp::Swap<32, big_endian>::writeval(phash + 8, maskwords);
+  elfcpp::Swap<32, big_endian>::writeval(phash + 12, shift2);
+
+  unsigned char* p = phash + 16 + maskbits / 8;
+  for (unsigned int i = 0; i < bucketcount; ++i)
+    {
+      if (counts[i] == 0)
+       elfcpp::Swap<32, big_endian>::writeval(p, 0);
+      else
+       elfcpp::Swap<32, big_endian>::writeval(p, indx[i]);
+      p += 4;
+    }
+
+  for (unsigned int i = 0; i < nsyms; ++i)
+    {
+      Symbol* sym = hashed_dynsyms[i];
+      uint32_t hashval = dynsym_hashvals[i];
+
+      unsigned int bucket = hashval % bucketcount;
+      unsigned int val = ((hashval >> shift1)
+                         & ((maskbits >> shift1) - 1));
+      bitmask[val] |= (static_cast<Word>(1U)) << (hashval & mask);
+      bitmask[val] |= (static_cast<Word>(1U)) << ((hashval >> shift2) & mask);
+      val = hashval & ~ 1U;
+      if (counts[bucket] == 1)
+       {
+         // Last element terminates the chain.
+         val |= 1;
+       }
+      elfcpp::Swap<32, big_endian>::writeval(p + (indx[bucket] - symindx) * 4,
+                                            val);
+      --counts[bucket];
+
+      sym->set_dynsym_index(indx[bucket]);
+      ++indx[bucket];
+    }
+
+  p = phash + 16;
+  for (unsigned int i = 0; i < maskwords; ++i)
+    {
+      elfcpp::Swap<size, big_endian>::writeval(p, bitmask[i]);
+      p += size / 8;
+    }
+
+  *phashlen = hashlen;
+  *pphash = phash;
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones for implemented targets.
 
index 04a2c63..bc877c4 100644 (file)
@@ -17,8 +17,71 @@ class Dynobj : public Object
 {
  public:
   Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0)
-    : Object(name, input_file, true, offset)
+    : Object(name, input_file, true, offset), soname_()
   { }
+
+  // Return the name to use in a DT_NEEDED entry for this object.
+  const char*
+  soname() const;
+
+  // Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
+  // DYNSYMS is the global dynamic symbols.  LOCAL_DYNSYM_COUNT is the
+  // number of local dynamic symbols, which is the index of the first
+  // dynamic gobal symbol.
+  static void
+  create_elf_hash_table(const Target*, const std::vector<Symbol*>& dynsyms,
+                       unsigned int local_dynsym_count,
+                       unsigned char** pphash,
+                       unsigned int* phashlen);
+
+  // Create a GNU hash table, setting *PPHASH and *PHASHLEN.  DYNSYMS
+  // is the global dynamic symbols.  LOCAL_DYNSYM_COUNT is the number
+  // of local dynamic symbols, which is the index of the first dynamic
+  // gobal symbol.
+  static void
+  create_gnu_hash_table(const Target*, const std::vector<Symbol*>& dynsyms,
+                       unsigned int local_dynsym_count,
+                       unsigned char** pphash, unsigned int* phashlen);
+
+ protected:
+  // Set the DT_SONAME string.
+  void
+  set_soname_string(const char* s)
+  { this->soname_.assign(s); }
+
+ private:
+  // Compute the ELF hash code for a string.
+  static uint32_t
+  elf_hash(const char*);
+
+  // Compute the GNU hash code for a string.
+  static uint32_t
+  gnu_hash(const char*);
+
+  // Compute the number of hash buckets to use.
+  static unsigned int
+  compute_bucket_count(const std::vector<uint32_t>& hashcodes,
+                      bool for_gnu_hash_table);
+
+  // Sized version of create_elf_hash_table.
+  template<bool big_endian>
+  static void
+  sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
+                             const std::vector<uint32_t>& chain,
+                             unsigned char* phash,
+                             unsigned int hashlen);
+
+  // Sized version of create_gnu_hash_table.
+  template<int size, bool big_endian>
+  static void
+  sized_create_gnu_hash_table(const std::vector<Symbol*>& hashed_dynsyms,
+                             const std::vector<uint32_t>& dynsym_hashvals,
+                             unsigned int unhashed_dynsym_count,
+                             unsigned char** pphash,
+                             unsigned int* phashlen);
+
+  // The DT_SONAME name, if any.
+  std::string soname_;
 };
 
 // A dynamic object, size and endian specific version.
@@ -58,6 +121,11 @@ class Sized_dynobj : public Dynobj
   do_section_contents(unsigned int shndx)
   { return this->elf_file_.section_contents(shndx); }
 
+  // Return section flags.
+  uint64_t
+  do_section_flags(unsigned int shndx)
+  { return this->elf_file_.section_flags(shndx); }
+
  private:
   // For convenience.
   typedef Sized_dynobj<size, big_endian> This;
@@ -104,8 +172,6 @@ class Sized_dynobj : public Dynobj
 
   // General access to the ELF file.
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
-  // The DT_SONAME name, if any.
-  std::string soname_;
 };
 
 } // End namespace gold.
index 43c69b3..e96476c 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "gold.h"
 
-#include <cassert>
 #include <cstring>
 #include <cerrno>
 #include <fcntl.h>
@@ -19,7 +18,7 @@ namespace gold
 
 File_read::View::~View()
 {
-  assert(!this->is_locked());
+  gold_assert(!this->is_locked());
   delete[] this->data_;
 }
 
@@ -32,7 +31,7 @@ File_read::View::lock()
 void
 File_read::View::unlock()
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
   --this->lock_count_;
 }
 
@@ -49,7 +48,7 @@ File_read::View::is_locked()
 
 File_read::~File_read()
 {
-  assert(this->lock_count_ == 0);
+  gold_assert(this->lock_count_ == 0);
   if (this->descriptor_ >= 0)
     {
       if (close(this->descriptor_) < 0)
@@ -64,9 +63,9 @@ File_read::~File_read()
 bool
 File_read::open(const std::string& name)
 {
-  assert(this->lock_count_ == 0
-        && this->descriptor_ < 0
-        && this->name_.empty());
+  gold_assert(this->lock_count_ == 0
+             && this->descriptor_ < 0
+             && this->name_.empty());
   this->name_ = name;
   this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
   ++this->lock_count_;
@@ -76,7 +75,7 @@ File_read::open(const std::string& name)
 int
 File_read::get_descriptor()
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
   return this->descriptor_;
 }
 
@@ -89,7 +88,7 @@ File_read::lock()
 void
 File_read::unlock()
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
   --this->lock_count_;
 }
 
@@ -121,7 +120,7 @@ File_read::find_view(off_t start, off_t size)
 off_t
 File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
   int o = this->descriptor_;
 
   if (lseek(o, start, SEEK_SET) < 0)
@@ -161,7 +160,7 @@ File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
 void
 File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
 
   File_read::View* pv = this->find_view(start, size);
   if (pv != NULL)
@@ -180,7 +179,7 @@ File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
 File_read::View*
 File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
 
   off_t poff = File_read::page_offset(start);
 
@@ -244,7 +243,7 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
 const unsigned char*
 File_read::get_view(off_t start, off_t size, off_t* pbytes)
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
   File_read::View* pv = this->find_or_make_view(start, size, pbytes);
   return pv->data() + (start - pv->start());
 }
@@ -252,7 +251,7 @@ File_read::get_view(off_t start, off_t size, off_t* pbytes)
 File_view*
 File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
 {
-  assert(this->lock_count_ > 0);
+  gold_assert(this->lock_count_ > 0);
   File_read::View* pv = this->find_or_make_view(start, size, pbytes);
   pv->lock();
   return new File_view(*this, pv, pv->data() + (start - pv->start()));
@@ -271,7 +270,7 @@ File_read::clear_views(bool destroying)
        delete p->second;
       else
        {
-         assert(!destroying);
+         gold_assert(!destroying);
          this->saved_views_.push_back(p->second);
        }
     }
@@ -287,7 +286,7 @@ File_read::clear_views(bool destroying)
        }
       else
        {
-         assert(!destroying);
+         gold_assert(!destroying);
          ++p;
        }
     }
@@ -297,7 +296,7 @@ File_read::clear_views(bool destroying)
 
 File_view::~File_view()
 {
-  assert(this->file_.is_locked());
+  gold_assert(this->file_.is_locked());
   this->view_->unlock();
 }
 
index c6e1170..5373739 100644 (file)
@@ -1,7 +1,5 @@
 // gold-threads.cc -- thread support for gold
 
-#include <cassert>
-
 #include "gold.h"
 
 #ifdef ENABLE_THREADS
@@ -87,20 +85,20 @@ Lock_impl::Lock_impl()
 
 Lock_impl::~Lock_impl()
 {
-  assert(!this->acquired_);
+  gold_assert(!this->acquired_);
 }
 
 void
 Lock_impl::acquire()
 {
-  assert(!this->acquired_);
+  gold_assert(!this->acquired_);
   this->acquired_ = true;
 }
 
 void
 Lock_impl::release()
 {
-  assert(this->acquired_);
+  gold_assert(this->acquired_);
   this->acquired_ = false;
 }
 
@@ -192,7 +190,7 @@ Condvar_impl::~Condvar_impl()
 void
 Condvar_impl::wait(Lock_impl* li)
 {
-  assert(li->acquired_);
+  gold_assert(li->acquired_);
 }
 
 void
index 3073b18..7c8ed8f 100644 (file)
@@ -52,10 +52,14 @@ gold_nomem()
   gold_exit(false);
 }
 
+// Handle an unreachable case.
+
 void
-gold_unreachable()
+do_gold_unreachable(const char* filename, int lineno, const char* function)
 {
-  abort();
+  fprintf(stderr, "%s: internal error in %s, at %s:%d\n",
+         program_name, function, filename, lineno);
+  gold_exit(false);
 }
 
 // This class arranges to run the functions done in the middle of the
@@ -136,6 +140,10 @@ queue_middle_tasks(const General_options& options,
                   Layout* layout,
                   Workqueue* workqueue)
 {
+  // Define some sections and symbols needed for a dynamic link.  This
+  // handles some cases we want to see before we read the relocs.
+  layout->create_initial_dynamic_sections(input_objects, symtab);
+
   // Predefine standard symbols.  This should be fast, so we don't
   // bother to create a task for it.
   define_standard_symbols(symtab, layout, input_objects->target());
@@ -215,7 +223,9 @@ queue_final_tasks(const General_options& options,
 
   // Queue a task to write out everything else.
   final_blocker->add_blocker();
-  workqueue->queue(new Write_data_task(layout, of, final_blocker));
+  workqueue->queue(new Write_data_task(layout, symtab,
+                                      input_objects->target(),
+                                      of, final_blocker));
 
   // Queue a task to close the output file.  This will be blocked by
   // FINAL_BLOCKER.
index d55d1f6..78c106f 100644 (file)
@@ -163,10 +163,18 @@ gold_fatal(const char* msg, bool perrno) ATTRIBUTE_NORETURN;
 extern void
 gold_nomem() ATTRIBUTE_NORETURN;
 
-// This function is called in cases which can not arise if the code is
-// written correctly.
-extern void
-gold_unreachable() ATTRIBUTE_NORETURN;
+// This macro and function are used in cases which can not arise if
+// the code is written correctly.
+
+#define gold_unreachable() \
+  (gold::do_gold_unreachable(__FILE__, __LINE__, __FUNCTION__))
+
+extern void do_gold_unreachable(const char*, int, const char*)
+  ATTRIBUTE_NORETURN;
+
+// Assertion check.
+
+#define gold_assert(expr) ((void)(!(expr) ? gold_unreachable(), 0 : 0))
 
 // Queue up the first set of tasks.
 extern void
index e6522e3..488da79 100644 (file)
@@ -20,6 +20,8 @@ namespace
 
 using namespace gold;
 
+class Output_data_plt_i386;
+
 // The i386 target class.
 
 class Target_i386 : public Sized_target<32, false>
@@ -27,7 +29,7 @@ class Target_i386 : public Sized_target<32, false>
  public:
   Target_i386()
     : Sized_target<32, false>(&i386_info),
-      got_(NULL)
+      got_(NULL), plt_(NULL), got_plt_(NULL)
   { }
 
   // Scan the relocations to look for symbol adjustments.
@@ -36,6 +38,7 @@ class Target_i386 : public Sized_target<32, false>
              Symbol_table* symtab,
              Layout* layout,
              Sized_relobj<32, false>* object,
+             unsigned int data_shndx,
              unsigned int sh_type,
              const unsigned char* prelocs,
              size_t reloc_count,
@@ -61,6 +64,7 @@ class Target_i386 : public Sized_target<32, false>
     local(const General_options& options, Symbol_table* symtab,
          Layout* layout, Target_i386* target,
          Sized_relobj<32, false>* object,
+         unsigned int data_shndx,
          const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
          const elfcpp::Sym<32, false>& lsym);
 
@@ -68,6 +72,7 @@ class Target_i386 : public Sized_target<32, false>
     global(const General_options& options, Symbol_table* symtab,
           Layout* layout, Target_i386* target,
           Sized_relobj<32, false>* object,
+          unsigned int data_shndx,
           const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
           Symbol* gsym);
   };
@@ -146,11 +151,29 @@ class Target_i386 : public Sized_target<32, false>
   // Adjust TLS relocation type based on the options and whether this
   // is a local symbol.
   static unsigned int
-  optimize_tls_reloc(const General_options*, bool is_local, int r_type);
+  optimize_tls_reloc(const General_options*, bool is_final, int r_type);
 
   // Get the GOT section, creating it if necessary.
   Output_data_got<32, false>*
-  got_section(Symbol_table*, Layout*);
+  got_section(const General_options*, Symbol_table*, Layout*);
+
+  // Create a PLT entry for a global symbol.
+  void
+  make_plt_entry(const General_options* options, Symbol_table*,
+                Layout*, Symbol*);
+
+  // Get the PLT section.
+  Output_data_plt_i386*
+  plt_section() const
+  {
+    gold_assert(this->plt_ != NULL);
+    return this->plt_;
+  }
+
+  // Copy a relocation against a global symbol.
+  void
+  copy_reloc(const General_options*, Sized_relobj<32, false>*, unsigned int,
+            Symbol*, const elfcpp::Rel<32, false>&);
 
   // Information about this specific target which we pass to the
   // general Target structure.
@@ -158,6 +181,10 @@ class Target_i386 : public Sized_target<32, false>
 
   // The GOT section.
   Output_data_got<32, false>* got_;
+  // The PLT section.
+  Output_data_plt_i386* plt_;
+  // The GOT PLT section.
+  Output_data_space* got_plt_;
 };
 
 const Target::Target_info Target_i386::i386_info =
@@ -176,37 +203,317 @@ const Target::Target_info Target_i386::i386_info =
 // Get the GOT section, creating it if necessary.
 
 Output_data_got<32, false>*
-Target_i386::got_section(Symbol_table* symtab, Layout* layout)
+Target_i386::got_section(const General_options* options, Symbol_table* symtab,
+                        Layout* layout)
 {
   if (this->got_ == NULL)
     {
-      this->got_ = new Output_data_got<32, false>();
+      gold_assert(options != NULL && symtab != NULL && layout != NULL);
+
+      this->got_ = new Output_data_got<32, false>(options);
 
-      assert(symtab != NULL && layout != NULL);
       layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                      elfcpp::SHF_ALLOC, this->got_);
 
+      // The old GNU linker creates a .got.plt section.  We just
+      // create another set of data in the .got section.  Note that we
+      // always create a PLT if we create a GOT, although the PLT
+      // might be empty.
+      this->got_plt_ = new Output_data_space(4);
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     elfcpp::SHF_ALLOC, this->got_plt_);
+
       // The first three entries are reserved.
-      this->got_->add_constant(0);
-      this->got_->add_constant(0);
-      this->got_->add_constant(0);
+      this->got_plt_->set_space_size(3 * 4);
 
-      // Define _GLOBAL_OFFSET_TABLE_ at the start of the section.
-      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", this->got_,
+      // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
+      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_",
+                                   this->got_plt_,
                                    0, 0, elfcpp::STT_OBJECT,
                                    elfcpp::STB_GLOBAL,
                                    elfcpp::STV_HIDDEN, 0,
                                    false, false);
     }
+
   return this->got_;
 }
 
+// A class to handle the PLT data.
+
+class Output_data_plt_i386 : public Output_section_data
+{
+ public:
+  typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
+
+  Output_data_plt_i386(Layout*, Output_data_space*, bool is_shared);
+
+  // Add an entry to the PLT.
+  void
+  add_entry(Symbol* gsym);
+
+ private:
+  // The size of an entry in the PLT.
+  static const int plt_entry_size = 16;
+
+  // The first entry in the PLT for an executable.
+  static unsigned char exec_first_plt_entry[plt_entry_size];
+
+  // The first entry in the PLT for a shared object.
+  static unsigned char dyn_first_plt_entry[plt_entry_size];
+
+  // Other entries in the PLT for an executable.
+  static unsigned char exec_plt_entry[plt_entry_size];
+
+  // Other entries in the PLT for a shared object.
+  static unsigned char dyn_plt_entry[plt_entry_size];
+
+  // Set the final size.
+  void
+  do_set_address(uint64_t, off_t)
+  { this->set_data_size((this->count_ + 1) * plt_entry_size); }
+
+  // Write out the PLT data.
+  void
+  do_write(Output_file*);
+
+  // The reloc section.
+  Reloc_section* rel_;
+  // The .got.plt section.
+  Output_data_space* got_plt_;
+  // The number of PLT entries.
+  unsigned int count_;
+  // Whether we are generated a shared object.
+  bool is_shared_;
+};
+
+// Create the PLT section.  The ordinary .got section is an argument,
+// since we need to refer to the start.  We also create our own .got
+// section just for PLT entries.
+
+Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
+                                          Output_data_space* got_plt,
+                                          bool is_shared)
+  : Output_section_data(4), got_plt_(got_plt), is_shared_(is_shared)
+{
+  this->rel_ = new Reloc_section();
+  layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
+                                 elfcpp::SHF_ALLOC, this->rel_);
+}
+
+// Add an entry to the PLT.
+
+void
+Output_data_plt_i386::add_entry(Symbol* gsym)
+{
+  gold_assert(!gsym->has_plt_offset());
+
+  // Note that when setting the PLT offset we skip the initial
+  // reserved PLT entry.
+  gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
+
+  ++this->count_;
+
+  off_t got_offset = this->got_plt_->data_size();
+
+  // Every PLT entry needs a GOT entry which points back to the PLT
+  // entry (this will be changed by the dynamic linker, normally
+  // lazily when the function is called).
+  this->got_plt_->set_space_size(got_offset + 4);
+
+  // Every PLT entry needs a reloc.
+  this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_,
+                        got_offset);
+
+  // Note that we don't need to save the symbol.  The contents of the
+  // PLT are independent of which symbols are used.  The symbols only
+  // appear in the relocations.
+}
+
+// The first entry in the PLT for an executable.
+
+unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
+{
+  0xff, 0x35,  // pushl contents of memory address
+  0, 0, 0, 0,  // replaced with address of .got + 4
+  0xff, 0x25,  // jmp indirect
+  0, 0, 0, 0,  // replaced with address of .got + 8
+  0, 0, 0, 0   // unused
+};
+
+// The first entry in the PLT for a shared object.
+
+unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
+{
+  0xff, 0xb3, 4, 0, 0, 0,      // pushl 4(%ebx)
+  0xff, 0xa3, 8, 0, 0, 0,      // jmp *8(%ebx)
+  0, 0, 0, 0                   // unused
+};
+
+// Subsequent entries in the PLT for an executable.
+
+unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
+{
+  0xff, 0x25,  // jmp indirect
+  0, 0, 0, 0,  // replaced with address of symbol in .got
+  0x68,                // pushl immediate
+  0, 0, 0, 0,  // replaced with offset into relocation table
+  0xe9,                // jmp relative
+  0, 0, 0, 0   // replaced with offset to start of .plt
+};
+
+// Subsequent entries in the PLT for a shared object.
+
+unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
+{
+  0xff, 0xa3,  // jmp *offset(%ebx)
+  0, 0, 0, 0,  // replaced with offset of symbol in .got
+  0x68,                // pushl immediate
+  0, 0, 0, 0,  // replaced with offset into relocation table
+  0xe9,                // jmp relative
+  0, 0, 0, 0   // replaced with offset to start of .plt
+};
+
+// Write out the PLT.  This uses the hand-coded instructions above,
+// and adjusts them as needed.  This is all specified by the i386 ELF
+// Processor Supplement.
+
+void
+Output_data_plt_i386::do_write(Output_file* of)
+{
+  const off_t offset = this->offset();
+  const off_t oview_size = this->data_size();
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+  const off_t got_file_offset = this->got_plt_->offset();
+  const off_t got_size = this->got_plt_->data_size();
+  unsigned char* const got_view = of->get_output_view(got_file_offset,
+                                                     got_size);
+
+  unsigned char* pov = oview;
+
+  elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
+  elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
+
+  if (this->is_shared_)
+    memcpy(pov, dyn_first_plt_entry, plt_entry_size);
+  else
+    {
+      memcpy(pov, exec_first_plt_entry, plt_entry_size);
+      elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
+      elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
+    }
+  pov += plt_entry_size;
+
+  unsigned char* got_pov = got_view;
+
+  memset(got_pov, 0, 12);
+  got_pov += 12;
+
+  const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
+
+  unsigned int plt_offset = plt_entry_size;
+  unsigned int plt_rel_offset = 0;
+  unsigned int got_offset = 12;
+  const unsigned int count = this->count_;
+  for (unsigned int i = 0;
+       i < count;
+       ++i,
+        pov += plt_entry_size,
+        got_pov += 4,
+        plt_offset += plt_entry_size,
+        plt_rel_offset += rel_size,
+        got_offset += 4)
+    {
+      // Set and adjust the PLT entry itself.
+
+      if (this->is_shared_)
+       {
+         memcpy(pov, dyn_plt_entry, plt_entry_size);
+         elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
+       }
+      else
+       {
+         memcpy(pov, exec_plt_entry, plt_entry_size);
+         elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+                                                     (got_address
+                                                      + got_offset));
+       }
+
+      elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
+      elfcpp::Swap<32, false>::writeval(pov + 12,
+                                       - (plt_offset + plt_entry_size));
+
+      // Set the entry in the GOT.
+      elfcpp::Swap<32, false>::writeval(got_pov, plt_address + plt_offset + 6);
+    }
+
+  gold_assert(pov - oview == oview_size);
+  gold_assert(got_pov - got_view == got_size);
+
+  of->write_output_view(offset, oview_size, oview);
+  of->write_output_view(got_file_offset, got_size, got_view);
+}
+
+// Create a PLT entry for a global symbol.
+
+void
+Target_i386::make_plt_entry(const General_options* options,
+                           Symbol_table* symtab, Layout* layout, Symbol* gsym)
+{
+  if (gsym->has_plt_offset())
+    return;
+
+  if (this->plt_ == NULL)
+    {
+      // Create the GOT sections first.
+      this->got_section(options, symtab, layout);
+
+      this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
+                                           options->is_shared());
+    }
+
+  this->plt_->add_entry(gsym);
+}
+
+// Handle a relocation against a non-function symbol defined in a
+// dynamic object.  The traditional way to handle this is to generate
+// a COPY relocation to copy the variable at runtime from the shared
+// object into the executable's data segment.  However, this is
+// undesirable in general, as if the size of the object changes in the
+// dynamic object, the executable will no longer work correctly.  If
+// this relocation is in a writable section, then we can create a
+// dynamic reloc and the dynamic linker will resolve it to the correct
+// address at runtime.  However, we do not want do that if the
+// relocation is in a read-only section, as it would prevent the
+// readonly segment from being shared.  And if we have to eventually
+// generate a COPY reloc, then any dynamic relocations will be
+// useless.  So this means that if this is a writable section, we need
+// to save the relocation until we see whether we have to create a
+// COPY relocation for this symbol for any other relocation.
+
+void
+Target_i386::copy_reloc(const General_options* options,
+                       Sized_relobj<32, false>* object,
+                       unsigned int data_shndx, Symbol* gsym,
+                       const elfcpp::Rel<32, false>&)
+{
+  if (!Relocate_functions<32, false>::need_copy_reloc(options, object,
+                                                     data_shndx, gsym))
+    {
+      // So far we do not need a COPY reloc.  Save this relocation.
+      // If it turns out that we never a COPY reloc for this symbol,
+      // then we emit the relocation.
+    }
+
+}
+
 // Optimize the TLS relocation type based on what we know about the
-// symbol.  IS_LOCAL is true if this symbol can be resolved entirely
-// locally--i.e., does not have to be in the dynamic symbol table.
+// symbol.  IS_FINAL is true if the final address of this symbol is
+// known at link time.
 
 unsigned int
-Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
+Target_i386::optimize_tls_reloc(const General_options* options,
+                               bool is_final,
                                int r_type)
 {
   // If we are generating a shared library, then we can't do anything
@@ -223,7 +530,7 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
       // access.  Since we know that we are generating an executable,
       // we can convert this to Initial-Exec.  If we also know that
       // this is a local symbol, we can further switch to Local-Exec.
-      if (is_local)
+      if (is_final)
        return elfcpp::R_386_TLS_LE_32;
       return elfcpp::R_386_TLS_IE_32;
 
@@ -244,7 +551,7 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
       // from the GOT.  If we know that we are linking against the
       // local symbol, we can switch to Local-Exec, which links the
       // thread offset into the instruction.
-      if (is_local)
+      if (is_final)
        return elfcpp::R_386_TLS_LE_32;
       return r_type;
        
@@ -255,7 +562,7 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
       return r_type;
 
     default:
-      abort();
+      gold_unreachable();
     }
 }
 
@@ -267,7 +574,9 @@ Target_i386::Scan::local(const General_options& options,
                         Layout* layout,
                         Target_i386* target,
                         Sized_relobj<32, false>* object,
-                        const elfcpp::Rel<32, false>&, unsigned int r_type,
+                        unsigned int,
+                        const elfcpp::Rel<32, false>&,
+                        unsigned int r_type,
                         const elfcpp::Sym<32, false>&)
 {
   switch (r_type)
@@ -282,6 +591,7 @@ Target_i386::Scan::local(const General_options& options,
     case elfcpp::R_386_8:
       // FIXME: If we are generating a shared object we need to copy
       // this relocation into the object.
+      gold_assert(!options.is_shared());
       break;
 
     case elfcpp::R_386_PC32:
@@ -292,7 +602,7 @@ Target_i386::Scan::local(const General_options& options,
     case elfcpp::R_386_GOTOFF:
     case elfcpp::R_386_GOTPC:
       // We need a GOT section.
-      target->got_section(symtab, layout);
+      target->got_section(&options, symtab, layout);
       break;
 
     case elfcpp::R_386_COPY:
@@ -319,13 +629,16 @@ Target_i386::Scan::local(const General_options& options,
     case elfcpp::R_386_TLS_LE_32:
     case elfcpp::R_386_TLS_GOTDESC:
     case elfcpp::R_386_TLS_DESC_CALL:
-      r_type = Target_i386::optimize_tls_reloc(&options, true, r_type);
+      r_type = Target_i386::optimize_tls_reloc(&options,
+                                              !options.is_shared(),
+                                              r_type);
       switch (r_type)
        {
        case elfcpp::R_386_TLS_LE:
        case elfcpp::R_386_TLS_LE_32:
          // FIXME: If generating a shared object, we need to copy
          // this relocation into the object.
+         gold_assert(!options.is_shared());
          break;
 
        case elfcpp::R_386_TLS_IE:
@@ -370,7 +683,9 @@ Target_i386::Scan::global(const General_options& options,
                          Layout* layout,
                          Target_i386* target,
                          Sized_relobj<32, false>* object,
-                         const elfcpp::Rel<32, false>&, unsigned int r_type,
+                         unsigned int data_shndx,
+                         const elfcpp::Rel<32, false>& reloc,
+                         unsigned int r_type,
                          Symbol* gsym)
 {
   switch (r_type)
@@ -390,32 +705,44 @@ Target_i386::Scan::global(const General_options& options,
       // copy this relocation into the object.  If this symbol is
       // defined in a shared object, we may need to copy this
       // relocation in order to avoid a COPY relocation.
+      gold_assert(!options.is_shared());
+
+      if (gsym->is_defined_in_dynobj())
+       {
+         // This symbol is defined in a dynamic object.  If it is a
+         // function, we make a PLT entry.  Otherwise we need to
+         // either generate a COPY reloc or copy this reloc.
+         if (gsym->type() == elfcpp::STT_FUNC)
+           target->make_plt_entry(&options, symtab, layout, gsym);
+         else
+           target->copy_reloc(&options, object, data_shndx, gsym, reloc);
+       }
+
       break;
 
     case elfcpp::R_386_GOT32:
       // The symbol requires a GOT entry.
-      if (target->got_section(symtab, layout)->add_global(gsym))
+      if (target->got_section(&options, symtab, layout)->add_global(gsym))
        {
-         // If this symbol is not resolved locally, we need to add a
+         // If this symbol is not fully resolved, we need to add a
          // dynamic relocation for it.
-         if (!gsym->is_resolved_locally())
-           abort();
+         if (!gsym->final_value_is_known(&options))
+           gold_unreachable();
        }
       break;
 
     case elfcpp::R_386_PLT32:
-      // If the symbol is resolved locally, this is just a PC32 reloc.
-      if (gsym->is_resolved_locally())
+      // If the symbol is fully resolved, this is just a PC32 reloc.
+      // Otherwise we need a PLT entry.
+      if (gsym->final_value_is_known(&options))
        break;
-      fprintf(stderr,
-             _("%s: %s: unsupported reloc %u against global symbol %s\n"),
-             program_name, object->name().c_str(), r_type, gsym->name());
+      target->make_plt_entry(&options, symtab, layout, gsym);
       break;
 
     case elfcpp::R_386_GOTOFF:
     case elfcpp::R_386_GOTPC:
       // We need a GOT section.
-      target->got_section(symtab, layout);
+      target->got_section(&options, symtab, layout);
       break;
 
     case elfcpp::R_386_COPY:
@@ -442,30 +769,34 @@ Target_i386::Scan::global(const General_options& options,
     case elfcpp::R_386_TLS_LE_32:
     case elfcpp::R_386_TLS_GOTDESC:
     case elfcpp::R_386_TLS_DESC_CALL:
-      r_type = Target_i386::optimize_tls_reloc(&options,
-                                              gsym->is_resolved_locally(),
-                                              r_type);
-      switch (r_type)
-       {
-       case elfcpp::R_386_TLS_LE:
-       case elfcpp::R_386_TLS_LE_32:
-         // FIXME: If generating a shared object, we need to copy
-         // this relocation into the object.
-         break;
-
-       case elfcpp::R_386_TLS_IE:
-       case elfcpp::R_386_TLS_GOTIE:
-       case elfcpp::R_386_TLS_GD:
-       case elfcpp::R_386_TLS_LDM:
-       case elfcpp::R_386_TLS_LDO_32:
-       case elfcpp::R_386_TLS_IE_32:
-       case elfcpp::R_386_TLS_GOTDESC:
-       case elfcpp::R_386_TLS_DESC_CALL:
-         fprintf(stderr,
-                 _("%s: %s: unsupported reloc %u against global symbol %s\n"),
-                 program_name, object->name().c_str(), r_type, gsym->name());
-         break;
-       }
+      {
+       const bool is_final = gsym->final_value_is_known(&options);
+       r_type = Target_i386::optimize_tls_reloc(&options, is_final, r_type);
+       switch (r_type)
+         {
+         case elfcpp::R_386_TLS_LE:
+         case elfcpp::R_386_TLS_LE_32:
+           // FIXME: If generating a shared object, we need to copy
+           // this relocation into the object.
+           gold_assert(!options.is_shared());
+           break;
+
+         case elfcpp::R_386_TLS_IE:
+         case elfcpp::R_386_TLS_GOTIE:
+         case elfcpp::R_386_TLS_GD:
+         case elfcpp::R_386_TLS_LDM:
+         case elfcpp::R_386_TLS_LDO_32:
+         case elfcpp::R_386_TLS_IE_32:
+         case elfcpp::R_386_TLS_GOTDESC:
+         case elfcpp::R_386_TLS_DESC_CALL:
+           fprintf(stderr,
+                   _("%s: %s: unsupported reloc %u "
+                     "against global symbol %s\n"),
+                   program_name, object->name().c_str(), r_type,
+                   gsym->name());
+           break;
+         }
+      }
       break;
 
     case elfcpp::R_386_32PLT:
@@ -493,6 +824,7 @@ Target_i386::scan_relocs(const General_options& options,
                         Symbol_table* symtab,
                         Layout* layout,
                         Sized_relobj<32, false>* object,
+                        unsigned int data_shndx,
                         unsigned int sh_type,
                         const unsigned char* prelocs,
                         size_t reloc_count,
@@ -514,6 +846,7 @@ Target_i386::scan_relocs(const General_options& options,
     layout,
     this,
     object,
+    data_shndx,
     prelocs,
     reloc_count,
     local_symbol_count,
@@ -552,6 +885,15 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
       return false;
     }
 
+  // Pick the value to use for symbols defined in shared objects.
+  if (gsym != NULL && gsym->is_defined_in_dynobj())
+    {
+      if (gsym->has_plt_offset())
+       address = target->plt_section()->address() + gsym->plt_offset();
+      else
+       gold_unreachable();
+    }
+
   switch (r_type)
     {
     case elfcpp::R_386_NONE:
@@ -584,30 +926,26 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
       break;
 
     case elfcpp::R_386_PLT32:
-      if (gsym->is_resolved_locally())
-       Relocate_functions<32, false>::pcrel32(view, value, address);
-      else
-       fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
-               program_name,
-               relinfo->location(relnum, rel.get_r_offset()).c_str(),
-               r_type);
+      gold_assert(gsym->has_plt_offset()
+                 || gsym->final_value_is_known(relinfo->options));
+      Relocate_functions<32, false>::pcrel32(view, value, address);
       break;
 
     case elfcpp::R_386_GOT32:
       // Local GOT offsets not yet supported.
-      assert(gsym);
-      assert(gsym->has_got_offset());
+      gold_assert(gsym);
+      gold_assert(gsym->has_got_offset());
       value = gsym->got_offset();
       Relocate_functions<32, false>::rel32(view, value);
       break;
 
     case elfcpp::R_386_GOTOFF:
-      value -= target->got_section(NULL, NULL)->address();
+      value -= target->got_section(NULL, NULL, NULL)->address();
       Relocate_functions<32, false>::rel32(view, value);
       break;
 
     case elfcpp::R_386_GOTPC:
-      value = target->got_section(NULL, NULL)->address();
+      value = target->got_section(NULL, NULL, NULL)->address();
       Relocate_functions<32, false>::pcrel32(view, value, address);
       break;
 
@@ -685,9 +1023,11 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       gold_exit(false);
     }
 
-  const bool is_local = gsym == NULL || gsym->is_resolved_locally();
+  const bool is_final = (gsym == NULL
+                        ? !relinfo->options->is_shared()
+                        : gsym->final_value_is_known(relinfo->options));
   const unsigned int opt_r_type =
-    Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type);
+    Target_i386::optimize_tls_reloc(relinfo->options, is_final, r_type);
   switch (r_type)
     {
     case elfcpp::R_386_TLS_LE_32:
@@ -955,7 +1295,7 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
                              elfcpp::Elf_types<32>::Elf_Addr address,
                              off_t view_size)
 {
-  assert(sh_type == elfcpp::SHT_REL);
+  gold_assert(sh_type == elfcpp::SHT_REL);
 
   gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
                         Target_i386::Relocate>(
index f9f5548..97917b0 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "gold.h"
 
-#include <cassert>
 #include <cstring>
 #include <algorithm>
 #include <iostream>
@@ -10,6 +9,7 @@
 
 #include "output.h"
 #include "symtab.h"
+#include "dynobj.h"
 #include "layout.h"
 
 namespace gold
@@ -39,13 +39,18 @@ Layout_task_runner::run(Workqueue* workqueue)
 // Layout methods.
 
 Layout::Layout(const General_options& options)
-  : options_(options), namepool_(), sympool_(), signatures_(),
+  : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
     section_name_map_(), segment_list_(), section_list_(),
-    special_output_list_(), tls_segment_(NULL)
+    unattached_section_list_(), special_output_list_(),
+    tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL)
 {
   // Make space for more than enough segments for a typical file.
   // This is just for efficiency--it's OK if we wind up needing more.
-  segment_list_.reserve(12);
+  this->segment_list_.reserve(12);
+
+  // We expect three unattached Output_data objects: the file header,
+  // the segment headers, and the section headers.
+  this->special_output_list_.reserve(3);
 }
 
 // Hash a key we use to look up an output section mapping.
@@ -219,9 +224,10 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
                            elfcpp::Elf_Xword flags)
 {
   Output_section* os = new Output_section(name, type, flags, true);
+  this->section_list_.push_back(os);
 
   if ((flags & elfcpp::SHF_ALLOC) == 0)
-    this->section_list_.push_back(os);
+    this->unattached_section_list_.push_back(os);
   else
     {
       // This output section goes into a PT_LOAD segment.
@@ -299,6 +305,28 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
   return os;
 }
 
+// Create the dynamic sections which are needed before we read the
+// relocs.
+
+void
+Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
+                                       Symbol_table* symtab)
+{
+  if (!input_objects->any_dynamic())
+    return;
+
+  const char* dynamic_name = this->namepool_.add(".dynamic", NULL);
+  this->dynamic_section_ = this->make_output_section(dynamic_name,
+                                                    elfcpp::SHT_DYNAMIC,
+                                                    (elfcpp::SHF_ALLOC
+                                                     | elfcpp::SHF_WRITE));
+
+  symtab->define_in_output_data(input_objects->target(), "_DYNAMIC",
+                               this->dynamic_section_, 0, 0,
+                               elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
+                               elfcpp::STV_HIDDEN, 0, false, false);
+}
+
 // Find the first read-only PT_LOAD segment, creating one if
 // necessary.
 
@@ -355,7 +383,8 @@ Layout::find_first_load_seg()
 off_t
 Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 {
-  const int size = input_objects->target()->get_size();
+  const Target* const target = input_objects->target();
+  const int size = target->get_size();
 
   Output_segment* phdr_seg = NULL;
   if (input_objects->any_dynamic())
@@ -368,17 +397,22 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
       phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
       this->segment_list_.push_back(phdr_seg);
 
+      // This holds the dynamic tags.
+      Output_data_dynamic* odyn;
+      odyn = new Output_data_dynamic(input_objects->target(),
+                                    &this->dynpool_);
+
       // Create the dynamic symbol table, including the hash table,
       // the dynamic relocations, and the version sections.
-      this->create_dynamic_symtab(size, symtab);
-
-      // Create the .dynamic section to hold the dynamic data, and put
-      // it in a PT_DYNAMIC segment.
-      this->create_dynamic_section();
+      this->create_dynamic_symtab(target, odyn, symtab);
 
       // Create the .interp section to hold the name of the
       // interpreter, and put it in a PT_INTERP segment.
-      this->create_interp(input_objects->target());
+      this->create_interp(target);
+
+      // Finish the .dynamic section to hold the dynamic data, and put
+      // it in a PT_DYNAMIC segment.
+      this->finish_dynamic_section(input_objects, symtab, odyn);
     }
 
   // FIXME: Handle PT_GNU_STACK.
@@ -386,7 +420,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   Output_segment* load_seg = this->find_first_load_seg();
 
   // Lay out the segment headers.
-  bool big_endian = input_objects->target()->is_big_endian();
+  bool big_endian = target->is_big_endian();
   Output_segment_headers* segment_headers;
   segment_headers = new Output_segment_headers(size, big_endian,
                                               this->segment_list_);
@@ -400,7 +434,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   file_header = new Output_file_header(size,
                                       big_endian,
                                       this->options_,
-                                      input_objects->target(),
+                                      target,
                                       symtab,
                                       segment_headers);
   load_seg->add_initial_output_data(file_header);
@@ -412,15 +446,13 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 
   // Set the file offsets of all the segments, and all the sections
   // they contain.
-  off_t off = this->set_segment_offsets(input_objects->target(), load_seg,
-                                       &shndx);
+  off_t off = this->set_segment_offsets(target, load_seg, &shndx);
 
   // Create the symbol table sections.
   // FIXME: We don't need to do this if we are stripping symbols.
-  Output_section* osymtab;
   Output_section* ostrtab;
   this->create_symtab_sections(size, input_objects, symtab, &off,
-                              &osymtab, &ostrtab);
+                              &ostrtab);
 
   // Create the .shstrtab section.
   Output_section* shstrtab_section = this->create_shstrtab();
@@ -430,7 +462,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   off = this->set_section_offsets(off, &shndx);
 
   // Now the section index of OSTRTAB is set.
-  osymtab->set_link(ostrtab->out_shndx());
+  this->symtab_section_->set_link(ostrtab->out_shndx());
 
   // Create the section table header.
   Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
@@ -438,6 +470,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   file_header->set_section_info(oshdrs, shstrtab_section);
 
   // Now we know exactly where everything goes in the output file.
+  Output_data::layout_complete();
 
   return off;
 }
@@ -457,7 +490,7 @@ Layout::segment_precedes(const Output_segment* seg1,
   // segment.  We simply make it always first.
   if (type1 == elfcpp::PT_PHDR)
     {
-      assert(type2 != elfcpp::PT_PHDR);
+      gold_assert(type2 != elfcpp::PT_PHDR);
       return true;
     }
   if (type2 == elfcpp::PT_PHDR)
@@ -467,7 +500,7 @@ Layout::segment_precedes(const Output_segment* seg1,
   // segment.  We simply make it always second.
   if (type1 == elfcpp::PT_INTERP)
     {
-      assert(type2 != elfcpp::PT_INTERP);
+      gold_assert(type2 != elfcpp::PT_INTERP);
       return true;
     }
   if (type2 == elfcpp::PT_INTERP)
@@ -497,7 +530,7 @@ Layout::segment_precedes(const Output_segment* seg1,
     {
       if (type1 != type2)
        return type1 < type2;
-      assert(flags1 != flags2);
+      gold_assert(flags1 != flags2);
       return flags1 < flags2;
     }
 
@@ -522,7 +555,7 @@ Layout::segment_precedes(const Output_segment* seg1,
 
   uint64_t paddr1 = seg1->paddr();
   uint64_t paddr2 = seg2->paddr();
-  assert(paddr1 != paddr2);
+  gold_assert(paddr1 != paddr2);
   return paddr1 < paddr2;
 }
 
@@ -550,7 +583,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
       if ((*p)->type() == elfcpp::PT_LOAD)
        {
          if (load_seg != NULL && load_seg != *p)
-           abort();
+           gold_unreachable();
          load_seg = NULL;
 
          // If the last segment was readonly, and this one is not,
@@ -630,8 +663,8 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
 off_t
 Layout::set_section_offsets(off_t off, unsigned int* pshndx)
 {
-  for (Layout::Section_list::iterator p = this->section_list_.begin();
-       p != this->section_list_.end();
+  for (Section_list::iterator p = this->unattached_section_list_.begin();
+       p != this->unattached_section_list_.end();
        ++p)
     {
       (*p)->set_out_shndx(*pshndx);
@@ -651,7 +684,6 @@ void
 Layout::create_symtab_sections(int size, const Input_objects* input_objects,
                               Symbol_table* symtab,
                               off_t* poff,
-                              Output_section** posymtab,
                               Output_section** postrtab)
 {
   int symsize;
@@ -667,7 +699,7 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
       align = 8;
     }
   else
-    abort();
+    gold_unreachable();
 
   off_t off = *poff;
   off = align_address(off, align);
@@ -678,6 +710,21 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
   off += symsize;
   unsigned int local_symbol_index = 1;
 
+  // Add STT_SECTION symbols for each Output section which needs one.
+  for (Section_list::iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      if (!(*p)->needs_symtab_index())
+       (*p)->set_symtab_index(-1U);
+      else
+       {
+         (*p)->set_symtab_index(local_symbol_index);
+         ++local_symbol_index;
+         off += symsize;
+       }
+    }
+
   for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
        p != input_objects->relobj_end();
        ++p)
@@ -691,30 +738,35 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
     }
 
   unsigned int local_symcount = local_symbol_index;
-  assert(local_symcount * symsize == off - startoff);
+  gold_assert(local_symcount * symsize == off - startoff);
 
   off = symtab->finalize(local_symcount, off, &this->sympool_);
 
   this->sympool_.set_string_offsets();
 
   const char* symtab_name = this->namepool_.add(".symtab", NULL);
-  Output_section* osymtab = new Output_section_symtab(symtab_name,
-                                                     off - startoff);
-  this->section_list_.push_back(osymtab);
+  Output_section* osymtab = this->make_output_section(symtab_name,
+                                                     elfcpp::SHT_SYMTAB,
+                                                     0);
+  this->symtab_section_ = osymtab;
+
+  Output_section_data* pos = new Output_data_space(off - startoff,
+                                                  align);
+  osymtab->add_output_section_data(pos);
 
   const char* strtab_name = this->namepool_.add(".strtab", NULL);
-  Output_section *ostrtab = new Output_section_strtab(strtab_name,
-                                                     &this->sympool_);
-  this->section_list_.push_back(ostrtab);
-  this->special_output_list_.push_back(ostrtab);
+  Output_section* ostrtab = this->make_output_section(strtab_name,
+                                                     elfcpp::SHT_STRTAB,
+                                                     0);
+
+  Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
+  ostrtab->add_output_section_data(pstr);
 
   osymtab->set_address(0, startoff);
   osymtab->set_info(local_symcount);
   osymtab->set_entsize(symsize);
-  osymtab->set_addralign(align);
 
   *poff = off;
-  *posymtab = osymtab;
   *postrtab = ostrtab;
 }
 
@@ -732,10 +784,10 @@ Layout::create_shstrtab()
 
   this->namepool_.set_string_offsets();
 
-  Output_section* os = new Output_section_strtab(name, &this->namepool_);
+  Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0);
 
-  this->section_list_.push_back(os);
-  this->special_output_list_.push_back(os);
+  Output_section_data* posd = new Output_data_strtab(&this->namepool_);
+  os->add_output_section_data(posd);
 
   return os;
 }
@@ -748,7 +800,7 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
 {
   Output_section_headers* oshdrs;
   oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
-                                     this->section_list_,
+                                     this->unattached_section_list_,
                                      &this->namepool_);
   off_t off = align_address(*poff, oshdrs->addralign());
   oshdrs->set_address(0, off);
@@ -761,17 +813,109 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
 // Create the dynamic symbol table.
 
 void
-Layout::create_dynamic_symtab(int, Symbol_table*)
+Layout::create_dynamic_symtab(const Target* target, Output_data_dynamic* odyn,
+                             Symbol_table* symtab)
 {
-  abort();
-}
+  // Count all the symbols in the dynamic symbol table, and set the
+  // dynamic symbol indexes.
 
-// Create the .dynamic section and PT_DYNAMIC segment.
+  // Skip symbol 0, which is always all zeroes.
+  unsigned int index = 1;
 
-void
-Layout::create_dynamic_section()
-{
-  abort();
+  // Add STT_SECTION symbols for each Output section which needs one.
+  for (Section_list::iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      if (!(*p)->needs_dynsym_index())
+       (*p)->set_dynsym_index(-1U);
+      else
+       {
+         (*p)->set_dynsym_index(index);
+         ++index;
+       }
+    }
+
+  // FIXME: Some targets apparently require local symbols in the
+  // dynamic symbol table.  Here is where we will have to count them,
+  // and set the dynamic symbol indexes, and add the names to
+  // this->dynpool_.
+
+  unsigned int local_symcount = index;
+
+  std::vector<Symbol*> dynamic_symbols;
+
+  // FIXME: We have to tell set_dynsym_indexes whether the
+  // -E/--export-dynamic option was used.
+  index = symtab->set_dynsym_indexes(index, &dynamic_symbols,
+                                    &this->dynpool_);
+
+  int symsize;
+  unsigned int align;
+  const int size = target->get_size();
+  if (size == 32)
+    {
+      symsize = elfcpp::Elf_sizes<32>::sym_size;
+      align = 4;
+    }
+  else if (size == 64)
+    {
+      symsize = elfcpp::Elf_sizes<64>::sym_size;
+      align = 8;
+    }
+  else
+    gold_unreachable();
+
+  const char* dynsym_name = this->namepool_.add(".dynsym", NULL);
+  Output_section* dynsym = this->make_output_section(dynsym_name,
+                                                    elfcpp::SHT_DYNSYM,
+                                                    elfcpp::SHF_ALLOC);
+
+  Output_section_data* odata = new Output_data_space(index * symsize,
+                                                    align);
+  dynsym->add_output_section_data(odata);
+
+  dynsym->set_info(local_symcount);
+  dynsym->set_entsize(symsize);
+  dynsym->set_addralign(align);
+
+  this->dynsym_section_ = dynsym;
+
+  odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
+  odyn->add_constant(elfcpp::DT_SYMENT, symsize);
+
+  const char* dynstr_name = this->namepool_.add(".dynstr", NULL);
+  Output_section* dynstr = this->make_output_section(dynstr_name,
+                                                    elfcpp::SHT_STRTAB,
+                                                    elfcpp::SHF_ALLOC);
+
+  Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
+  dynstr->add_output_section_data(strdata);
+
+  odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
+  odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
+
+  // FIXME: We need an option to create a GNU hash table.
+
+  unsigned char* phash;
+  unsigned int hashlen;
+  Dynobj::create_elf_hash_table(target, dynamic_symbols, local_symcount,
+                               &phash, &hashlen);
+
+  const char* hash_name = this->namepool_.add(".hash", NULL);
+  Output_section* hashsec = this->make_output_section(hash_name,
+                                                     elfcpp::SHT_HASH,
+                                                     elfcpp::SHF_ALLOC);
+
+  Output_section_data* hashdata = new Output_data_const_buffer(phash,
+                                                              hashlen,
+                                                              align);
+  hashsec->add_output_section_data(hashdata);
+
+  hashsec->set_entsize(4);
+  // FIXME: .hash should link to .dynsym.
+
+  odyn->add_section_address(elfcpp::DT_HASH, hashsec);
 }
 
 // Create the .interp section and PT_INTERP segment.
@@ -783,7 +927,7 @@ Layout::create_interp(const Target* target)
   if (interp == NULL)
     {
       interp = target->dynamic_linker();
-      assert(interp != NULL);
+      gold_assert(interp != NULL);
     }
 
   size_t len = strlen(interp) + 1;
@@ -801,6 +945,41 @@ Layout::create_interp(const Target* target)
   oseg->add_initial_output_section(osec, elfcpp::PF_R);
 }
 
+// Finish the .dynamic section and PT_DYNAMIC segment.
+
+void
+Layout::finish_dynamic_section(const Input_objects* input_objects,
+                              const Symbol_table* symtab,
+                              Output_data_dynamic* odyn)
+{
+  this->dynamic_section_->add_output_section_data(odyn);
+
+  Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
+                                           elfcpp::PF_R | elfcpp::PF_W);
+  this->segment_list_.push_back(oseg);
+  oseg->add_initial_output_section(this->dynamic_section_,
+                                  elfcpp::PF_R | elfcpp::PF_W);
+
+  for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
+       p != input_objects->dynobj_end();
+       ++p)
+    {
+      // FIXME: Handle --as-needed.
+      odyn->add_string(elfcpp::DT_NEEDED, (*p)->soname());
+    }
+
+  // FIXME: Support --init and --fini.
+  Symbol* sym = symtab->lookup("_init");
+  if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
+    odyn->add_symbol(elfcpp::DT_INIT, sym);
+
+  sym = symtab->lookup("_fini");
+  if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
+    odyn->add_symbol(elfcpp::DT_FINI, sym);
+
+  // FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
+}
+
 // The mapping of .gnu.linkonce section names to real section names.
 
 #define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
@@ -950,8 +1129,51 @@ Layout::add_comdat(const char* signature, bool group)
 // Write out data not associated with a section or the symbol table.
 
 void
-Layout::write_data(Output_file* of) const
+Layout::write_data(const Symbol_table* symtab, const Target* target,
+                  Output_file* of) const
 {
+  const Output_section* symtab_section = this->symtab_section_;
+  for (Section_list::const_iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      if ((*p)->needs_symtab_index())
+       {
+         gold_assert(symtab_section != NULL);
+         unsigned int index = (*p)->symtab_index();
+         gold_assert(index > 0 && index != -1U);
+         off_t off = (symtab_section->offset()
+                      + index * symtab_section->entsize());
+         symtab->write_section_symbol(target, *p, of, off);
+       }
+    }
+
+  const Output_section* dynsym_section = this->dynsym_section_;
+  for (Section_list::const_iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      if ((*p)->needs_dynsym_index())
+       {
+         gold_assert(dynsym_section != NULL);
+         unsigned int index = (*p)->dynsym_index();
+         gold_assert(index > 0 && index != -1U);
+         off_t off = (dynsym_section->offset()
+                      + index * dynsym_section->entsize());
+         symtab->write_section_symbol(target, *p, of, off);
+       }
+    }
+
+  // Write out the Output_sections.  Most won't have anything to
+  // write, since most of the data will come from input sections which
+  // are handled elsewhere.  But some Output_sections do have
+  // Output_data.
+  for (Section_list::const_iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    (*p)->write(of);
+
+  // Write out the Output_data which are not in an Output_section.
   for (Data_list::const_iterator p = this->special_output_list_.begin();
        p != this->special_output_list_.end();
        ++p)
@@ -981,7 +1203,7 @@ Write_data_task::locks(Workqueue* workqueue)
 void
 Write_data_task::run(Workqueue*)
 {
-  this->layout_->write_data(this->of_);
+  this->layout_->write_data(this->symtab_, this->target_, this->of_);
 }
 
 // Write_symbols_task methods.
index 759fd85..26948bb 100644 (file)
@@ -20,10 +20,10 @@ class Input_objects;
 class Symbol_table;
 class Output_section_data;
 class Output_section;
-class Output_section_symtab;
 class Output_section_headers;
 class Output_segment;
 class Output_data;
+class Output_data_dynamic;
 class Target;
 
 // This task function handles mapping the input sections to output
@@ -80,6 +80,10 @@ class Layout
                          elfcpp::Elf_Xword flags,
                          Output_section_data*);
 
+  // Create dynamic sections if necessary.
+  void
+  create_initial_dynamic_sections(const Input_objects*, Symbol_table*);
+
   // Return the Stringpool used for symbol names.
   const Stringpool*
   sympool() const
@@ -110,7 +114,7 @@ class Layout
   // Write out data not associated with an input file or the symbol
   // table.
   void
-  write_data(Output_file*) const;
+  write_data(const Symbol_table*, const Target*, Output_file*) const;
 
   // Return an output section named NAME, or NULL if there is none.
   Output_section*
@@ -128,11 +132,11 @@ class Layout
 
   // The list of sections not attached to a segment.
 
-  typedef std::list<Output_section*> Section_list;
+  typedef std::vector<Output_section*> Section_list;
 
   // The list of information to write out which is not attached to
   // either a section or a segment.
-  typedef std::list<Output_data*> Data_list;
+  typedef std::vector<Output_data*> Data_list;
 
  private:
   Layout(const Layout&);
@@ -157,7 +161,6 @@ class Layout
   // Create the output sections for the symbol table.
   void
   create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
-                        Output_section** osymtab,
                         Output_section** ostrtab);
 
   // Create the .shstrtab section.
@@ -170,11 +173,12 @@ class Layout
 
   // Create the dynamic symbol table.
   void
-  create_dynamic_symtab(int size, Symbol_table*);
+  create_dynamic_symtab(const Target*, Output_data_dynamic*, Symbol_table*);
 
-  // Create the .dynamic section and PT_DYNAMIC segment.
+  // Finish the .dynamic section and PT_DYNAMIC segment.
   void
-  create_dynamic_section();
+  finish_dynamic_section(const Input_objects*, const Symbol_table*,
+                        Output_data_dynamic*);
 
   // Create the .interp section and PT_INTERP segment.
   void
@@ -256,20 +260,30 @@ class Layout
   Stringpool namepool_;
   // The output symbol names.
   Stringpool sympool_;
+  // The dynamic strings, if needed.
+  Stringpool dynpool_;
   // The list of group sections and linkonce sections which we have seen.
   Signatures signatures_;
   // The mapping from input section name/type/flags to output sections.
   Section_name_map section_name_map_;
   // The list of output segments.
   Segment_list segment_list_;
+  // The list of output sections.
+  Section_list section_list_;
   // The list of output sections which are not attached to any output
   // segment.
-  Section_list section_list_;
-  // The list of sections which require special output because they
-  // are not comprised of input sections.
+  Section_list unattached_section_list_;
+  // The list of unattached Output_data objects which require special
+  // handling because they are not Output_sections.
   Data_list special_output_list_;
   // A pointer to the PT_TLS segment if there is one.
   Output_segment* tls_segment_;
+  // The SHT_SYMTAB output section.
+  Output_section* symtab_section_;
+  // The SHT_DYNSYM output section if there is one.
+  Output_section* dynsym_section_;
+  // The SHT_DYNAMIC output section if there is one.
+  Output_section* dynamic_section_;
 };
 
 // This task handles writing out data which is not part of a section
@@ -278,9 +292,11 @@ class Layout
 class Write_data_task : public Task
 {
  public:
-  Write_data_task(const Layout* layout, Output_file* of,
+  Write_data_task(const Layout* layout, const Symbol_table* symtab,
+                 const Target* target, Output_file* of,
                  Task_token* final_blocker)
-    : layout_(layout), of_(of), final_blocker_(final_blocker)
+    : layout_(layout), symtab_(symtab), target_(target), of_(of),
+      final_blocker_(final_blocker)
   { }
 
   // The standard Task methods.
@@ -296,6 +312,8 @@ class Write_data_task : public Task
 
  private:
   const Layout* layout_;
+  const Symbol_table* symtab_;
+  const Target* target_;
   Output_file* of_;
   Task_token* final_blocker_;
 };
index 74c1347..2086fed 100644 (file)
@@ -4,7 +4,6 @@
 
 #include <cerrno>
 #include <cstring>
-#include <cassert>
 #include <cstdarg>
 
 #include "target-select.h"
@@ -210,7 +209,7 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
   // Get the symbol table section header.
   typename This::Shdr symtabshdr(pshdrs
                                 + this->symtab_shndx_ * This::shdr_size);
-  assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+  gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
 
   // We only need the external symbols.
   const int sym_size = This::sym_size;
@@ -477,7 +476,7 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
 {
   if (sd->symbols == NULL)
     {
-      assert(sd->symbol_names == NULL);
+      gold_assert(sd->symbol_names == NULL);
       return;
     }
 
@@ -517,14 +516,14 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
                                                          off_t off,
                                                          Stringpool* pool)
 {
-  assert(this->symtab_shndx_ != -1U);
+  gold_assert(this->symtab_shndx_ != -1U);
   if (this->symtab_shndx_ == 0)
     {
       // This object has no symbols.  Weird but legal.
       return index;
     }
 
-  assert(off == static_cast<off_t>(align_address(off, size >> 3)));
+  gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
 
   this->local_symbol_offset_ = off;
 
@@ -532,12 +531,12 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
   const unsigned int symtab_shndx = this->symtab_shndx_;
   typename This::Shdr symtabshdr(this,
                                 this->elf_file_.section_header(symtab_shndx));
-  assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+  gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
 
   // Read the local symbols.
   const int sym_size = This::sym_size;
   const unsigned int loccount = this->local_symbol_count_;
-  assert(loccount == symtabshdr.get_sh_info());
+  gold_assert(loccount == symtabshdr.get_sh_info());
   off_t locsize = loccount * sym_size;
   const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
                                              locsize);
@@ -641,7 +640,7 @@ void
 Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
                                                    const Stringpool* sympool)
 {
-  assert(this->symtab_shndx_ != -1U);
+  gold_assert(this->symtab_shndx_ != -1U);
   if (this->symtab_shndx_ == 0)
     {
       // This object has no symbols.  Weird but legal.
@@ -652,9 +651,9 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
   const unsigned int symtab_shndx = this->symtab_shndx_;
   typename This::Shdr symtabshdr(this,
                                 this->elf_file_.section_header(symtab_shndx));
-  assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+  gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
   const unsigned int loccount = this->local_symbol_count_;
-  assert(loccount == symtabshdr.get_sh_info());
+  gold_assert(loccount == symtabshdr.get_sh_info());
 
   // Read the local symbols.
   const int sym_size = This::sym_size;
@@ -676,8 +675,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
 
   const std::vector<Map_to_output>& mo(this->map_to_output());
 
-  assert(this->local_values_.size() == loccount);
-  assert(this->local_indexes_.size() == loccount);
+  gold_assert(this->local_values_.size() == loccount);
+  gold_assert(this->local_indexes_.size() == loccount);
 
   unsigned char* ov = oview;
   psyms += sym_size;
@@ -687,12 +686,12 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
 
       if (this->local_indexes_[i] == -1U)
        continue;
-      assert(this->local_indexes_[i] != 0);
+      gold_assert(this->local_indexes_[i] != 0);
 
       unsigned int st_shndx = isym.get_st_shndx();
       if (st_shndx < elfcpp::SHN_LORESERVE)
        {
-         assert(st_shndx < mo.size());
+         gold_assert(st_shndx < mo.size());
          if (mo[st_shndx].output_section == NULL)
            continue;
          st_shndx = mo[st_shndx].output_section->out_shndx();
@@ -700,7 +699,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
 
       elfcpp::Sym_write<size, big_endian> osym(ov);
 
-      assert(isym.get_st_name() < strtab_size);
+      gold_assert(isym.get_st_name() < strtab_size);
       const char* name = pnames + isym.get_st_name();
       osym.put_st_name(sympool->get_offset(name));
       osym.put_st_value(this->local_values_[i]);
@@ -712,7 +711,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
       ov += sym_size;
     }
 
-  assert(ov - oview == output_size);
+  gold_assert(ov - oview == output_size);
 
   of->write_output_view(this->local_symbol_offset_, output_size, oview);
 }
index b2f4706..cd2bc8d 100644 (file)
@@ -3,7 +3,6 @@
 #ifndef GOLD_OBJECT_H
 #define GOLD_OBJECT_H
 
-#include <cassert>
 #include <string>
 #include <vector>
 
@@ -166,8 +165,13 @@ class Object
   // Return the name of a section given a section index.  This is only
   // used for error messages.
   std::string
-  section_name(unsigned int shnum)
-  { return this->do_section_name(shnum); }
+  section_name(unsigned int shndx)
+  { return this->do_section_name(shndx); }
+
+  // Return the section flags given a section index.
+  uint64_t
+  section_flags(unsigned int shndx)
+  { return this->do_section_flags(shndx); }
 
   // Functions and types for the elfcpp::Elf_file interface.  This
   // permit us to use Object as the File template parameter for
@@ -233,11 +237,15 @@ class Object
   // Return the location of the contents of a section.  Implemented by
   // child class.
   virtual Location
-  do_section_contents(unsigned int shnum) = 0;
+  do_section_contents(unsigned int shndx) = 0;
 
   // Get the name of a section--implemented by child class.
   virtual std::string
-  do_section_name(unsigned int shnum) = 0;
+  do_section_name(unsigned int shndx) = 0;
+
+  // Get section flags--implemented by child class.
+  virtual uint64_t
+  do_section_flags(unsigned int shndx) = 0;
 
   // Get the file.
   Input_file*
@@ -324,8 +332,8 @@ template<int size, bool big_endian>
 inline Sized_target<size, big_endian>*
 Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY)
 {
-  assert(this->target_->get_size() == size);
-  assert(this->target_->is_big_endian() ? big_endian : !big_endian);
+  gold_assert(this->target_->get_size() == size);
+  gold_assert(this->target_->is_big_endian() ? big_endian : !big_endian);
   return static_cast<Sized_target<size, big_endian>*>(this->target_);
 }
 
@@ -367,7 +375,7 @@ class Relobj : public Object
   bool
   is_section_included(unsigned int shnum) const
   {
-    assert(shnum < this->map_to_output_.size());
+    gold_assert(shnum < this->map_to_output_.size());
     return this->map_to_output_[shnum].output_section != NULL;
   }
 
@@ -381,7 +389,7 @@ class Relobj : public Object
   void
   set_section_offset(unsigned int shndx, off_t off)
   {
-    assert(shndx < this->map_to_output_.size());
+    gold_assert(shndx < this->map_to_output_.size());
     this->map_to_output_[shndx].offset = off;
   }
 
@@ -431,7 +439,7 @@ class Relobj : public Object
 inline Output_section*
 Relobj::output_section(unsigned int shnum, off_t* poff)
 {
-  assert(shnum < this->map_to_output_.size());
+  gold_assert(shnum < this->map_to_output_.size());
   const Map_to_output& mo(this->map_to_output_[shnum]);
   *poff = mo.offset;
   return mo.output_section;
@@ -460,8 +468,8 @@ class Sized_relobj : public Relobj
   unsigned int
   symtab_index(unsigned int sym) const
   {
-    assert(sym < this->local_indexes_.size());
-    assert(this->local_indexes_[sym] != 0);
+    gold_assert(sym < this->local_indexes_.size());
+    gold_assert(this->local_indexes_[sym] != 0);
     return this->local_indexes_[sym];
   }
 
@@ -506,6 +514,11 @@ class Sized_relobj : public Relobj
   do_section_contents(unsigned int shndx)
   { return this->elf_file_.section_contents(shndx); }
 
+  // Return section flags.
+  uint64_t
+  do_section_flags(unsigned int shndx)
+  { return this->elf_file_.section_flags(shndx); }
+
   // Return the appropriate Sized_target structure.
   Sized_target<size, big_endian>*
   sized_target()
index 6b88429..b8339e8 100644 (file)
@@ -291,8 +291,8 @@ Input_arguments::add_file(const Input_file_argument& file)
     this->input_argument_list_.push_back(Input_argument(file));
   else
     {
-      assert(!this->input_argument_list_.empty());
-      assert(this->input_argument_list_.back().is_group());
+      gold_assert(!this->input_argument_list_.empty());
+      gold_assert(this->input_argument_list_.back().is_group());
       this->input_argument_list_.back().group()->add_file(file);
     }
 }
@@ -302,7 +302,7 @@ Input_arguments::add_file(const Input_file_argument& file)
 void
 Input_arguments::start_group()
 {
-  assert(!this->in_group_);
+  gold_assert(!this->in_group_);
   Input_file_group* group = new Input_file_group();
   this->input_argument_list_.push_back(Input_argument(group));
   this->in_group_ = true;
@@ -313,7 +313,7 @@ Input_arguments::start_group()
 void
 Input_arguments::end_group()
 {
-  assert(this->in_group_);
+  gold_assert(this->in_group_);
   this->in_group_ = false;
 }
 
index ac51524..56907c0 100644 (file)
@@ -15,7 +15,6 @@
 #include <list>
 #include <string>
 #include <vector>
-#include <cassert>
 
 namespace gold
 {
@@ -218,7 +217,7 @@ class Input_argument
   const Input_file_argument&
   file() const
   {
-    assert(this->is_file_);
+    gold_assert(this->is_file_);
     return this->file_;
   }
 
@@ -226,14 +225,14 @@ class Input_argument
   const Input_file_group*
   group() const
   {
-    assert(!this->is_file_);
+    gold_assert(!this->is_file_);
     return this->group_;
   }
 
   Input_file_group*
   group()
   {
-    assert(!this->is_file_);
+    gold_assert(!this->is_file_);
     return this->group_;
   }
 
index 0330384..e4720df 100644 (file)
 namespace gold
 {
 
+// Output_data variables.
+
+bool Output_data::sizes_are_fixed;
+
 // Output_data methods.
 
 Output_data::~Output_data()
@@ -45,7 +49,7 @@ Output_data::default_alignment(int size)
   else if (size == 64)
     return 8;
   else
-    abort();
+    gold_unreachable();
 }
 
 // Output_section_header methods.  This currently assumes that the
@@ -55,12 +59,12 @@ Output_section_headers::Output_section_headers(
     int size,
     bool big_endian,
     const Layout::Segment_list& segment_list,
-    const Layout::Section_list& section_list,
+    const Layout::Section_list& unattached_section_list,
     const Stringpool* secnamepool)
   : size_(size),
     big_endian_(big_endian),
     segment_list_(segment_list),
-    section_list_(section_list),
+    unattached_section_list_(unattached_section_list),
     secnamepool_(secnamepool)
 {
   // Count all the sections.  Start with 1 for the null section.
@@ -70,7 +74,7 @@ Output_section_headers::Output_section_headers(
        ++p)
     if ((*p)->type() == elfcpp::PT_LOAD)
       count += (*p)->output_section_count();
-  count += section_list.size();
+  count += unattached_section_list.size();
 
   int shdr_size;
   if (size == 32)
@@ -78,7 +82,7 @@ Output_section_headers::Output_section_headers(
   else if (size == 64)
     shdr_size = elfcpp::Elf_sizes<64>::shdr_size;
   else
-    abort();
+    gold_unreachable();
 
   this->set_data_size(count * shdr_size);
 }
@@ -103,7 +107,7 @@ Output_section_headers::do_write(Output_file* of)
        this->do_sized_write<64, false>(of);
     }
   else
-    abort();
+    gold_unreachable();
 }
 
 template<int size, bool big_endian>
@@ -139,11 +143,12 @@ Output_section_headers::do_sized_write(Output_file* of)
     v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
            this->secnamepool_, v, &shndx
            SELECT_SIZE_ENDIAN(size, big_endian));
-  for (Layout::Section_list::const_iterator p = this->section_list_.begin();
-       p != this->section_list_.end();
+  for (Layout::Section_list::const_iterator p =
+        this->unattached_section_list_.begin();
+       p != this->unattached_section_list_.end();
        ++p)
     {
-      assert(shndx == (*p)->out_shndx());
+      gold_assert(shndx == (*p)->out_shndx());
       elfcpp::Shdr_write<size, big_endian> oshdr(v);
       (*p)->write_header(this->secnamepool_, &oshdr);
       v += shdr_size;
@@ -167,7 +172,7 @@ Output_segment_headers::Output_segment_headers(
   else if (size == 64)
     phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
   else
-    abort();
+    gold_unreachable();
 
   this->set_data_size(segment_list.size() * phdr_size);
 }
@@ -190,7 +195,7 @@ Output_segment_headers::do_write(Output_file* of)
        this->do_sized_write<64, false>(of);
     }
   else
-    abort();
+    gold_unreachable();
 }
 
 template<int size, bool big_endian>
@@ -237,7 +242,7 @@ Output_file_header::Output_file_header(int size,
   else if (size == 64)
     ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
   else
-    abort();
+    gold_unreachable();
 
   this->set_data_size(ehdr_size);
 }
@@ -272,7 +277,7 @@ Output_file_header::do_write(Output_file* of)
        this->do_sized_write<64, false>(of);
     }
   else
-    abort();
+    gold_unreachable();
 }
 
 // Write out the file header with appropriate size and endianess.
@@ -281,7 +286,7 @@ template<int size, bool big_endian>
 void
 Output_file_header::do_sized_write(Output_file* of)
 {
-  assert(this->offset() == 0);
+  gold_assert(this->offset() == 0);
 
   int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
   unsigned char* view = of->get_output_view(0, ehdr_size);
@@ -298,7 +303,7 @@ Output_file_header::do_sized_write(Output_file* of)
   else if (size == 64)
     e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64;
   else
-    abort();
+    gold_unreachable();
   e_ident[elfcpp::EI_DATA] = (big_endian
                              ? elfcpp::ELFDATA2MSB
                              : elfcpp::ELFDATA2LSB);
@@ -352,9 +357,17 @@ Output_file_header::do_sized_write(Output_file* of)
 // Output_data_const methods.
 
 void
-Output_data_const::do_write(Output_file* output)
+Output_data_const::do_write(Output_file* of)
 {
-  output->write(this->offset(), data_.data(), data_.size());
+  of->write(this->offset(), this->data_.data(), this->data_.size());
+}
+
+// Output_data_const_buffer methods.
+
+void
+Output_data_const_buffer::do_write(Output_file* of)
+{
+  of->write(this->offset(), this->p_, this->data_size());
 }
 
 // Output_section_data methods.
@@ -362,10 +375,30 @@ Output_data_const::do_write(Output_file* output)
 unsigned int
 Output_section_data::do_out_shndx() const
 {
-  assert(this->output_section_ != NULL);
+  gold_assert(this->output_section_ != NULL);
   return this->output_section_->out_shndx();
 }
 
+// Output_data_strtab methods.
+
+// Set the address.  We don't actually care about the address, but we
+// do set our final size.
+
+void
+Output_data_strtab::do_set_address(uint64_t, off_t)
+{
+  this->strtab_->set_string_offsets();
+  this->set_data_size(this->strtab_->get_strtab_size());
+}
+
+// Write out a string table.
+
+void
+Output_data_strtab::do_write(Output_file* of)
+{
+  this->strtab_->write(of, this->offset());
+}
+
 // Output_reloc methods.
 
 // Get the symbol index of a relocation.
@@ -379,7 +412,7 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
   switch (this->local_sym_index_)
     {
     case INVALID_CODE:
-      abort();
+      gold_unreachable();
 
     case GSYM_CODE:
       if (this->u_.gsym == NULL)
@@ -403,13 +436,13 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
          // FIXME: It seems that some targets may need to generate
          // dynamic relocations against local symbols for some
          // reasons.  This will have to be addressed at some point.
-         abort();
+         gold_unreachable();
        }
       else
        index = this->u_.object->symtab_index(this->local_sym_index_);
       break;
     }
-  assert(index != -1U);
+  gold_assert(index != -1U);
   return index;
 }
 
@@ -422,7 +455,10 @@ void
 Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
     Write_rel* wr) const
 {
-  wr->put_r_offset(this->address_);
+  Address address = this->address_;
+  if (this->od_ != NULL)
+    address += this->od_->address();
+  wr->put_r_offset(address);
   wr->put_r_info(elfcpp::elf_r_info<size>(this->get_symbol_index(),
                                          this->type_));
 }
@@ -472,7 +508,7 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
       pov += reloc_size;
     }
 
-  assert(pov - oview == oview_size);
+  gold_assert(pov - oview == oview_size);
 
   of->write_output_view(off, oview_size, oview);
 
@@ -486,8 +522,9 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
 
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
-    const
+Output_data_got<size, big_endian>::Got_entry::write(
+    const General_options* options,
+    unsigned char* pov) const
 {
   Valtype val = 0;
 
@@ -501,7 +538,7 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
        // value.  Otherwise we just write zero.  The target code is
        // responsible for creating a relocation entry to fill in the
        // value at runtime.
-       if (gsym->is_resolved_locally())
+       if (gsym->final_value_is_known(options))
          {
            Sized_symbol<size>* sgsym;
            // This cast is a bit ugly.  We don't want to put a
@@ -518,11 +555,10 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
       break;
 
     default:
-      abort();
+      gold_unreachable();
     }
 
-  Valtype* povv = reinterpret_cast<Valtype*>(pov);
-  elfcpp::Swap<size, big_endian>::writeval(povv, val);
+  elfcpp::Swap<size, big_endian>::writeval(pov, val);
 }
 
 // Output_data_got methods.
@@ -561,11 +597,11 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
        p != this->entries_.end();
        ++p)
     {
-      p->write(pov);
+      p->write(this->options_, pov);
       pov += add;
     }
 
-  assert(pov - oview == oview_size);
+  gold_assert(pov - oview == oview_size);
 
   of->write_output_view(off, oview_size, oview);
 
@@ -573,6 +609,121 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
   this->entries_.clear();
 }
 
+// Output_data_dynamic::Dynamic_entry methods.
+
+// Write out the entry.
+
+template<int size, bool big_endian>
+void
+Output_data_dynamic::Dynamic_entry::write(
+    unsigned char* pov,
+    const Stringpool* pool) const
+{
+  typename elfcpp::Elf_types<size>::Elf_WXword val;
+  switch (this->classification_)
+    {
+    case DYNAMIC_NUMBER:
+      val = this->u_.val;
+      break;
+
+    case DYNAMIC_SECTION_ADDRESS:
+      val = this->u_.os->address();
+      break;
+
+    case DYNAMIC_SECTION_SIZE:
+      val = this->u_.os->data_size();
+      break;
+
+    case DYNAMIC_SYMBOL:
+      {
+       Sized_symbol<size>* s = static_cast<Sized_symbol<size>*>(this->u_.sym);
+       val = s->value();
+      }
+      break;
+
+    case DYNAMIC_STRING:
+      val = pool->get_offset(this->u_.str);
+      break;
+
+    default:
+      gold_unreachable();
+    }
+
+  elfcpp::Dyn_write<size, big_endian> dw(pov);
+  dw.put_d_tag(this->tag_);
+  dw.put_d_val(val);
+}
+
+// Output_data_dynamic methods.
+
+// Set the final data size.
+
+void
+Output_data_dynamic::do_set_address(uint64_t, off_t)
+{
+  // Add the terminating entry.
+  this->add_constant(elfcpp::DT_NULL, 0);
+
+  int dyn_size;
+  if (this->target_->get_size() == 32)
+    dyn_size = elfcpp::Elf_sizes<32>::dyn_size;
+  else if (this->target_->get_size() == 64)
+    dyn_size = elfcpp::Elf_sizes<64>::dyn_size;
+  else
+    gold_unreachable();
+  this->set_data_size(this->entries_.size() * dyn_size);
+}
+
+// Write out the dynamic entries.
+
+void
+Output_data_dynamic::do_write(Output_file* of)
+{
+  if (this->target_->get_size() == 32)
+    {
+      if (this->target_->is_big_endian())
+       this->sized_write<32, true>(of);
+      else
+       this->sized_write<32, false>(of);
+    }
+  else if (this->target_->get_size() == 64)
+    {
+      if (this->target_->is_big_endian())
+       this->sized_write<64, true>(of);
+      else
+       this->sized_write<64, false>(of);
+    }
+  else
+    gold_unreachable();
+}
+
+template<int size, bool big_endian>
+void
+Output_data_dynamic::sized_write(Output_file* of)
+{
+  const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size;
+
+  const off_t offset = this->offset();
+  const off_t oview_size = this->data_size();
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+  unsigned char* pov = oview;
+  for (typename Dynamic_entries::const_iterator p = this->entries_.begin();
+       p != this->entries_.end();
+       ++p)
+    {
+      p->write<size, big_endian>(pov, this->pool_);
+      pov += dyn_size;
+    }
+
+  gold_assert(pov - oview == oview_size);
+
+  of->write_output_view(offset, oview_size, oview);
+
+  // We no longer need the dynamic entries.
+  this->entries_.clear();
+}
+
 // Output_section::Input_section methods.
 
 // Return the data size.  For an input section we store the size here.
@@ -628,7 +779,9 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     dynsym_index_(0),
     input_sections_(),
     first_input_offset_(0),
-    may_add_data_(may_add_data)
+    may_add_data_(may_add_data),
+    needs_symtab_index_(false),
+    needs_dynsym_index_(false)
 {
 }
 
@@ -648,7 +801,7 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
                                  const char* secname,
                                  const elfcpp::Shdr<size, big_endian>& shdr)
 {
-  assert(this->may_add_data_);
+  gold_assert(this->may_add_data_);
 
   elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
   if ((addralign & (addralign - 1)) != 0)
@@ -682,7 +835,7 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
 void
 Output_section::add_output_section_data(Output_section_data* posd)
 {
-  assert(this->may_add_data_);
+  gold_assert(this->may_add_data_);
 
   if (this->input_sections_.empty())
     this->first_input_offset_ = this->data_size();
@@ -750,22 +903,6 @@ Output_section::do_write(Output_file* of)
     p->write(of);
 }
 
-// Output_section_strtab methods.
-
-Output_section_strtab::Output_section_strtab(const char* name,
-                                            Stringpool* contents)
-  : Output_section(name, elfcpp::SHT_STRTAB, 0, false),
-    contents_(contents)
-{
-  this->set_data_size(contents->get_strtab_size());
-}
-
-void
-Output_section_strtab::do_write(Output_file* of)
-{
-  this->contents_->write(of, this->offset());
-}
-
 // Output segment methods.
 
 Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
@@ -790,8 +927,8 @@ Output_segment::add_output_section(Output_section* os,
                                   elfcpp::Elf_Word seg_flags,
                                   bool front)
 {
-  assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
-  assert(!this->is_align_known_);
+  gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+  gold_assert(!this->is_align_known_);
 
   // Update the segment flags.
   this->flags_ |= seg_flags;
@@ -817,7 +954,7 @@ Output_segment::add_output_section(Output_section* os,
 
   if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
     {
-      Layout::Data_list::iterator p = pdl->end();
+      Output_segment::Output_data_list::iterator p = pdl->end();
       do
        {
          --p;
@@ -842,7 +979,7 @@ Output_segment::add_output_section(Output_section* os,
       pdl = &this->output_data_;
       bool nobits = os->type() == elfcpp::SHT_NOBITS;
       bool sawtls = false;
-      Layout::Data_list::iterator p = pdl->end();
+      Output_segment::Output_data_list::iterator p = pdl->end();
       do
        {
          --p;
@@ -888,7 +1025,7 @@ Output_segment::add_output_section(Output_section* os,
 void
 Output_segment::add_initial_output_data(Output_data* od)
 {
-  assert(!this->is_align_known_);
+  gold_assert(!this->is_align_known_);
   this->output_data_.push_front(od);
 }
 
@@ -942,7 +1079,7 @@ uint64_t
 Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
                                      unsigned int* pshndx)
 {
-  assert(this->type_ == elfcpp::PT_LOAD);
+  gold_assert(this->type_ == elfcpp::PT_LOAD);
 
   this->vaddr_ = addr;
   this->paddr_ = addr;
@@ -1011,7 +1148,7 @@ Output_segment::set_section_list_addresses(Output_data_list* pdl,
 void
 Output_segment::set_offset()
 {
-  assert(this->type_ != elfcpp::PT_LOAD);
+  gold_assert(this->type_ != elfcpp::PT_LOAD);
 
   if (this->output_data_.empty() && this->output_bss_.empty())
     {
@@ -1136,7 +1273,7 @@ Output_segment::write_section_headers_list(const Stringpool* secnamepool,
       if ((*p)->is_section())
        {
          const Output_section* ps = static_cast<const Output_section*>(*p);
-         assert(*pshndx == ps->out_shndx());
+         gold_assert(*pshndx == ps->out_shndx());
          elfcpp::Shdr_write<size, big_endian> oshdr(v);
          ps->write_header(secnamepool, &oshdr);
          v += shdr_size;
index c31640f..c7d835d 100644 (file)
@@ -3,7 +3,6 @@
 #ifndef GOLD_OUTPUT_H
 #define GOLD_OUTPUT_H
 
-#include <cassert>
 #include <list>
 #include <vector>
 
@@ -16,8 +15,10 @@ namespace gold
 
 class General_options;
 class Object;
+class Symbol;
 class Output_file;
 class Output_section;
+class Target;
 template<int size, bool big_endian>
 class Sized_target;
 template<int size, bool big_endian>
@@ -96,6 +97,12 @@ class Output_data
   write(Output_file* file)
   { this->do_write(file); }
 
+  // This is called by Layout::finalize to note that all sizes must
+  // now be fixed.
+  static void
+  layout_complete()
+  { Output_data::sizes_are_fixed = true; }
+
  protected:
   // Functions that child classes may or in some cases must implement.
 
@@ -127,15 +134,16 @@ class Output_data
   // Return the output section index, if there is an output section.
   virtual unsigned int
   do_out_shndx() const
-  { abort(); }
+  { gold_unreachable(); }
 
   // Set the output section index, if this is an output section.
   virtual void
   do_set_out_shndx(unsigned int)
-  { abort(); }
+  { gold_unreachable(); }
 
   // Set the address and file offset of the data.  This only needs to
-  // be implemented if the child needs to know.
+  // be implemented if the child needs to know.  The child class can
+  // set its size in this call.
   virtual void
   do_set_address(uint64_t, off_t)
   { }
@@ -145,7 +153,10 @@ class Output_data
   // Set the size of the data.
   void
   set_data_size(off_t data_size)
-  { this->data_size_ = data_size; }
+  {
+    gold_assert(!Output_data::sizes_are_fixed);
+    this->data_size_ = data_size;
+  }
 
   // Return default alignment for a size--32 or 64.
   static uint64_t
@@ -155,6 +166,10 @@ class Output_data
   Output_data(const Output_data&);
   Output_data& operator=(const Output_data&);
 
+  // This is used for verification, to make sure that we don't try to
+  // change any sizes after we set the section addresses.
+  static bool sizes_are_fixed;
+
   // Memory address in file (not always meaningful).
   uint64_t address_;
   // Size of data in file.
@@ -192,7 +207,7 @@ class Output_section_headers : public Output_data
   int size_;
   bool big_endian_;
   const Layout::Segment_list& segment_list_;
-  const Layout::Section_list& section_list_;
+  const Layout::Section_list& unattached_section_list_;
   const Stringpool* secnamepool_;
 };
 
@@ -254,7 +269,7 @@ class Output_file_header : public Output_data
   // checking.
   void
   do_set_address(uint64_t, off_t off) const
-  { assert(off == 0); }
+  { gold_assert(off == 0); }
 
  private:
   // Write the data to the file with the right size and endianness.
@@ -292,7 +307,7 @@ class Output_section_data : public Output_data
   void
   set_output_section(Output_section* os)
   {
-    assert(this->output_section_ == NULL);
+    gold_assert(this->output_section_ == NULL);
     this->output_section_ = os;
   }
 
@@ -334,36 +349,87 @@ class Output_data_const : public Output_section_data
       data_(reinterpret_cast<const char*>(p), len)
   { }
 
-  // Write the data to the file.
+  // Add more data.
+  void
+  add_data(const std::string& add)
+  {
+    this->data_.append(add);
+    this->set_data_size(this->data_.size());
+  }
+
+  // Write the data to the output file.
   void
-  do_write(Output_file* output);
+  do_write(Output_file*);
 
  private:
   std::string data_;
 };
 
-// Output_data_common is used to handle the common symbols.  This is
-// quite simple.
+// Another version of Output_data with constant data, in which the
+// buffer is allocated by the caller.
 
-class Output_data_common : public Output_section_data
+class Output_data_const_buffer : public Output_section_data
 {
  public:
-  Output_data_common(uint64_t addralign)
+  Output_data_const_buffer(const unsigned char* p, off_t len,
+                          uint64_t addralign)
+    : Output_section_data(len, addralign), p_(p)
+  { }
+
+  // Write the data the output file.
+  void
+  do_write(Output_file*);
+
+ private:
+  const unsigned char* p_;
+};
+
+// A place holder for data written out via some other mechanism.
+
+class Output_data_space : public Output_section_data
+{
+ public:
+  Output_data_space(off_t data_size, uint64_t addralign)
+    : Output_section_data(data_size, addralign)
+  { }
+
+  explicit Output_data_space(uint64_t addralign)
     : Output_section_data(addralign)
   { }
 
   // Set the size.
   void
-  set_common_size(off_t common_size)
-  { this->set_data_size(common_size); }
+  set_space_size(off_t space_size)
+  { this->set_data_size(space_size); }
 
-  // Write out the data--there is nothing to do, as common symbols are
-  // always zero and are stored in the BSS.
+  // Write out the data--this must be handled elsewhere.
   void
   do_write(Output_file*)
   { }
 };
 
+// A string table which goes into an output section.
+
+class Output_data_strtab : public Output_section_data
+{
+ public:
+  Output_data_strtab(Stringpool* strtab)
+    : Output_section_data(1), strtab_(strtab)
+  { }
+
+  // This is called to set the address and file offset.  Here we make
+  // sure that the Stringpool is finalized.
+  void
+  do_set_address(uint64_t, off_t);
+
+  // Write out the data.
+  void
+  do_write(Output_file*);
+
+ private:
+  Stringpool* strtab_;
+};
+
 // This POD class is used to represent a single reloc in the output
 // file.  This could be a private class within Output_data_reloc, but
 // the templatization is complex enough that I broke it out into a
@@ -391,23 +457,29 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   { }
 
   // A reloc against a global symbol.
-  Output_reloc(Symbol* gsym, unsigned int type, Address address)
-    : local_sym_index_(GSYM_CODE), type_(type), address_(address)
+  Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+              Address address)
+    : local_sym_index_(GSYM_CODE), type_(type), od_(od), address_(address)
   { this->u_.gsym = gsym; }
 
   // A reloc against a local symbol.
   Output_reloc(Sized_relobj<size, big_endian>* object,
               unsigned int local_sym_index,
-              unsigned int type, Address address)
-    : local_sym_index_(local_sym_index), type_(type), address_(address)
+              unsigned int type,
+              Output_data* od,
+              Address address)
+    : local_sym_index_(local_sym_index), type_(type), od_(od),
+      address_(address)
   {
-    assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE);
+    gold_assert(local_sym_index != GSYM_CODE
+               && local_sym_index != INVALID_CODE);
     this->u_.object = object;
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
-  Output_reloc(Output_section* os, unsigned int type, Address address)
-    : local_sym_index_(SECTION_CODE), type_(type), address_(address)
+  Output_reloc(Output_section* os, unsigned int type, Output_data* od,
+              Address address)
+    : local_sym_index_(SECTION_CODE), type_(type), od_(od), address_(address)
   { this->u_.os = os; }
 
   // Write the reloc entry to an output view.
@@ -451,7 +523,13 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // For a local symbol, the local symbol index.  This is GSYM_CODE
   // for a global symbol, or INVALID_CODE for an uninitialized value.
   unsigned int local_sym_index_;
+  // The reloc type--a processor specific code.
   unsigned int type_;
+  // If this is not NULL, then the relocation is against the contents
+  // of this output data.
+  Output_data* od_;
+  // The reloc address--if od_ is not NULL, this is the offset from
+  // the start of od_.
   Address address_;
 };
 
@@ -471,21 +549,23 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   { }
 
   // A reloc against a global symbol.
-  Output_reloc(Symbol* gsym, unsigned int type, Address address, Addend addend)
-    : rel_(gsym, type, address), addend_(addend)
+  Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+              Address address, Addend addend)
+    : rel_(gsym, type, od, address), addend_(addend)
   { }
 
   // A reloc against a local symbol.
   Output_reloc(Sized_relobj<size, big_endian>* object,
               unsigned int local_sym_index,
-              unsigned int type, Address address, Addend addend)
-    : rel_(object, local_sym_index, type, address), addend_(addend)
+              unsigned int type, Output_data* od, Address address,
+              Addend addend)
+    : rel_(object, local_sym_index, type, od, address), addend_(addend)
   { }
 
   // A reloc against the STT_SECTION symbol of an output section.
-  Output_reloc(Output_section* os, unsigned int type, Address address,
-              Addend addend)
-    : rel_(os, type, address), addend_(addend)
+  Output_reloc(Output_section* os, unsigned int type, Output_data* od,
+              Address address, Addend addend)
+    : rel_(os, type, od, address), addend_(addend)
   { }
 
   // Write the reloc entry to an output view.
@@ -564,19 +644,21 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   // Add a reloc against a global symbol.
   void
-  add_global(Symbol* gsym, unsigned int type, Address address)
-  { this->add(Output_reloc_type(gsym, type, address)); }
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
+  { this->add(Output_reloc_type(gsym, type, od, address)); }
 
   // Add a reloc against a local symbol.
   void
   add_local(Sized_relobj<size, big_endian>* object,
-           unsigned int local_sym_index, unsigned int type, Address address)
-  { this->add(Output_reloc_type(object, local_sym_index, type, address)); }
+           unsigned int local_sym_index, unsigned int type,
+           Output_data* od, Address address)
+  { this->add(Output_reloc_type(object, local_sym_index, type, od, address)); }
 
   // A reloc against the STT_SECTION symbol of an output section.
   void
-  add_output_section(Output_section* os, unsigned int type, Address address)
-  { this->add(Output_reloc_type(os, type, address)); }
+  add_output_section(Output_section* os, unsigned int type,
+                    Output_data* od, Address address)
+  { this->add(Output_reloc_type(os, type, od, address)); }
 };
 
 // The SHT_RELA version of Output_data_reloc.
@@ -600,24 +682,25 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 
   // Add a reloc against a global symbol.
   void
-  add_global(Symbol* gsym, unsigned int type, Address address, Addend addend)
-  { this->add(Output_reloc_type(gsym, type, address, addend)); }
+  add_global(Symbol* gsym, unsigned int type, Output_data* od,
+            Address address, Addend addend)
+  { this->add(Output_reloc_type(gsym, type, od, address, addend)); }
 
   // Add a reloc against a local symbol.
   void
   add_local(Sized_relobj<size, big_endian>* object,
            unsigned int local_sym_index, unsigned int type,
-           Address address, Addend addend)
+           Output_data* od, Address address, Addend addend)
   {
-    this->add(Output_reloc_type(object, local_sym_index, type, address,
+    this->add(Output_reloc_type(object, local_sym_index, type, od, address,
                                addend));
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
   void
-  add_output_section(Output_section* os, unsigned int type, Address address,
-                    Addend addend)
-  { this->add(Output_reloc_type(os, type, address, addend)); }
+  add_output_section(Output_section* os, unsigned int type, Output_data* od,
+                    Address address, Addend addend)
+  { this->add(Output_reloc_type(os, type, od, address, addend)); }
 };
 
 // Output_data_got is used to manage a GOT.  Each entry in the GOT is
@@ -631,9 +714,9 @@ class Output_data_got : public Output_section_data
  public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
 
-  Output_data_got()
+  Output_data_got(const General_options* options)
     : Output_section_data(Output_data::default_alignment(size)),
-      entries_()
+      options_(options), entries_()
   { }
 
   // Add an entry for a global symbol to the GOT.  Return true if this
@@ -676,7 +759,7 @@ class Output_data_got : public Output_section_data
     { this->u_.constant = 0; }
 
     // Create a global symbol entry.
-    Got_entry(Symbol* gsym)
+    explicit Got_entry(Symbol* gsym)
       : local_sym_index_(GSYM_CODE)
     { this->u_.gsym = gsym; }
 
@@ -684,20 +767,20 @@ class Output_data_got : public Output_section_data
     Got_entry(Object* object, unsigned int local_sym_index)
       : local_sym_index_(local_sym_index)
     {
-      assert(local_sym_index != GSYM_CODE
-            && local_sym_index != CONSTANT_CODE);
+      gold_assert(local_sym_index != GSYM_CODE
+                 && local_sym_index != CONSTANT_CODE);
       this->u_.object = object;
     }
 
     // Create a constant entry.  The constant is a host value--it will
     // be swapped, if necessary, when it is written out.
-    Got_entry(Valtype constant)
+    explicit Got_entry(Valtype constant)
       : local_sym_index_(CONSTANT_CODE)
     { this->u_.constant = constant; }
 
     // Write the GOT entry to an output view.
     void
-    write(unsigned char* pov) const;
+    write(const General_options*, unsigned char* pov) const;
 
    private:
     enum
@@ -737,10 +820,142 @@ class Output_data_got : public Output_section_data
   set_got_size()
   { this->set_data_size(this->got_offset(this->entries_.size())); }
 
+  // Options.
+  const General_options* options_;
   // The list of GOT entries.
   Got_entries entries_;
 };
 
+// Output_data_dynamic is used to hold the data in SHT_DYNAMIC
+// section.
+
+class Output_data_dynamic : public Output_section_data
+{
+ public:
+  Output_data_dynamic(const Target* target, Stringpool* pool)
+    : Output_section_data(Output_data::default_alignment(target->get_size())),
+      target_(target), entries_(), pool_(pool)
+  { }
+
+  // Add a new dynamic entry with a fixed numeric value.
+  void
+  add_constant(elfcpp::DT tag, unsigned int val)
+  { this->add_entry(Dynamic_entry(tag, val)); }
+
+  // Add a new dynamic entry with the address of a section.
+  void
+  add_section_address(elfcpp::DT tag, Output_section* os)
+  { this->add_entry(Dynamic_entry(tag, os, false)); }
+
+  // Add a new dynamic entry with the size of a section.
+  void
+  add_section_size(elfcpp::DT tag, Output_section* os)
+  { this->add_entry(Dynamic_entry(tag, os, true)); }
+
+  // Add a new dynamic entry with the address of a symbol.
+  void
+  add_symbol(elfcpp::DT tag, Symbol* sym)
+  { this->add_entry(Dynamic_entry(tag, sym)); }
+
+  // Add a new dynamic entry with a string.
+  void
+  add_string(elfcpp::DT tag, const char* str)
+  { this->add_entry(Dynamic_entry(tag, this->pool_->add(str, NULL))); }
+
+  // Set the final data size.
+  void
+  do_set_address(uint64_t, off_t);
+
+  // Write out the dynamic entries.
+  void
+  do_write(Output_file*);
+
+ private:
+  // This POD class holds a single dynamic entry.
+  class Dynamic_entry
+  {
+   public:
+    // Create an entry with a fixed numeric value.
+    Dynamic_entry(elfcpp::DT tag, unsigned int val)
+      : tag_(tag), classification_(DYNAMIC_NUMBER)
+    { this->u_.val = val; }
+
+    // Create an entry with the size or address of a section.
+    Dynamic_entry(elfcpp::DT tag, Output_section* os, bool section_size)
+      : tag_(tag),
+       classification_(section_size
+                       ? DYNAMIC_SECTION_SIZE
+                       : DYNAMIC_SECTION_ADDRESS)
+    { this->u_.os = os; }
+
+    // Create an entry with the address of a symbol.
+    Dynamic_entry(elfcpp::DT tag, Symbol* sym)
+      : tag_(tag), classification_(DYNAMIC_SYMBOL)
+    { this->u_.sym = sym; }
+
+    // Create an entry with a string.
+    Dynamic_entry(elfcpp::DT tag, const char* str)
+      : tag_(tag), classification_(DYNAMIC_STRING)
+    { this->u_.str = str; }
+
+    // Write the dynamic entry to an output view.
+    template<int size, bool big_endian>
+    void
+    write(unsigned char* pov, const Stringpool*) const;
+
+   private:
+    enum Classification
+    {
+      // Number.
+      DYNAMIC_NUMBER,
+      // Section address.
+      DYNAMIC_SECTION_ADDRESS,
+      // Section size.
+      DYNAMIC_SECTION_SIZE,
+      // Symbol adress.
+      DYNAMIC_SYMBOL,
+      // String.
+      DYNAMIC_STRING
+    };
+
+    union
+    {
+      // For DYNAMIC_NUMBER.
+      unsigned int val;
+      // For DYNAMIC_SECTION_ADDRESS and DYNAMIC_SECTION_SIZE.
+      Output_section* os;
+      // For DYNAMIC_SYMBOL.
+      Symbol* sym;
+      // For DYNAMIC_STRING.
+      const char* str;
+    } u_;
+    // The dynamic tag.
+    elfcpp::DT tag_;
+    // The type of entry.
+    Classification classification_;
+  };
+
+  // Add an entry to the list.
+  void
+  add_entry(const Dynamic_entry& entry)
+  { this->entries_.push_back(entry); }
+
+  // Sized version of write function.
+  template<int size, bool big_endian>
+  void
+  sized_write(Output_file* of);
+
+  // The type of the list of entries.
+  typedef std::vector<Dynamic_entry> Dynamic_entries;
+
+  // The target.
+  const Target* target_;
+  // The entries.
+  Dynamic_entries entries_;
+  // The pool used for strings.
+  Stringpool* pool_;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -788,6 +1003,11 @@ class Output_section : public Output_data
   do_set_out_shndx(unsigned int shndx)
   { this->out_shndx_ = shndx; }
 
+  // Return the entsize field.
+  uint64_t
+  entsize() const
+  { return this->entsize_; }
+
   // Set the entsize field.
   void
   set_entsize(uint64_t v)
@@ -822,7 +1042,7 @@ class Output_section : public Output_data
   unsigned int
   symtab_index() const
   {
-    assert(this->symtab_index_ != 0);
+    gold_assert(this->symtab_index_ != 0);
     return this->symtab_index_;
   }
 
@@ -830,7 +1050,7 @@ class Output_section : public Output_data
   void
   set_symtab_index(unsigned int index)
   {
-    assert(index != 0);
+    gold_assert(index != 0);
     this->symtab_index_ = index;
   }
 
@@ -848,7 +1068,7 @@ class Output_section : public Output_data
   unsigned int
   dynsym_index() const
   {
-    assert(this->dynsym_index_ != 0);
+    gold_assert(this->dynsym_index_ != 0);
     return this->dynsym_index_;
   }
 
@@ -856,7 +1076,7 @@ class Output_section : public Output_data
   void
   set_dynsym_index(unsigned int index)
   {
-    assert(index != 0);
+    gold_assert(index != 0);
     this->dynsym_index_ = index;
   }
 
@@ -871,7 +1091,7 @@ class Output_section : public Output_data
   // does nothing: the data is written out by calling Object::Relocate
   // on each input object.  But if there are any Output_section_data
   // objects we do need to write them out here.
-  virtual void
+  void
   do_write(Output_file*);
 
   // Return the address alignment--function required by parent class.
@@ -923,7 +1143,7 @@ class Output_section : public Output_data
        p2align_(ffsll(static_cast<long long>(addralign))),
        data_size_(data_size)
     {
-      assert(shndx != -1U);
+      gold_assert(shndx != -1U);
       this->u_.object = object;
     }
 
@@ -936,7 +1156,11 @@ class Output_section : public Output_data
     // The required alignment.
     uint64_t
     addralign() const
-    { return static_cast<uint64_t>(1) << this->p2align_; }
+    {
+      return (this->p2align_ == 0
+             ? 0
+             : static_cast<uint64_t>(1) << (this->p2align_ - 1));
+    }
 
     // Return the required size.
     off_t
@@ -1024,57 +1248,6 @@ class Output_section : public Output_data
   bool needs_dynsym_index_ : 1;
 };
 
-// A special Output_section which represents the symbol table
-// (SHT_SYMTAB).  The actual data is written out by
-// Symbol_table::write_globals.
-
-class Output_section_symtab : public Output_section
-{
- public:
-  Output_section_symtab(const char* name, off_t data_size)
-    : Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
-  { this->set_data_size(data_size); }
-
-  // The data is written out by Symbol_table::write_globals.  We don't
-  // do anything here.
-  void
-  do_write(Output_file*)
-  { }
-};
-
-// A special Output_section which represents the dynamic symbol table
-// (SHT_DYNSYM).  The actual data is written out by
-// Symbol_table::write_globals.
-
-class Output_section_dynsym : public Output_section
-{
- public:
-  Output_section_dynsym(const char* name, off_t data_size)
-    : Output_section(name, elfcpp::SHT_DYNSYM, 0, false)
-  { this->set_data_size(data_size); }
-
-  // The data is written out by Symbol_table::write_globals.  We don't
-  // do anything here.
-  void
-  do_write(Output_file*)
-  { }
-};
-
-// A special Output_section which holds a string table.
-
-class Output_section_strtab : public Output_section
-{
- public:
-  Output_section_strtab(const char* name, Stringpool* contents);
-
-  // Write out the data.
-  void
-  do_write(Output_file*);
-
- private:
-  Stringpool* contents_;
-};
-
 // An output segment.  PT_LOAD segments are built from collections of
 // output sections.  Other segments typically point within PT_LOAD
 // segments, and are built directly as needed.
@@ -1247,7 +1420,7 @@ class Output_file
   unsigned char*
   get_output_view(off_t start, off_t size)
   {
-    assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
+    gold_assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
     return this->base_ + start;
   }
 
index b5725e5..5663031 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-11-15 16:35-0800\n"
+"POT-Creation-Date: 2006-11-29 09:53-0800\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -56,331 +56,331 @@ msgstr ""
 msgid "%s: %s: member at %ld is not an ELF object"
 msgstr ""
 
-#: dirsearch.cc:51
+#: dirsearch.cc:50
 #, c-format
 msgid "can not read directory %s"
 msgstr ""
 
-#: dynobj.cc:97
+#: dynobj.cc:109
 #, c-format
 msgid "%s: %s: unexpected duplicate type %u section: %u, %u\n"
 msgstr ""
 
-#: dynobj.cc:138
+#: dynobj.cc:150
 #, c-format
 msgid "%s: %s: unexpected link in section %u header: %u != %u\n"
 msgstr ""
 
-#: dynobj.cc:176
+#: dynobj.cc:188
 #, c-format
 msgid "%s: %s: DYNAMIC section %u link out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:186
+#: dynobj.cc:198
 #, c-format
 msgid "%s: %s: DYNAMIC section %u link %u is not a strtab\n"
 msgstr ""
 
-#: dynobj.cc:208
+#: dynobj.cc:220
 #, c-format
 msgid "%s: %s: DT_SONAME value out of range: %lld >= %lld\n"
 msgstr ""
 
-#: dynobj.cc:225
+#: dynobj.cc:237
 #, c-format
 msgid "%s: %s: missing DT_NULL in dynamic segment\n"
 msgstr ""
 
-#: dynobj.cc:273
+#: dynobj.cc:285
 #, c-format
 msgid "%s: %s: invalid dynamic symbol table name index: %u\n"
 msgstr ""
 
-#: dynobj.cc:281
+#: dynobj.cc:293
 #, c-format
 msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: dynobj.cc:356 object.cc:422
+#: dynobj.cc:368 object.cc:421
 #, c-format
 msgid "%s: %s: bad section name offset for section %u: %lu\n"
 msgstr ""
 
-#: dynobj.cc:386
+#: dynobj.cc:398
 #, c-format
 msgid "%s: %s: duplicate definition for version %u\n"
 msgstr ""
 
-#: dynobj.cc:430 dynobj.cc:549
+#: dynobj.cc:442 dynobj.cc:561
 #, c-format
 msgid "%s: %s: verdef vd_next field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:454
+#: dynobj.cc:466
 #, c-format
 msgid "%s: %s: verneed vn_aux field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:473
+#: dynobj.cc:485
 #, c-format
 msgid "%s: %s: verneed vna_next field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:486
+#: dynobj.cc:498
 #, c-format
 msgid "%s: %s: verneed vn_next field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:516
+#: dynobj.cc:528
 #, c-format
 msgid "%s: %s: verdef vd_cnt field too small: %u\n"
 msgstr ""
 
-#: dynobj.cc:525
+#: dynobj.cc:537
 #, c-format
 msgid "%s: %s: verdef vd_aux field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:537
+#: dynobj.cc:549
 #, c-format
 msgid "%s: %s: verdaux vda_name field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:579
+#: dynobj.cc:591
 #, c-format
 msgid "%s: %s: vernaux vna_name field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:615
+#: dynobj.cc:628
 #, c-format
 msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: fileread.cc:56
+#: fileread.cc:55
 #, c-format
 msgid "%s: warning: close(%s) failed: %s"
 msgstr ""
 
-#: fileread.cc:129
+#: fileread.cc:128
 #, c-format
 msgid "%s: %s: lseek to %lld failed: %s"
 msgstr ""
 
-#: fileread.cc:139
+#: fileread.cc:138
 #, c-format
 msgid "%s: %s: read failed: %s\n"
 msgstr ""
 
-#: fileread.cc:149 fileread.cc:232
+#: fileread.cc:148 fileread.cc:231
 #, c-format
 msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n"
 msgstr ""
 
-#: fileread.cc:327
+#: fileread.cc:326
 #, c-format
 msgid "%s: cannot find %s\n"
 msgstr ""
 
-#: fileread.cc:335
+#: fileread.cc:334
 #, c-format
 msgid "%s: cannot open %s: %s\n"
 msgstr ""
 
-#: gold.cc:102
+#: gold.cc:106
 msgid "no input files"
 msgstr ""
 
-#: gold-threads.cc:48
+#: gold-threads.cc:46
 msgid "pthead_mutextattr_init failed"
 msgstr ""
 
-#: gold-threads.cc:51
+#: gold-threads.cc:49
 msgid "pthread_mutextattr_settype failed"
 msgstr ""
 
-#: gold-threads.cc:55
+#: gold-threads.cc:53
 msgid "pthread_mutex_init failed"
 msgstr ""
 
-#: gold-threads.cc:58
+#: gold-threads.cc:56
 msgid "pthread_mutexattr_destroy failed"
 msgstr ""
 
-#: gold-threads.cc:64
+#: gold-threads.cc:62
 msgid "pthread_mutex_destroy failed"
 msgstr ""
 
-#: gold-threads.cc:71
+#: gold-threads.cc:69
 msgid "pthread_mutex_lock failed"
 msgstr ""
 
-#: gold-threads.cc:78
+#: gold-threads.cc:76
 msgid "pthread_mutex_unlock failed"
 msgstr ""
 
-#: gold-threads.cc:159
+#: gold-threads.cc:157
 msgid "pthread_cond_init failed"
 msgstr ""
 
-#: gold-threads.cc:165
+#: gold-threads.cc:163
 msgid "pthread_cond_destroy failed"
 msgstr ""
 
-#: gold-threads.cc:172
+#: gold-threads.cc:170
 msgid "pthread_cond_wait failed"
 msgstr ""
 
-#: gold-threads.cc:179
+#: gold-threads.cc:177
 msgid "pthread_cond_signal failed"
 msgstr ""
 
 #. FIXME: This needs to specify the location somehow.
-#: i386.cc:88
+#: i386.cc:93
 #, c-format
 msgid "%s: missing expected TLS relocation\n"
 msgstr ""
 
-#: i386.cc:307 i386.cc:430 i386.cc:623
+#: i386.cc:617 i386.cc:757 i386.cc:961
 #, c-format
 msgid "%s: %s: unexpected reloc %u in object file\n"
 msgstr ""
 
-#: i386.cc:340 i386.cc:359
+#: i386.cc:653 i386.cc:672
 #, c-format
 msgid "%s: %s: unsupported reloc %u against local symbol\n"
 msgstr ""
 
-#: i386.cc:411 i386.cc:465 i386.cc:483
+#: i386.cc:793 i386.cc:814
 #, c-format
 msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
 msgstr ""
 
-#: i386.cc:505
+#: i386.cc:837
 #, c-format
 msgid "%s: %s: unsupported RELA reloc section\n"
 msgstr ""
 
-#: i386.cc:544
+#: i386.cc:877
 #, c-format
 msgid "%s: %s: missing expected TLS relocation\n"
 msgstr ""
 
-#: i386.cc:590 i386.cc:655 i386.cc:728 i386.cc:739
+#: i386.cc:993 i386.cc:1068 i386.cc:1079
 #, c-format
 msgid "%s: %s: unsupported reloc %u\n"
 msgstr ""
 
-#: i386.cc:682
+#: i386.cc:1020
 #, c-format
 msgid "%s: %s: TLS reloc but no TLS segment\n"
 msgstr ""
 
-#: i386.cc:713
+#: i386.cc:1053
 #, c-format
 msgid "%s: %s: unsupported reloc type %u\n"
 msgstr ""
 
-#: i386.cc:922
+#: i386.cc:1262
 #, c-format
 msgid "%s: %s: TLS relocation out of range\n"
 msgstr ""
 
-#: i386.cc:940
+#: i386.cc:1280
 #, c-format
 msgid "%s: %s: TLS relocation against invalid instruction\n"
 msgstr ""
 
-#: object.cc:31
+#: object.cc:30
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:87
+#: object.cc:86
 #, c-format
 msgid "%s: %s: section name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:230
+#: object.cc:229
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:238
+#: object.cc:237
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:294
+#: object.cc:293
 #, c-format
 msgid "%s: %s: section group %u info %u out of range\n"
 msgstr ""
 
-#: object.cc:311
+#: object.cc:310
 #, c-format
 msgid "%s: %s: symbol %u name offset %u out of range\n"
 msgstr ""
 
-#: object.cc:345
+#: object.cc:344
 #, c-format
 msgid "%s: %s: section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:489
+#: object.cc:488
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: object.cc:576
+#: object.cc:575
 #, c-format
 msgid "%s: %s: unknown section index %u for local symbol %u\n"
 msgstr ""
 
-#: object.cc:587
+#: object.cc:586
 #, c-format
 msgid "%s: %s: local symbol %u section index %u out of range\n"
 msgstr ""
 
-#: object.cc:616
+#: object.cc:615
 #, c-format
 msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
 msgstr ""
 
-#: object.cc:800
+#: object.cc:799
 #, c-format
 msgid "%s: %s: unsupported ELF file type %d\n"
 msgstr ""
 
-#: object.cc:819 object.cc:872 object.cc:893
+#: object.cc:818 object.cc:871 object.cc:892
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:828
+#: object.cc:827
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:831
+#: object.cc:830
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:839
+#: object.cc:838
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:846
+#: object.cc:845
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:854
+#: object.cc:853
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:861
+#: object.cc:860
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
@@ -486,7 +486,7 @@ msgstr ""
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:565 script.cc:1128
+#: options.cc:565 script.cc:1133
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
@@ -496,37 +496,37 @@ msgstr ""
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: output.cc:656
+#: output.cc:809
 #, c-format
 msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
 msgstr ""
 
-#: output.cc:1171
+#: output.cc:1308
 #, c-format
 msgid "%s: %s: open: %s\n"
 msgstr ""
 
-#: output.cc:1180
+#: output.cc:1317
 #, c-format
 msgid "%s: %s: lseek: %s\n"
 msgstr ""
 
-#: output.cc:1187
+#: output.cc:1324
 #, c-format
 msgid "%s: %s: write: %s\n"
 msgstr ""
 
-#: output.cc:1197
+#: output.cc:1334
 #, c-format
 msgid "%s: %s: mmap: %s\n"
 msgstr ""
 
-#: output.cc:1211
+#: output.cc:1348
 #, c-format
 msgid "%s: %s: munmap: %s\n"
 msgstr ""
 
-#: output.cc:1219
+#: output.cc:1356
 #, c-format
 msgid "%s: %s: close: %s\n"
 msgstr ""
@@ -577,52 +577,52 @@ msgstr ""
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
 
-#: symtab.cc:446 symtab.cc:543
+#: symtab.cc:445 symtab.cc:542
 #, c-format
 msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
 msgstr ""
 
-#: symtab.cc:463
+#: symtab.cc:462
 #, c-format
 msgid "%s: %s: bad global symbol name offset %u at %lu\n"
 msgstr ""
 
-#: symtab.cc:550
+#: symtab.cc:549
 #, c-format
 msgid "%s: %s: too few symbol versions\n"
 msgstr ""
 
-#: symtab.cc:570
+#: symtab.cc:569
 #, c-format
 msgid "%s: %s: bad symbol name offset %u at %lu\n"
 msgstr ""
 
-#: symtab.cc:614
+#: symtab.cc:613
 #, c-format
 msgid "%s: %s: versym for symbol %zu out of range: %u\n"
 msgstr ""
 
-#: symtab.cc:622
+#: symtab.cc:621
 #, c-format
 msgid "%s: %s: versym for symbol %zu has no name: %u\n"
 msgstr ""
 
-#: symtab.cc:1019 symtab.cc:1158
+#: symtab.cc:1050 symtab.cc:1201
 #, c-format
 msgid "%s: %s: unsupported symbol section 0x%x\n"
 msgstr ""
 
-#: symtab.cc:1274
+#: symtab.cc:1364
 #, c-format
 msgid "%s: %s: warning: %s\n"
 msgstr ""
 
-#: target-reloc.h:163
+#: target-reloc.h:164
 #, c-format
 msgid "%s: %s: reloc has bad offset %zu\n"
 msgstr ""
 
-#: target-reloc.h:173
+#: target-reloc.h:174
 #, c-format
 msgid "%s: %s: undefined reference to '%s'\n"
 msgstr ""
index c301d16..2b200ba 100644 (file)
@@ -56,7 +56,7 @@ Read_symbols::run(Workqueue* workqueue)
 {
   if (this->input_argument_->is_group())
     {
-      assert(this->input_group_ == NULL);
+      gold_assert(this->input_group_ == NULL);
       this->do_group(workqueue);
       return;
     }
@@ -170,7 +170,7 @@ Read_symbols::do_group(Workqueue* workqueue)
        ++p)
     {
       const Input_argument* arg = &*p;
-      assert(arg->is_file());
+      gold_assert(arg->is_file());
 
       Task_token* next_blocker = new Task_token();
       next_blocker->add_blocker();
index ce6af0b..35f262e 100644 (file)
@@ -227,17 +227,17 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
     }
 
   // Read the local symbols.
-  assert(this->symtab_shndx_ != -1U);
+  gold_assert(this->symtab_shndx_ != -1U);
   if (this->symtab_shndx_ == 0 || this->local_symbol_count_ == 0)
     rd->local_symbols = NULL;
   else
     {
       typename This::Shdr symtabshdr(pshdrs
                                     + this->symtab_shndx_ * This::shdr_size);
-      assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+      gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
       const int sym_size = This::sym_size;
       const unsigned int loccount = this->local_symbol_count_;
-      assert(loccount == symtabshdr.get_sh_info());
+      gold_assert(loccount == symtabshdr.get_sh_info());
       off_t locsize = loccount * sym_size;
       rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
                                                 locsize);
@@ -266,8 +266,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
        p != rd->relocs.end();
        ++p)
     {
-      target->scan_relocs(options, symtab, layout, this, p->sh_type,
-                         p->contents->data(), p->reloc_count,
+      target->scan_relocs(options, symtab, layout, this, p->data_shndx,
+                         p->sh_type, p->contents->data(), p->reloc_count,
                          this->local_symbol_count_,
                          local_symbols,
                          this->symbols_);
@@ -357,8 +357,8 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
       if (sh_size == 0)
        continue;
 
-      assert(map_sections[i].offset >= 0
-            && map_sections[i].offset + sh_size <= os->data_size());
+      gold_assert(map_sections[i].offset >= 0
+                 && map_sections[i].offset + sh_size <= os->data_size());
 
       unsigned char* view = of->get_output_view(start, sh_size);
       this->read(shdr.get_sh_offset(), sh_size, view);
@@ -418,7 +418,7 @@ Sized_relobj<size, big_endian>::relocate_sections(
          continue;
        }
 
-      assert((*pviews)[index].view != NULL);
+      gold_assert((*pviews)[index].view != NULL);
 
       if (shdr.get_sh_link() != this->symtab_shndx_)
        {
@@ -471,6 +471,29 @@ Sized_relobj<size, big_endian>::relocate_sections(
     }
 }
 
+// Relocate_functions functions.
+
+// Return whether we need a COPY reloc for a relocation against GSYM.
+// The relocation is being applied to section SHNDX in OBJECT.
+
+template<int size, bool big_endian>
+bool
+Relocate_functions<size, big_endian>::need_copy_reloc(
+    const General_options*,
+    Relobj* object,
+    unsigned int shndx,
+    Symbol*)
+{
+  // FIXME: Handle -z nocopyrelocs.
+
+  // If this is a readonly section, then we need a COPY reloc.
+  // Otherwise we can use a dynamic reloc.
+  if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0)
+    return true;
+
+  return false;
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones for implemented targets.
 
@@ -546,5 +569,28 @@ Sized_relobj<64, true>::do_relocate(const General_options& options,
                                    const Layout* layout,
                                    Output_file* of);
 
+template
+bool
+Relocate_functions<32, false>::need_copy_reloc(const General_options*,
+                                              Relobj*, unsigned int,
+                                              Symbol*);
+
+template
+bool
+Relocate_functions<32, true>::need_copy_reloc(const General_options*,
+                                             Relobj*, unsigned int,
+                                             Symbol*);
+
+template
+bool
+Relocate_functions<64, false>::need_copy_reloc(const General_options*,
+                                              Relobj*, unsigned int,
+                                              Symbol*);
+
+template
+bool
+Relocate_functions<64, true>::need_copy_reloc(const General_options*,
+                                             Relobj*, unsigned int,
+                                             Symbol*);
 
 } // End namespace gold.
index 9b0518e..7829440 100644 (file)
 namespace gold
 {
 
+class General_options;
 class Relobj;
 class Read_relocs_data;
 class Stringpool;
+class Symbol;
 class Layout;
 
 // A class to read the relocations for an object file, and then queue
@@ -227,6 +229,12 @@ public:
   {
     This::template pcrel<64>(view, value, address);
   }
+
+  // Return whether we need a COPY reloc for a reloc against GSYM,
+  // which is being applied to section SHNDX in OBJECT.
+  static bool
+  need_copy_reloc(const General_options*, Relobj* object, unsigned int shndx,
+                 Symbol* gsym);
 };
 
 } // End namespace gold.
index 2b6d65c..891de8c 100644 (file)
@@ -19,7 +19,7 @@ void
 Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
                      Object* object)
 {
-  assert(this->source_ == FROM_OBJECT);
+  gold_assert(this->source_ == FROM_OBJECT);
   this->u_.from_object.object = object;
   // FIXME: Handle SHN_XINDEX.
   this->u_.from_object.shnum = sym.get_st_shndx();
@@ -98,12 +98,12 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case elfcpp::STB_LOCAL:
       // We should only see externally visible symbols in the symbol
       // table.
-      abort();
+      gold_unreachable();
 
     default:
       // Any target which wants to handle STB_LOOS, etc., needs to
       // define a resolve method.
-      abort();
+      gold_unreachable();
     }
 
   if (to->source() == Symbol::FROM_OBJECT
@@ -507,7 +507,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       return;
 
     default:
-      abort();
+      gold_unreachable();
     }
 }
 
index b22611f..f5584d9 100644 (file)
@@ -4,7 +4,6 @@
 
 #include <string>
 #include <vector>
-#include <cassert>
 #include <cstdio>
 #include <cstdlib>
 
@@ -50,14 +49,20 @@ class Token
   Token(Classification classification, int lineno, int charpos)
     : classification_(classification), value_(), opcode_(0),
       lineno_(lineno), charpos_(charpos)
-  { assert(classification == TOKEN_INVALID || classification == TOKEN_EOF); }
+  {
+    gold_assert(classification == TOKEN_INVALID
+               || classification == TOKEN_EOF);
+  }
 
   // A general token with a value.
   Token(Classification classification, const std::string& value,
        int lineno, int charpos)
     : classification_(classification), value_(value), opcode_(0),
       lineno_(lineno), charpos_(charpos)
-  { assert(classification != TOKEN_INVALID && classification != TOKEN_EOF); }
+  {
+    gold_assert(classification != TOKEN_INVALID
+               && classification != TOKEN_EOF);
+  }
 
   // A token representing a string of characters.
   Token(const std::string& s, int lineno, int charpos)
@@ -101,21 +106,21 @@ class Token
   const std::string&
   string_value() const
   {
-    assert(this->classification_ == TOKEN_STRING);
+    gold_assert(this->classification_ == TOKEN_STRING);
     return this->value_;
   }
 
   int
   operator_value() const
   {
-    assert(this->classification_ == TOKEN_OPERATOR);
+    gold_assert(this->classification_ == TOKEN_OPERATOR);
     return this->opcode_;
   }
 
   int64_t
   integer_value() const
   {
-    assert(this->classification_ == TOKEN_INTEGER);
+    gold_assert(this->classification_ == TOKEN_INTEGER);
     return strtoll(this->value_.c_str(), NULL, 0);
   }
 
@@ -1097,7 +1102,7 @@ yylex(YYSTYPE* lvalp, void* closurev)
     default:
     case Token::TOKEN_INVALID:
     case Token::TOKEN_EOF:
-      abort();
+      gold_unreachable();
 
     case Token::TOKEN_STRING:
       {
index 5b60259..d53cf77 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "gold.h"
 
-#include <cassert>
 #include <cstring>
 #include <algorithm>
 #include <vector>
@@ -60,12 +59,15 @@ Stringpool::Stringpool_hash::operator()(const char* s) const
 const char*
 Stringpool::add_string(const char* s, Key* pkey)
 {
+  // We are in trouble if we've already computed the string offsets.
+  gold_assert(this->strtab_size_ == 0);
+
   // The size we allocate for a new Stringdata.
   const size_t buffer_size = 1000;
   // The amount we multiply the Stringdata index when calculating the
   // key.
   const size_t key_mult = 1024;
-  assert(key_mult >= buffer_size);
+  gold_assert(key_mult >= buffer_size);
 
   size_t len = strlen(s);
 
@@ -141,7 +143,7 @@ Stringpool::add(const char* s, Key* pkey)
   std::pair<const char*, Val> element(ret, std::make_pair(k, ozero));
   std::pair<String_set_type::iterator, bool> ins =
     this->string_set_.insert(element);
-  assert(ins.second);
+  gold_assert(ins.second);
 
   if (pkey != NULL)
     *pkey = k;
@@ -222,6 +224,12 @@ Stringpool::is_suffix(const char* s1, const char* s2)
 void
 Stringpool::set_string_offsets()
 {
+  if (this->strtab_size_ != 0)
+    {
+      // We've already computed the offsets.
+      return;
+    }
+
   size_t count = this->string_set_.size();
 
   std::vector<String_set_type::iterator> v;
@@ -260,10 +268,11 @@ Stringpool::set_string_offsets()
 off_t
 Stringpool::get_offset(const char* s) const
 {
+  gold_assert(this->strtab_size_ != 0);
   String_set_type::const_iterator p = this->string_set_.find(s);
   if (p != this->string_set_.end())
     return p->second.second;
-  abort();
+  gold_unreachable();
 }
 
 // Write the ELF strtab into the output file at the specified offset.
@@ -271,6 +280,7 @@ Stringpool::get_offset(const char* s) const
 void
 Stringpool::write(Output_file* of, off_t offset)
 {
+  gold_assert(this->strtab_size_ != 0);
   unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
   char* view = reinterpret_cast<char*>(viewu);
   view[0] = '\0';
index ed549b4..05c498e 100644 (file)
@@ -63,7 +63,10 @@ class Stringpool
   // Get the size of the ELF strtab.
   off_t
   get_strtab_size() const
-  { return this->strtab_size_; }
+  {
+    gold_assert(this->strtab_size_ != 0);
+    return this->strtab_size_;
+  }
 
   // Write the strtab into the output file at the specified offset.
   void
index 92d5583..4d2bb1a 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "gold.h"
 
-#include <cassert>
 #include <stdint.h>
 #include <string>
 #include <utility>
@@ -198,8 +197,8 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
 void
 Symbol_table::make_forwarder(Symbol* from, Symbol* to)
 {
-  assert(from != to);
-  assert(!from->is_forwarder() && !to->is_forwarder());
+  gold_assert(from != to);
+  gold_assert(!from->is_forwarder() && !to->is_forwarder());
   this->forwarders_[from] = to;
   from->set_forwarder();
 }
@@ -209,10 +208,10 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
 Symbol*
 Symbol_table::resolve_forwards(const Symbol* from) const
 {
-  assert(from->is_forwarder());
+  gold_assert(from->is_forwarder());
   Unordered_map<const Symbol*, Symbol*>::const_iterator p =
     this->forwarders_.find(from);
-  assert(p != this->forwarders_.end());
+  gold_assert(p != this->forwarders_.end());
   return p->second;
 }
 
@@ -324,7 +323,7 @@ Symbol_table::add_from_object(Object* object,
       // We already have an entry for NAME/VERSION.
       ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (ins.first->second
                                                            SELECT_SIZE(size));
-      assert(ret != NULL);
+      gold_assert(ret != NULL);
 
       was_undefined = ret->is_undefined();
       was_common = ret->is_common();
@@ -357,7 +356,7 @@ Symbol_table::add_from_object(Object* object,
   else
     {
       // This is the first time we have seen NAME/VERSION.
-      assert(ins.first->second == NULL);
+      gold_assert(ins.first->second == NULL);
 
       was_undefined = false;
       was_common = false;
@@ -406,7 +405,7 @@ Symbol_table::add_from_object(Object* object,
            {
              // This is the first time we have seen NAME/NULL.  Point
              // it at the new entry for NAME/VERSION.
-             assert(insdef.second);
+             gold_assert(insdef.second);
              insdef.first->second = ret;
            }
        }
@@ -654,7 +653,7 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
                                    bool only_if_ref
                                     ACCEPT_SIZE_ENDIAN)
 {
-  assert(this->size_ == size);
+  gold_assert(this->size_ == size);
 
   Symbol* oldsym;
   Sized_symbol<size>* sym;
@@ -685,20 +684,20 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
        {
          // We already have a symbol table entry for NAME.
          oldsym = ins.first->second;
-         assert(oldsym != NULL);
+         gold_assert(oldsym != NULL);
          sym = NULL;
        }
       else
        {
          // We haven't seen this symbol before.
-         assert(ins.first->second == NULL);
+         gold_assert(ins.first->second == NULL);
 
          if (!target->has_make_symbol())
            sym = new Sized_symbol<size>();
          else
            {
-             assert(target->get_size() == size);
-             assert(target->is_big_endian() ? big_endian : !big_endian);
+             gold_assert(target->get_size() == size);
+             gold_assert(target->is_big_endian() ? big_endian : !big_endian);
              typedef Sized_target<size, big_endian> My_target;
              My_target* sized_target = static_cast<My_target*>(target);
              sym = sized_target->make_symbol();
@@ -713,11 +712,11 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
 
   if (oldsym != NULL)
     {
-      assert(sym == NULL);
+      gold_assert(sym == NULL);
 
       sym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
                                                            SELECT_SIZE(size));
-      assert(sym->source() == Symbol::FROM_OBJECT);
+      gold_assert(sym->source() == Symbol::FROM_OBJECT);
       const int old_shnum = sym->shnum();
       if (old_shnum != elfcpp::SHN_UNDEF
          && old_shnum != elfcpp::SHN_COMMON
@@ -748,7 +747,7 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
                                    bool offset_is_from_end,
                                    bool only_if_ref)
 {
-  assert(target->get_size() == this->size_);
+  gold_assert(target->get_size() == this->size_);
   if (this->size_ == 32)
     this->do_define_in_output_data<32>(target, name, od, value, symsize,
                                       type, binding, visibility, nonvis,
@@ -758,7 +757,7 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
                                       type, binding, visibility, nonvis,
                                       offset_is_from_end, only_if_ref);
   else
-    abort();
+    gold_unreachable();
 }
 
 // Define a symbol in an Output_data, sized version.
@@ -808,7 +807,7 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
                                       Symbol::Segment_offset_base offset_base,
                                       bool only_if_ref)
 {
-  assert(target->get_size() == this->size_);
+  gold_assert(target->get_size() == this->size_);
   if (this->size_ == 32)
     this->do_define_in_output_segment<32>(target, name, os, value, symsize,
                                          type, binding, visibility, nonvis,
@@ -818,7 +817,7 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
                                          type, binding, visibility, nonvis,
                                          offset_base, only_if_ref);
   else
-    abort();
+    gold_unreachable();
 }
 
 // Define a symbol in an Output_segment, sized version.
@@ -866,7 +865,7 @@ Symbol_table::define_as_constant(Target* target, const char* name,
                                 elfcpp::STV visibility, unsigned char nonvis,
                                 bool only_if_ref)
 {
-  assert(target->get_size() == this->size_);
+  gold_assert(target->get_size() == this->size_);
   if (this->size_ == 32)
     this->do_define_as_constant<32>(target, name, value, symsize,
                                    type, binding, visibility, nonvis,
@@ -876,7 +875,7 @@ Symbol_table::define_as_constant(Target* target, const char* name,
                                    type, binding, visibility, nonvis,
                                    only_if_ref);
   else
-    abort();
+    gold_unreachable();
 }
 
 // Define a symbol as a constant, sized version.
@@ -955,6 +954,33 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
     }
 }
 
+// Set the dynamic symbol indexes.  INDEX is the index of the first
+// global dynamic symbol.  Pointers to the symbols are stored into the
+// vector SYMS.  The names are added to DYNPOOL.  This returns an
+// updated dynamic symbol index.
+
+unsigned int
+Symbol_table::set_dynsym_indexes(unsigned int index,
+                                std::vector<Symbol*>* syms,
+                                Stringpool* dynpool)
+{
+  for (Symbol_table_type::iterator p = this->table_.begin();
+       p != this->table_.end();
+       ++p)
+    {
+      Symbol* sym = p->second;
+      if (sym->needs_dynsym_entry())
+       {
+         sym->set_dynsym_index(index);
+         ++index;
+         syms->push_back(sym);
+         dynpool->add(sym->name(), NULL);
+       }
+    }
+
+  return index;
+}
+
 // Set the final values for all the symbols.  The index of the first
 // global symbol in the output file is INDEX.  Record the file offset
 // OFF.  Add their names to POOL.  Return the new file offset.
@@ -964,7 +990,7 @@ Symbol_table::finalize(unsigned int index, off_t off, Stringpool* pool)
 {
   off_t ret;
 
-  assert(index != 0);
+  gold_assert(index != 0);
   this->first_global_index_ = index;
 
   if (this->size_ == 32)
@@ -972,7 +998,7 @@ Symbol_table::finalize(unsigned int index, off_t off, Stringpool* pool)
   else if (this->size_ == 64)
     ret = this->sized_finalize<64>(index, off, pool);
   else
-    abort();
+    gold_unreachable();
 
   // Now that we have the final symbol table, we can reliably note
   // which symbols should get warnings.
@@ -1002,7 +1028,12 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
       Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
 
       // FIXME: Here we need to decide which symbols should go into
-      // the output file.
+      // the output file, based on --strip.
+
+      // The default version of a symbol may appear twice in the
+      // symbol table.  We only need to finalize it once.
+      if (sym->has_symtab_index())
+       continue;
 
       typename Sized_symbol<size>::Value_type value;
 
@@ -1072,7 +1103,7 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
                value += os->filesz();
                break;
              default:
-               abort();
+               gold_unreachable();
              }
          }
          break;
@@ -1082,7 +1113,7 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
          break;
 
        default:
-         abort();
+         gold_unreachable();
        }
 
       sym->set_value(value);
@@ -1118,7 +1149,7 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
        this->sized_write_globals<64, false>(target, sympool, of);
     }
   else
-    abort();
+    gold_unreachable();
 }
 
 // Write out the global symbols.
@@ -1141,8 +1172,20 @@ Symbol_table::sized_write_globals(const Target*,
     {
       Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
 
-      if (sym->symtab_index() == -1U)
-       continue;
+      unsigned int sym_index = sym->symtab_index();
+      if (sym_index == -1U)
+       {
+         // This symbol is not included in the output file.
+         continue;
+       }
+      if (sym_index != index)
+       {
+         // We have already seen this symbol, because it has a
+         // default version.
+         gold_assert(sym_index < index);
+         continue;
+       }
+      ++index;
 
       unsigned int shndx;
       switch (sym->source())
@@ -1173,7 +1216,7 @@ Symbol_table::sized_write_globals(const Target*,
                Relobj* relobj = static_cast<Relobj*>(symobj);
                off_t secoff;
                Output_section* os = relobj->output_section(shnum, &secoff);
-               assert(os != NULL);
+               gold_assert(os != NULL);
                shndx = os->out_shndx();
              }
          }
@@ -1192,12 +1235,9 @@ Symbol_table::sized_write_globals(const Target*,
          break;
 
        default:
-         abort();
+         gold_unreachable();
        }
 
-      assert(sym->symtab_index() == index);
-      ++index;
-
       elfcpp::Sym_write<size, big_endian> osym(ps);
       osym.put_st_name(sympool->get_offset(sym->name()));
       osym.put_st_value(sym->value());
@@ -1210,11 +1250,61 @@ Symbol_table::sized_write_globals(const Target*,
       ps += sym_size;
     }
 
-  assert(ps - psyms == oview_size);
+  gold_assert(ps - psyms == oview_size);
 
   of->write_output_view(this->offset_, oview_size, psyms);
 }
 
+// Write out a section symbol.  Return the update offset.
+
+void
+Symbol_table::write_section_symbol(const Target* target,
+                                  const Output_section *os,
+                                  Output_file* of,
+                                  off_t offset) const
+{
+  if (this->size_ == 32)
+    {
+      if (target->is_big_endian())
+       this->sized_write_section_symbol<32, true>(os, of, offset);
+      else
+       this->sized_write_section_symbol<32, false>(os, of, offset);
+    }
+  else if (this->size_ == 64)
+    {
+      if (target->is_big_endian())
+       this->sized_write_section_symbol<64, true>(os, of, offset);
+      else
+       this->sized_write_section_symbol<64, false>(os, of, offset);
+    }
+  else
+    gold_unreachable();
+}
+
+// Write out a section symbol, specialized for size and endianness.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_section_symbol(const Output_section* os,
+                                        Output_file* of,
+                                        off_t offset) const
+{
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+  unsigned char* pov = of->get_output_view(offset, sym_size);
+
+  elfcpp::Sym_write<size, big_endian> osym(pov);
+  osym.put_st_name(0);
+  osym.put_st_value(os->address());
+  osym.put_st_size(0);
+  osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL,
+                                      elfcpp::STT_SECTION));
+  osym.put_st_other(elfcpp::elf_st_other(elfcpp::STV_DEFAULT, 0));
+  osym.put_st_shndx(os->out_shndx());
+
+  of->write_output_view(offset, sym_size, pov);
+}
+
 // Warnings functions.
 
 // Add a new warning.
@@ -1268,9 +1358,9 @@ Warnings::note_warnings(Symbol_table* symtab)
 void
 Warnings::issue_warning(const Symbol* sym, const std::string& location) const
 {
-  assert(sym->has_warning());
+  gold_assert(sym->has_warning());
   Warning_table::const_iterator p = this->warnings_.find(sym->name());
-  assert(p != this->warnings_.end());
+  gold_assert(p != this->warnings_.end());
   fprintf(stderr, _("%s: %s: warning: %s\n"), program_name, location.c_str(),
          p->second.text.c_str());
 }
index 06a4b6b..1350bf1 100644 (file)
@@ -6,7 +6,6 @@
 #include <string>
 #include <utility>
 #include <vector>
-#include <cassert>
 
 #include "elfcpp.h"
 #include "stringpool.h"
@@ -26,6 +25,7 @@ class Dynobj;
 template<int size, bool big_endian>
 class Sized_dynobj;
 class Output_data;
+class Output_section;
 class Output_segment;
 class Output_file;
 class Target;
@@ -90,7 +90,7 @@ class Symbol
   Object*
   object() const
   {
-    assert(this->source_ == FROM_OBJECT);
+    gold_assert(this->source_ == FROM_OBJECT);
     return this->u_.from_object.object;
   }
 
@@ -99,7 +99,7 @@ class Symbol
   unsigned int
   shnum() const
   {
-    assert(this->source_ == FROM_OBJECT);
+    gold_assert(this->source_ == FROM_OBJECT);
     return this->u_.from_object.shnum;
   }
 
@@ -109,7 +109,7 @@ class Symbol
   Output_data*
   output_data() const
   {
-    assert(this->source_ == IN_OUTPUT_DATA);
+    gold_assert(this->source_ == IN_OUTPUT_DATA);
     return this->u_.in_output_data.output_data;
   }
 
@@ -118,7 +118,7 @@ class Symbol
   bool
   offset_is_from_end() const
   {
-    assert(this->source_ == IN_OUTPUT_DATA);
+    gold_assert(this->source_ == IN_OUTPUT_DATA);
     return this->u_.in_output_data.offset_is_from_end;
   }
 
@@ -128,7 +128,7 @@ class Symbol
   Output_segment*
   output_segment() const
   {
-    assert(this->source_ == IN_OUTPUT_SEGMENT);
+    gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
     return this->u_.in_output_segment.output_segment;
   }
 
@@ -137,7 +137,7 @@ class Symbol
   Segment_offset_base
   offset_base() const
   {
-    assert(this->source_ == IN_OUTPUT_SEGMENT);
+    gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
     return this->u_.in_output_segment.offset_base;
   }
 
@@ -184,11 +184,6 @@ class Symbol
   set_needs_dynsym_entry()
   { this->needs_dynsym_entry_ = true; }
 
-  // Return whether this symbol was ever seen in a dynamic object.
-  bool
-  in_dyn() const
-  { return this->in_dyn_; }
-
   // Mark this symbol as having been seen in a dynamic object.
   void
   set_in_dyn()
@@ -202,7 +197,7 @@ class Symbol
   unsigned int
   symtab_index() const
   {
-    assert(this->symtab_index_ != 0);
+    gold_assert(this->symtab_index_ != 0);
     return this->symtab_index_;
   }
 
@@ -210,10 +205,16 @@ class Symbol
   void
   set_symtab_index(unsigned int index)
   {
-    assert(index != 0);
+    gold_assert(index != 0);
     this->symtab_index_ = index;
   }
 
+  // Return whether this symbol already has an index in the output
+  // file symbol table.
+  bool
+  has_symtab_index() const
+  { return this->symtab_index_ != 0; }
+
   // Return the index of this symbol in the dynamic symbol table.  A
   // value of -1U means that this symbol is not going into the dynamic
   // symbol table.  This starts out as zero, and is set to a non-zero
@@ -222,7 +223,7 @@ class Symbol
   unsigned int
   dynsym_index() const
   {
-    assert(this->dynsym_index_ != 0);
+    gold_assert(this->dynsym_index_ != 0);
     return this->dynsym_index_;
   }
 
@@ -230,7 +231,7 @@ class Symbol
   void
   set_dynsym_index(unsigned int index)
   {
-    assert(index != 0);
+    gold_assert(index != 0);
     this->dynsym_index_ = index;
   }
 
@@ -243,7 +244,7 @@ class Symbol
   unsigned int
   got_offset() const
   {
-    assert(this->has_got_offset());
+    gold_assert(this->has_got_offset());
     return this->got_offset_;
   }
 
@@ -255,14 +256,36 @@ class Symbol
     this->got_offset_ = got_offset;
   }
 
-  // Return whether this symbol is resolved locally.  This is always
-  // true when linking statically.  It is true for a symbol defined in
-  // this object when using -Bsymbolic.  It is true for a symbol
-  // marked local in a version file.  FIXME: This needs to be
-  // completed.
+  // Return whether this symbol has an entry in the PLT section.
   bool
-  is_resolved_locally() const
-  { return !this->in_dyn_; }
+  has_plt_offset() const
+  { return this->has_plt_offset_; }
+
+  // Return the offset into the PLT section of this symbol.
+  unsigned int
+  plt_offset() const
+  {
+    gold_assert(this->has_plt_offset());
+    return this->plt_offset_;
+  }
+
+  // Set the PLT offset of this symbol.
+  void
+  set_plt_offset(unsigned int plt_offset)
+  {
+    this->has_plt_offset_ = true;
+    this->plt_offset_ = plt_offset;
+  }
+
+  // Return true if the final value of this symbol is known at link
+  // time.
+  bool
+  final_value_is_known(const General_options* options) const
+  {
+    if (options->is_shared())
+      return false;
+    return this->source_ != FROM_OBJECT || !this->object()->is_dynamic();
+  }
 
   // Return whether this is a defined symbol (not undefined or
   // common).
@@ -270,8 +293,17 @@ class Symbol
   is_defined() const
   {
     return (this->source_ != FROM_OBJECT
-           || (this->u_.from_object.shnum != elfcpp::SHN_UNDEF
-               && this->u_.from_object.shnum != elfcpp::SHN_COMMON));
+           || (this->shnum() != elfcpp::SHN_UNDEF
+               && this->shnum() != elfcpp::SHN_COMMON));
+  }
+
+  // Return whether this symbol is defined in a dynamic object.
+  bool
+  is_defined_in_dynobj() const
+  {
+    return (this->source_ == FROM_OBJECT
+           && this->object()->is_dynamic()
+           && this->is_defined());
   }
 
   // Return whether this is an undefined symbol.
@@ -286,7 +318,7 @@ class Symbol
   is_common() const
   {
     return (this->source_ == FROM_OBJECT
-           && (this->u_.from_object.shnum == elfcpp::SHN_COMMON
+           && (this->shnum() == elfcpp::SHN_COMMON
                || this->type_ == elfcpp::STT_COMMON));
   }
 
@@ -401,6 +433,11 @@ class Symbol
   // is true), this is the offset from the start of the GOT section.
   unsigned int got_offset_;
 
+  // If this symbol has an entry in the PLT section (has_plt_offset_
+  // is true), then this is the offset from the start of the PLT
+  // section.
+  unsigned int plt_offset_;
+
   // Symbol type.
   elfcpp::STT type_ : 4;
   // Symbol binding.
@@ -430,6 +467,8 @@ class Symbol
   bool in_dyn_ : 1;
   // True if the symbol has an entry in the GOT section.
   bool has_got_offset_ : 1;
+  // True if the symbol has an entry in the PLT section.
+  bool has_plt_offset_ : 1;
   // True if there is a warning for this symbol.
   bool has_warning_ : 1;
 };
@@ -735,7 +774,7 @@ class Symbol_table
   Symbol*
   resolve_forwards(const Symbol* from) const;
 
-  // Return the size of the symbols in the table.
+  // Return the bitsize (32 or 64) of the symbols in the table.
   int
   get_size() const
   { return this->size_; }
@@ -774,6 +813,14 @@ class Symbol_table
   issue_warning(const Symbol* sym, const std::string& location) const
   { this->warnings_.issue_warning(sym, location); }
 
+  // Set the dynamic symbol indexes.  INDEX is the index of the first
+  // global dynamic symbol.  Pointers to the symbols are stored into
+  // the vector.  The names are stored into the Stringpool.  This
+  // returns an updated dynamic symbol index.
+  unsigned int
+  set_dynsym_indexes(unsigned int index, std::vector<Symbol*>*,
+                    Stringpool*);
+
   // Finalize the symbol table after we have set the final addresses
   // of all the input sections.  This sets the final symbol indexes,
   // values and adds the names to *POOL.  INDEX is the index of the
@@ -786,11 +833,16 @@ class Symbol_table
   void
   write_globals(const Target*, const Stringpool*, Output_file*) const;
 
+  // Write out a section symbol.  Return the updated offset.
+  void
+  write_section_symbol(const Target*, const Output_section*, Output_file*,
+                      off_t) const;
+
  private:
   Symbol_table(const Symbol_table&);
   Symbol_table& operator=(const Symbol_table&);
 
-  // Set the size of the symbols in the table.
+  // Set the size (32 or 64) of the symbols in the table.
   void
   set_size(int size)
   { this->size_ = size; }
@@ -865,6 +917,11 @@ class Symbol_table
   void
   sized_write_globals(const Target*, const Stringpool*, Output_file*) const;
 
+  // Write out a section symbol, specialized for size and endianness.
+  template<int size, bool big_endian>
+  void
+  sized_write_section_symbol(const Output_section*, Output_file*, off_t) const;
+
   // The type of the symbol hash table.
 
   typedef std::pair<Stringpool::Key, Stringpool::Key> Symbol_table_key;
@@ -932,7 +989,7 @@ template<int size>
 Sized_symbol<size>*
 Symbol_table::get_sized_symbol(Symbol* sym ACCEPT_SIZE) const
 {
-  assert(size == this->get_size());
+  gold_assert(size == this->get_size());
   return static_cast<Sized_symbol<size>*>(sym);
 }
 
@@ -940,7 +997,7 @@ template<int size>
 const Sized_symbol<size>*
 Symbol_table::get_sized_symbol(const Symbol* sym ACCEPT_SIZE) const
 {
-  assert(size == this->get_size());
+  gold_assert(size == this->get_size());
   return static_cast<const Sized_symbol<size>*>(sym);
 }
 
index 5b057ac..727de02 100644 (file)
@@ -26,6 +26,7 @@ scan_relocs(
     Layout* layout,
     Target_type* target,
     Sized_relobj<size, big_endian>* object,
+    unsigned int data_shndx,
     const unsigned char* prelocs,
     size_t reloc_count,
     size_t local_count,
@@ -47,7 +48,7 @@ scan_relocs(
 
       if (r_sym < local_count)
        {
-         assert(plocal_syms != NULL);
+         gold_assert(plocal_syms != NULL);
          typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
                                                      + r_sym * sym_size);
          const unsigned int shndx = lsym.get_st_shndx();
@@ -73,18 +74,18 @@ scan_relocs(
              continue;
            }
 
-         scan.local(options, symtab, layout, target, object, reloc, r_type,
-                    lsym);
+         scan.local(options, symtab, layout, target, object, data_shndx,
+                    reloc, r_type, lsym);
        }
       else
        {
          Symbol* gsym = global_syms[r_sym - local_count];
-         assert(gsym != NULL);
+         gold_assert(gsym != NULL);
          if (gsym->is_forwarder())
            gsym = symtab->resolve_forwards(gsym);
 
-         scan.global(options, symtab, layout, target, object, reloc, r_type,
-                     gsym);
+         scan.global(options, symtab, layout, target, object, data_shndx,
+                     reloc, r_type, gsym);
        }
     }
 }
@@ -146,7 +147,7 @@ relocate_section(
       else
        {
          const Symbol* gsym = global_syms[r_sym - local_count];
-         assert(gsym != NULL);
+         gold_assert(gsym != NULL);
          if (gsym->is_forwarder())
            gsym = relinfo->symtab->resolve_forwards(gsym);
 
index 5a86c35..039b97d 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef GOLD_TARGET_H
 #define GOLD_TARGET_H
 
-#include <cassert>
-
 #include "elfcpp.h"
 
 namespace gold
@@ -137,7 +135,7 @@ class Sized_target : public Target
   // returns true.
   virtual Sized_symbol<size>*
   make_symbol()
-  { abort(); }
+  { gold_unreachable(); }
 
   // Resolve a symbol for the target.  This should be overridden by a
   // target which needs to take special action.  TO is the
@@ -145,12 +143,13 @@ class Sized_target : public Target
   // This will only be called if has_resolve() returns true.
   virtual void
   resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
-  { abort(); }
+  { gold_unreachable(); }
 
   // Scan the relocs for a section, and record any information
   // required for the symbol.  OPTIONS is the command line options.
   // SYMTAB is the symbol table.  OBJECT is the object in which the
-  // section appears.  SH_TYPE is the type of the relocation section,
+  // section appears.  DATA_SHNDX is the section index that these
+  // relocs apply to.  SH_TYPE is the type of the relocation section,
   // SHT_REL or SHT_RELA.  PRELOCS points to the relocation data.
   // RELOC_COUNT is the number of relocs.  LOCAL_SYMBOL_COUNT is the
   // number of local symbols.  PLOCAL_SYMBOLS points to the local
@@ -161,6 +160,7 @@ class Sized_target : public Target
              Symbol_table* symtab,
              Layout* layout,
              Sized_relobj<size, big_endian>* object,
+             unsigned int data_shndx,
              unsigned int sh_type,
              const unsigned char* prelocs,
              size_t reloc_count,
@@ -187,8 +187,8 @@ class Sized_target : public Target
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
   {
-    assert(pti->size == size);
-    assert(pti->is_big_endian ? big_endian : !big_endian);
+    gold_assert(pti->size == size);
+    gold_assert(pti->is_big_endian ? big_endian : !big_endian);
   }
 };
 
index 3ef3422..9062118 100644 (file)
@@ -2,8 +2,6 @@
 
 #include "gold.h"
 
-#include <cassert>
-
 #include "workqueue.h"
 
 namespace gold
@@ -18,59 +16,59 @@ Task_token::Task_token()
 
 Task_token::~Task_token()
 {
-  assert(this->readers_ == 0 && this->writer_ == NULL);
+  gold_assert(this->readers_ == 0 && this->writer_ == NULL);
 }
 
 bool
 Task_token::is_readable() const
 {
-  assert(!this->is_blocker_);
+  gold_assert(!this->is_blocker_);
   return this->writer_ == NULL;
 }
 
 void
 Task_token::add_reader()
 {
-  assert(!this->is_blocker_);
-  assert(this->is_readable());
+  gold_assert(!this->is_blocker_);
+  gold_assert(this->is_readable());
   ++this->readers_;
 }
 
 void
 Task_token::remove_reader()
 {
-  assert(!this->is_blocker_);
-  assert(this->readers_ > 0);
+  gold_assert(!this->is_blocker_);
+  gold_assert(this->readers_ > 0);
   --this->readers_;
 }
 
 bool
 Task_token::is_writable() const
 {
-  assert(!this->is_blocker_);
+  gold_assert(!this->is_blocker_);
   return this->writer_ == NULL && this->readers_ == 0;
 }
 
 void
 Task_token::add_writer(const Task* t)
 {
-  assert(!this->is_blocker_);
-  assert(this->is_writable());
+  gold_assert(!this->is_blocker_);
+  gold_assert(this->is_writable());
   this->writer_ = t;
 }
 
 void
 Task_token::remove_writer(const Task* t)
 {
-  assert(!this->is_blocker_);
-  assert(this->writer_ == t);
+  gold_assert(!this->is_blocker_);
+  gold_assert(this->writer_ == t);
   this->writer_ = NULL;
 }
 
 bool
 Task_token::has_write_lock(const Task* t)
 {
-  assert(!this->is_blocker_);
+  gold_assert(!this->is_blocker_);
   return this->writer_ == t;
 }
 
@@ -82,14 +80,14 @@ Task_token::add_blocker()
   if (this->readers_ == 0 && this->writer_ == NULL)
     this->is_blocker_ = true;
   else
-    assert(this->is_blocker_);
+    gold_assert(this->is_blocker_);
   ++this->readers_;
 }
 
 bool
 Task_token::remove_blocker()
 {
-  assert(this->is_blocker_ && this->readers_ > 0);
+  gold_assert(this->is_blocker_ && this->readers_ > 0);
   --this->readers_;
   return this->readers_ == 0;
 }
@@ -97,7 +95,8 @@ Task_token::remove_blocker()
 bool
 Task_token::is_blocked() const
 {
-  assert(this->is_blocker_ || (this->readers_ == 0 && this->writer_ == NULL));
+  gold_assert(this->is_blocker_
+             || (this->readers_ == 0 && this->writer_ == NULL));
   return this->readers_ > 0;
 }
 
@@ -109,7 +108,7 @@ Task_block_token::Task_block_token(Task_token& token, Workqueue* workqueue)
   // We must increment the block count when the task is created and
   // put on the queue.  This object is created when the task is run,
   // so we don't increment the block count here.
-  assert(this->token_.is_blocked());
+  gold_assert(this->token_.is_blocked());
 }
 
 Task_block_token::~Task_block_token()
@@ -187,9 +186,9 @@ Workqueue::Workqueue(const General_options&)
 
 Workqueue::~Workqueue()
 {
-  assert(this->tasks_.empty());
-  assert(this->completed_.empty());
-  assert(this->running_ == 0);
+  gold_assert(this->tasks_.empty());
+  gold_assert(this->completed_.empty());
+  gold_assert(this->running_ == 0);
 }
 
 // Add a task to the queue.
@@ -263,7 +262,7 @@ Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
              {
                // There had better be some tasks running, or we will
                // never find a runnable task.
-               assert(this->running_ > 0);
+               gold_assert(this->running_ > 0);
 
                // We couldn't find any runnable tasks, and we
                // couldn't release any locks.
@@ -322,7 +321,7 @@ Workqueue::process()
 
            // There must be something for us to wait for, or we won't
            // be able to make progress.
-           assert(this->running_ > 0 || !this->completed_.empty());
+           gold_assert(this->running_ > 0 || !this->completed_.empty());
 
            if (all_blocked)
              {
@@ -330,7 +329,7 @@ Workqueue::process()
                this->clear_completed();
                while (this->cleared_blockers_ == 0)
                  {
-                   assert(this->running_ > 0);
+                   gold_assert(this->running_ > 0);
                    this->completed_condvar_.wait();
                    this->clear_completed();
                  }
@@ -385,7 +384,7 @@ Workqueue::completed(Task* t, Task_locker* tl)
 {
   {
     Hold_lock hl(this->completed_lock_);
-    assert(this->running_ > 0);
+    gold_assert(this->running_ > 0);
     --this->running_;
     this->completed_.push_back(tl);
     this->completed_condvar_.signal();