Generate version information.
authorIan Lance Taylor <iant@google.com>
Wed, 6 Dec 2006 00:02:36 +0000 (00:02 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 6 Dec 2006 00:02:36 +0000 (00:02 +0000)
13 files changed:
elfcpp/elfcpp.h
gold/dynobj.cc
gold/dynobj.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/output.h
gold/po/gold.pot
gold/reloc.cc
gold/resolve.cc
gold/symtab.cc
gold/symtab.h
gold/target.h

index ba85b3d5b2a295b706b4d4100b9713e783bf6542..305487f8bf03fb69b6bd8c03dc385cf25620fd8e 100644 (file)
@@ -692,6 +692,11 @@ struct Elf_sizes
   static const int rela_size = sizeof(internal::Rela_data<size>);
   // Size of ELF dynamic entry.
   static const int dyn_size = sizeof(internal::Dyn_data<size>);
+  // Size of ELF version structures.
+  static const int verdef_size = sizeof(internal::Verdef_data);
+  static const int verdaux_size = sizeof(internal::Verdaux_data);
+  static const int verneed_size = sizeof(internal::Verneed_data);
+  static const int vernaux_size = sizeof(internal::Vernaux_data);
 };
 
 // Accessor class for the ELF file header.
@@ -1378,6 +1383,46 @@ class Verdef
   const internal::Verdef_data* p_;
 };
 
+template<int size, bool big_endian>
+class Verdef_write
+{
+ public:
+  Verdef_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Verdef_data*>(p))
+  { }
+
+  void
+  set_vd_version(Elf_Half v)
+  { this->p_->vd_version = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vd_flags(Elf_Half v)
+  { this->p_->vd_flags = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vd_ndx(Elf_Half v)
+  { this->p_->vd_ndx = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vd_cnt(Elf_Half v)
+  { this->p_->vd_cnt = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vd_hash(Elf_Word v)
+  { this->p_->vd_hash = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vd_aux(Elf_Word v)
+  { this->p_->vd_aux = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vd_next(Elf_Word v)
+  { this->p_->vd_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+  internal::Verdef_data* p_;
+};
+
 // Accessor classes for auxiliary entries in the ELF SHT_GNU_verdef
 // section.
 
@@ -1407,6 +1452,26 @@ class Verdaux
   const internal::Verdaux_data* p_;
 };
 
+template<int size, bool big_endian>
+class Verdaux_write
+{
+ public:
+  Verdaux_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Verdaux_data*>(p))
+  { }
+
+  void
+  set_vda_name(Elf_Word v)
+  { this->p_->vda_name = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vda_next(Elf_Word v)
+  { this->p_->vda_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+  internal::Verdaux_data* p_;
+};
+
 // Accessor classes for entries in the ELF SHT_GNU_verneed section.
 
 template<int size, bool big_endian>
@@ -1447,6 +1512,38 @@ class Verneed
   const internal::Verneed_data* p_;
 };
 
+template<int size, bool big_endian>
+class Verneed_write
+{
+ public:
+  Verneed_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Verneed_data*>(p))
+  { }
+
+  void
+  set_vn_version(Elf_Half v)
+  { this->p_->vn_version = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vn_cnt(Elf_Half v)
+  { this->p_->vn_cnt = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vn_file(Elf_Word v)
+  { this->p_->vn_file = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vn_aux(Elf_Word v)
+  { this->p_->vn_aux = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vn_next(Elf_Word v)
+  { this->p_->vn_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+  internal::Verneed_data* p_;
+};
+
 // Accessor classes for auxiliary entries in the ELF SHT_GNU_verneed
 // section.
 
@@ -1488,6 +1585,37 @@ class Vernaux
   const internal::Vernaux_data* p_;
 };
 
+template<int size, bool big_endian>
+class Vernaux_write
+{
+ public:
+  Vernaux_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Vernaux_data*>(p))
+  { }
+
+  void
+  set_vna_hash(Elf_Word v)
+  { this->p_->vna_hash = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vna_flags(Elf_Half v)
+  { this->p_->vna_flags = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vna_other(Elf_Half v)
+  { this->p_->vna_other = Convert<16, big_endian>::convert_host(v); }
+
+  void
+  set_vna_name(Elf_Word v)
+  { this->p_->vna_name = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  set_vna_next(Elf_Word v)
+  { this->p_->vna_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+  internal::Vernaux_data* p_;
+};
 
 } // End namespace elfcpp.
 
index ac5a74b1c6899aea6fd2b4bb8fd99da58a83dd85..9871bdeca114c48f1481fefc40cc9470bbab0086 100644 (file)
@@ -392,7 +392,8 @@ Sized_dynobj<size, big_endian>::set_version_map(
     unsigned int ndx,
     const char* name) const
 {
-  gold_assert(ndx < version_map->size());
+  if (ndx >= version_map->size())
+    version_map->resize(ndx + 1);
   if ((*version_map)[ndx] != NULL)
     {
       fprintf(stderr, _("%s: %s: duplicate definition for version %u\n"),
@@ -402,207 +403,191 @@ Sized_dynobj<size, big_endian>::set_version_map(
   (*version_map)[ndx] = name;
 }
 
-// Create a vector mapping version numbers to version strings.
+// Add mappings for the version definitions to VERSION_MAP.
 
 template<int size, bool big_endian>
 void
-Sized_dynobj<size, big_endian>::make_version_map(
+Sized_dynobj<size, big_endian>::make_verdef_map(
     Read_symbols_data* sd,
     Version_map* version_map) const
 {
-  if (sd->verdef == NULL && sd->verneed == NULL)
+  if (sd->verdef == NULL)
     return;
 
-  // First find the largest version index.
-  unsigned int maxver = 0;
+  const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
+  off_t names_size = sd->symbol_names_size;
 
-  if (sd->verdef != NULL)
+  const unsigned char* pverdef = sd->verdef->data();
+  off_t verdef_size = sd->verdef_size;
+  const unsigned int count = sd->verdef_info;
+
+  const unsigned char* p = pverdef;
+  for (unsigned int i = 0; i < count; ++i)
     {
-      const unsigned char* pverdef = sd->verdef->data();
-      off_t verdef_size = sd->verdef_size;
-      const unsigned int count = sd->verdef_info;
+      elfcpp::Verdef<size, big_endian> verdef(p);
 
-      const unsigned char* p = pverdef;
-      for (unsigned int i = 0; i < count; ++i)
+      if (verdef.get_vd_version() != elfcpp::VER_DEF_CURRENT)
        {
-         elfcpp::Verdef<size, big_endian> verdef(p);
-
-         const unsigned int vd_ndx = verdef.get_vd_ndx();
+         fprintf(stderr, _("%s: %s: unexpected verdef version %u\n"),
+                 program_name, this->name().c_str(), verdef.get_vd_version());
+         gold_exit(false);
+       }
 
-         // The GNU linker clears the VERSYM_HIDDEN bit.  I'm not
-         // sure why.
+      const unsigned int vd_ndx = verdef.get_vd_ndx();
 
-         if (vd_ndx > maxver)
-           maxver = vd_ndx;
+      // The GNU linker clears the VERSYM_HIDDEN bit.  I'm not
+      // sure why.
 
-         const unsigned int vd_next = verdef.get_vd_next();
-         if ((p - pverdef) + vd_next >= verdef_size)
-           {
-             fprintf(stderr,
-                     _("%s: %s: verdef vd_next field out of range: %u\n"),
-                     program_name, this->name().c_str(), vd_next);
-             gold_exit(false);
-           }
-
-         p += vd_next;
+      // The first Verdaux holds the name of this version.  Subsequent
+      // ones are versions that this one depends upon, which we don't
+      // care about here.
+      const unsigned int vd_cnt = verdef.get_vd_cnt();
+      if (vd_cnt < 1)
+       {
+         fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"),
+                 program_name, this->name().c_str(), vd_cnt);
+         gold_exit(false);
        }
-    }
 
-  if (sd->verneed != NULL)
-    {
-      const unsigned char* pverneed = sd->verneed->data();
-      off_t verneed_size = sd->verneed_size;
-      const unsigned int count = sd->verneed_info;
-
-      const unsigned char* p = pverneed;
-      for (unsigned int i = 0; i < count; ++i)
+      const unsigned int vd_aux = verdef.get_vd_aux();
+      if ((p - pverdef) + vd_aux >= verdef_size)
        {
-         elfcpp::Verneed<size, big_endian> verneed(p);
+         fprintf(stderr,
+                 _("%s: %s: verdef vd_aux field out of range: %u\n"),
+                 program_name, this->name().c_str(), vd_aux);
+         gold_exit(false);
+       }
 
-         const unsigned int vn_aux = verneed.get_vn_aux();
-         if ((p - pverneed) + vn_aux >= verneed_size)
-           {
-             fprintf(stderr,
-                     _("%s: %s: verneed vn_aux field out of range: %u\n"),
-                     program_name, this->name().c_str(), vn_aux);
-             gold_exit(false);
-           }
+      const unsigned char* pvda = p + vd_aux;
+      elfcpp::Verdaux<size, big_endian> verdaux(pvda);
 
-         const unsigned int vn_cnt = verneed.get_vn_cnt();
-         const unsigned char* pvna = p + vn_aux;
-         for (unsigned int j = 0; j < vn_cnt; ++j)
-           {
-             elfcpp::Vernaux<size, big_endian> vernaux(pvna);
-
-             const unsigned int vna_other = vernaux.get_vna_other();
-             if (vna_other > maxver)
-               maxver = vna_other;
-
-             const unsigned int vna_next = vernaux.get_vna_next();
-             if ((pvna - pverneed) + vna_next >= verneed_size)
-               {
-                 fprintf(stderr,
-                         _("%s: %s: verneed vna_next field "
-                           "out of range: %u\n"),
-                         program_name, this->name().c_str(), vna_next);
-                 gold_exit(false);
-               }
-
-             pvna += vna_next;
-           }
+      const unsigned int vda_name = verdaux.get_vda_name();
+      if (vda_name >= names_size)
+       {
+         fprintf(stderr,
+                 _("%s: %s: verdaux vda_name field out of range: %u\n"),
+                 program_name, this->name().c_str(), vda_name);
+         gold_exit(false);
+       }
 
-         const unsigned int vn_next = verneed.get_vn_next();
-         if ((p - pverneed) + vn_next >= verneed_size)
-           {
-             fprintf(stderr,
-                     _("%s: %s: verneed vn_next field out of range: %u\n"),
-                     program_name, this->name().c_str(), vn_next);
-             gold_exit(false);
-           }
+      this->set_version_map(version_map, vd_ndx, names + vda_name);
 
-         p += vn_next;
+      const unsigned int vd_next = verdef.get_vd_next();
+      if ((p - pverdef) + vd_next >= verdef_size)
+       {
+         fprintf(stderr,
+                 _("%s: %s: verdef vd_next field out of range: %u\n"),
+                 program_name, this->name().c_str(), vd_next);
+         gold_exit(false);
        }
+
+      p += vd_next;
     }
+}
 
-  // Now MAXVER is the largest version index we have seen.
+// Add mappings for the required versions to VERSION_MAP.
 
-  version_map->resize(maxver + 1);
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_verneed_map(
+    Read_symbols_data* sd,
+    Version_map* version_map) const
+{
+  if (sd->verneed == NULL)
+    return;
 
   const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
   off_t names_size = sd->symbol_names_size;
 
-  if (sd->verdef != NULL)
+  const unsigned char* pverneed = sd->verneed->data();
+  const off_t verneed_size = sd->verneed_size;
+  const unsigned int count = sd->verneed_info;
+
+  const unsigned char* p = pverneed;
+  for (unsigned int i = 0; i < count; ++i)
     {
-      const unsigned char* pverdef = sd->verdef->data();
-      off_t verdef_size = sd->verdef_size;
-      const unsigned int count = sd->verdef_info;
+      elfcpp::Verneed<size, big_endian> verneed(p);
 
-      const unsigned char* p = pverdef;
-      for (unsigned int i = 0; i < count; ++i)
+      if (verneed.get_vn_version() != elfcpp::VER_NEED_CURRENT)
        {
-         elfcpp::Verdef<size, big_endian> verdef(p);
+         fprintf(stderr, _("%s: %s: unexpected verneed version %u\n"),
+                 program_name, this->name().c_str(),
+                 verneed.get_vn_version());
+         gold_exit(false);
+       }
 
-         const unsigned int vd_cnt = verdef.get_vd_cnt();
-         if (vd_cnt < 1)
-           {
-             fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"),
-                     program_name, this->name().c_str(), vd_cnt);
-             gold_exit(false);
-           }
+      const unsigned int vn_aux = verneed.get_vn_aux();
 
-         const unsigned int vd_aux = verdef.get_vd_aux();
-         if ((p - pverdef) + vd_aux >= verdef_size)
-           {
-             fprintf(stderr,
-                     _("%s: %s: verdef vd_aux field out of range: %u\n"),
-                     program_name, this->name().c_str(), vd_aux);
-             gold_exit(false);
-           }
+      if ((p - pverneed) + vn_aux >= verneed_size)
+       {
+         fprintf(stderr,
+                 _("%s: %s: verneed vn_aux field out of range: %u\n"),
+                 program_name, this->name().c_str(), vn_aux);
+         gold_exit(false);
+       }
 
-         const unsigned char* pvda = p + vd_aux;
-         elfcpp::Verdaux<size, big_endian> verdaux(pvda);
+      const unsigned int vn_cnt = verneed.get_vn_cnt();
+      const unsigned char* pvna = p + vn_aux;
+      for (unsigned int j = 0; j < vn_cnt; ++j)
+       {
+         elfcpp::Vernaux<size, big_endian> vernaux(pvna);
 
-         const unsigned int vda_name = verdaux.get_vda_name();
-         if (vda_name >= names_size)
+         const unsigned int vna_name = vernaux.get_vna_name();
+         if (vna_name >= names_size)
            {
              fprintf(stderr,
-                     _("%s: %s: verdaux vda_name field out of range: %u\n"),
-                     program_name, this->name().c_str(), vda_name);
+                     _("%s: %s: vernaux vna_name field "
+                       "out of range: %u\n"),
+                     program_name, this->name().c_str(), vna_name);
              gold_exit(false);
            }
 
-         this->set_version_map(version_map, verdef.get_vd_ndx(),
-                               names + vda_name);
+         this->set_version_map(version_map, vernaux.get_vna_other(),
+                               names + vna_name);
 
-         const unsigned int vd_next = verdef.get_vd_next();
-         if ((p - pverdef) + vd_next >= verdef_size)
+         const unsigned int vna_next = vernaux.get_vna_next();
+         if ((pvna - pverneed) + vna_next >= verneed_size)
            {
              fprintf(stderr,
-                     _("%s: %s: verdef vd_next field out of range: %u\n"),
-                     program_name, this->name().c_str(), vd_next);
+                     _("%s: %s: verneed vna_next field "
+                       "out of range: %u\n"),
+                     program_name, this->name().c_str(), vna_next);
              gold_exit(false);
            }
 
-         p += vd_next;
+         pvna += vna_next;
+       }
+
+      const unsigned int vn_next = verneed.get_vn_next();
+      if ((p - pverneed) + vn_next >= verneed_size)
+       {
+         fprintf(stderr,
+                 _("%s: %s: verneed vn_next field out of range: %u\n"),
+                 program_name, this->name().c_str(), vn_next);
+         gold_exit(false);
        }
+
+      p += vn_next;
     }
+}
 
-  if (sd->verneed != NULL)
-    {
-      const unsigned char* pverneed = sd->verneed->data();
-      const unsigned int count = sd->verneed_info;
+// Create a vector mapping version numbers to version strings.
 
-      const unsigned char* p = pverneed;
-      for (unsigned int i = 0; i < count; ++i)
-       {
-         elfcpp::Verneed<size, big_endian> verneed(p);
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_version_map(
+    Read_symbols_data* sd,
+    Version_map* version_map) const
+{
+  if (sd->verdef == NULL && sd->verneed == NULL)
+    return;
 
-         const unsigned int vn_aux = verneed.get_vn_aux();
-         const unsigned int vn_cnt = verneed.get_vn_cnt();
-         const unsigned char* pvna = p + vn_aux;
-         for (unsigned int j = 0; j < vn_cnt; ++j)
-           {
-             elfcpp::Vernaux<size, big_endian> vernaux(pvna);
-
-             const unsigned int vna_name = vernaux.get_vna_name();
-             if (vna_name >= names_size)
-               {
-                 fprintf(stderr,
-                         _("%s: %s: vernaux vna_name field "
-                           "out of range: %u\n"),
-                         program_name, this->name().c_str(), vna_name);
-                 gold_exit(false);
-               }
-
-             this->set_version_map(version_map, vernaux.get_vna_other(),
-                                   names + vna_name);
-
-             pvna += vernaux.get_vna_next();
-           }
+  // A guess at the maximum version number we will see.  If this is
+  // wrong we will be less efficient but still correct.
+  version_map->reserve(sd->verdef_info + sd->verneed_info * 10);
 
-         p += verneed.get_vn_next();
-       }
-    }
+  this->make_verdef_map(sd, version_map);
+  this->make_verneed_map(sd, version_map);
 }
 
 // Add the dynamic symbols to the symbol table.
@@ -1059,6 +1044,478 @@ Dynobj::sized_create_gnu_hash_table(
   *pphash = phash;
 }
 
+// Verdef methods.
+
+// Write this definition to a buffer for the output section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const
+{
+  const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+  const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+  elfcpp::Verdef_write<size, big_endian> vd(pb);
+  vd.set_vd_version(elfcpp::VER_DEF_CURRENT);
+  vd.set_vd_flags((this->is_base_ ? elfcpp::VER_FLG_BASE : 0)
+                 | (this->is_weak_ ? elfcpp::VER_FLG_WEAK : 0));
+  vd.set_vd_ndx(this->index());
+  vd.set_vd_cnt(1 + this->deps_.size());
+  vd.set_vd_hash(Dynobj::elf_hash(this->name()));
+  vd.set_vd_aux(verdef_size);
+  vd.set_vd_next(is_last
+                ? 0
+                : verdef_size + (1 + this->deps_.size()) * verdaux_size);
+  pb += verdef_size;
+
+  elfcpp::Verdaux_write<size, big_endian> vda(pb);
+  vda.set_vda_name(dynpool->get_offset(this->name()));
+  vda.set_vda_next(this->deps_.empty() ? 0 : verdaux_size);
+  pb += verdaux_size;
+
+  Deps::const_iterator p;
+  unsigned int i;
+  for (p = this->deps_.begin(), i = 0;
+       p != this->deps_.end();
+       ++p, ++i)
+    {
+      elfcpp::Verdaux_write<size, big_endian> vda(pb);
+      vda.set_vda_name(dynpool->get_offset(*p));
+      vda.set_vda_next(i + 1 >= this->deps_.size() ? 0 : verdaux_size);
+      pb += verdaux_size;
+    }
+
+  return pb;
+}
+
+// Verneed methods.
+
+Verneed::~Verneed()
+{
+  for (Need_versions::iterator p = this->need_versions_.begin();
+       p != this->need_versions_.end();
+       ++p)
+    delete *p;
+}
+
+// Add a new version to this file reference.
+
+Verneed_version*
+Verneed::add_name(const char* name)
+{
+  Verneed_version* vv = new Verneed_version(name);
+  this->need_versions_.push_back(vv);
+  return vv;
+}
+
+// Set the version indexes starting at INDEX.
+
+unsigned int
+Verneed::finalize(unsigned int index)
+{
+  for (Need_versions::iterator p = this->need_versions_.begin();
+       p != this->need_versions_.end();
+       ++p)
+    {
+      (*p)->set_index(index);
+      ++index;
+    }
+  return index;
+}
+
+// Write this list of referenced versions to a buffer for the output
+// section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verneed::write(const Stringpool* dynpool, bool is_last,
+              unsigned char* pb) const
+{
+  const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+  const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+  elfcpp::Verneed_write<size, big_endian> vn(pb);
+  vn.set_vn_version(elfcpp::VER_NEED_CURRENT);
+  vn.set_vn_cnt(this->need_versions_.size());
+  vn.set_vn_file(dynpool->get_offset(this->filename()));
+  vn.set_vn_aux(verneed_size);
+  vn.set_vn_next(is_last
+                ? 0
+                : verneed_size + this->need_versions_.size() * vernaux_size);
+  pb += verneed_size;
+
+  Need_versions::const_iterator p;
+  unsigned int i;
+  for (p = this->need_versions_.begin(), i = 0;
+       p != this->need_versions_.end();
+       ++p, ++i)
+    {
+      elfcpp::Vernaux_write<size, big_endian> vna(pb);
+      vna.set_vna_hash(Dynobj::elf_hash((*p)->version()));
+      // FIXME: We need to sometimes set VER_FLG_WEAK here.
+      vna.set_vna_flags(0);
+      vna.set_vna_other((*p)->index());
+      vna.set_vna_name(dynpool->get_offset((*p)->version()));
+      vna.set_vna_next(i + 1 >= this->need_versions_.size()
+                      ? 0
+                      : vernaux_size);
+      pb += vernaux_size;
+    }
+
+  return pb;
+}
+
+// Versions methods.
+
+Versions::~Versions()
+{
+  for (Defs::iterator p = this->defs_.begin();
+       p != this->defs_.end();
+       ++p)
+    delete *p;
+
+  for (Needs::iterator p = this->needs_.begin();
+       p != this->needs_.end();
+       ++p)
+    delete *p;
+}
+
+// Record version information for a symbol going into the dynamic
+// symbol table.
+
+void
+Versions::record_version(const General_options* options,
+                        Stringpool* dynpool, const Symbol* sym)
+{
+  gold_assert(!this->is_finalized_);
+  gold_assert(sym->version() != NULL);
+
+  Stringpool::Key version_key;
+  const char* version = dynpool->add(sym->version(), &version_key);
+
+  if (!sym->is_from_dynobj())
+    this->add_def(options, sym, version, version_key);
+  else
+    {
+      // This is a version reference.
+
+      Object* object = sym->object();
+      gold_assert(object->is_dynamic());
+      Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+      this->add_need(dynpool, dynobj->soname(), version, version_key);
+    }
+}
+
+// We've found a symbol SYM defined in version VERSION.
+
+void
+Versions::add_def(const General_options* options, const Symbol* sym,
+                 const char* version, Stringpool::Key version_key)
+{
+  Key k(version_key, 0);
+  Version_base* const vbnull = NULL;
+  std::pair<Version_table::iterator, bool> ins =
+    this->version_table_.insert(std::make_pair(k, vbnull));
+
+  if (!ins.second)
+    {
+      // We already have an entry for this version.
+      Version_base* vb = ins.first->second;
+
+      // We have now seen a symbol in this version, so it is not
+      // weak.
+      vb->clear_weak();
+
+      // FIXME: When we support version scripts, we will need to
+      // check whether this symbol should be forced local.
+    }
+  else
+    {
+      // If we are creating a shared object, it is an error to
+      // find a definition of a symbol with a version which is not
+      // in the version script.
+      if (options->is_shared())
+       {
+         fprintf(stderr, _("%s: symbol %s has undefined version %s\n"),
+                 program_name, sym->name(), version);
+         gold_exit(false);
+       }
+
+      // If this is the first version we are defining, first define
+      // the base version.  FIXME: Should use soname here when
+      // creating a shared object.
+      Verdef* vdbase = new Verdef(options->output_file_name(), true, false,
+                                 true);
+      this->defs_.push_back(vdbase);
+
+      // When creating a regular executable, automatically define
+      // a new version.
+      Verdef* vd = new Verdef(version, false, false, false);
+      this->defs_.push_back(vd);
+      ins.first->second = vd;
+    }
+}
+
+// Add a reference to version NAME in file FILENAME.
+
+void
+Versions::add_need(Stringpool* dynpool, const char* filename, const char* name,
+                  Stringpool::Key name_key)
+{
+  Stringpool::Key filename_key;
+  filename = dynpool->add(filename, &filename_key);
+
+  Key k(name_key, filename_key);
+  Version_base* const vbnull = NULL;
+  std::pair<Version_table::iterator, bool> ins =
+    this->version_table_.insert(std::make_pair(k, vbnull));
+
+  if (!ins.second)
+    {
+      // We already have an entry for this filename/version.
+      return;
+    }
+
+  // See whether we already have this filename.  We don't expect many
+  // version references, so we just do a linear search.  This could be
+  // replaced by a hash table.
+  Verneed* vn = NULL;
+  for (Needs::iterator p = this->needs_.begin();
+       p != this->needs_.end();
+       ++p)
+    {
+      if ((*p)->filename() == filename)
+       {
+         vn = *p;
+         break;
+       }
+    }
+
+  if (vn == NULL)
+    {
+      // We have a new filename.
+      vn = new Verneed(filename);
+      this->needs_.push_back(vn);
+    }
+
+  ins.first->second = vn->add_name(name);
+}
+
+// Set the version indexes.  Create a new dynamic version symbol for
+// each new version definition.
+
+unsigned int
+Versions::finalize(const Target* target, Symbol_table* symtab,
+                  unsigned int dynsym_index, std::vector<Symbol*>* syms)
+{
+  gold_assert(!this->is_finalized_);
+
+  unsigned int vi = 1;
+
+  for (Defs::iterator p = this->defs_.begin();
+       p != this->defs_.end();
+       ++p)
+    {
+      (*p)->set_index(vi);
+      ++vi;
+
+      // Create a version symbol if necessary.
+      if (!(*p)->is_symbol_created())
+       {
+         Symbol* vsym =symtab->define_as_constant(target, (*p)->name(),
+                                                  (*p)->name(), 0, 0,
+                                                  elfcpp::STT_OBJECT,
+                                                  elfcpp::STB_GLOBAL,
+                                                  elfcpp::STV_DEFAULT, 0,
+                                                  false);
+         vsym->set_needs_dynsym_entry();
+         ++dynsym_index;
+         syms->push_back(vsym);
+         // The name is already in the dynamic pool.
+       }
+    }
+
+  // Index 1 is used for global symbols.
+  if (vi == 1)
+    {
+      gold_assert(this->defs_.empty());
+      vi = 2;
+    }
+
+  for (Needs::iterator p = this->needs_.begin();
+       p != this->needs_.end();
+       ++p)
+    vi = (*p)->finalize(vi);
+
+  this->is_finalized_ = true;
+
+  return dynsym_index;
+}
+
+// Return the version index to use for a symbol.  This does two hash
+// table lookups: one in DYNPOOL and one in this->version_table_.
+// Another approach alternative would be store a pointer in SYM, which
+// would increase the size of the symbol table.  Or perhaps we could
+// use a hash table from dynamic symbol pointer values to Version_base
+// pointers.
+
+unsigned int
+Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
+{
+  Stringpool::Key version_key;
+  const char* version = dynpool->find(sym->version(), &version_key);
+  gold_assert(version != NULL);
+
+  Version_table::const_iterator p;
+  if (!sym->is_from_dynobj())
+    {
+      Key k(version_key, 0);
+      p = this->version_table_.find(k);
+    }
+  else
+    {
+      Object* object = sym->object();
+      gold_assert(object->is_dynamic());
+      Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+      Stringpool::Key filename_key;
+      const char* filename = dynpool->find(dynobj->soname(), &filename_key);
+      gold_assert(filename != NULL);
+
+      Key k(version_key, filename_key);
+      p = this->version_table_.find(k);
+    }
+
+  gold_assert(p != this->version_table_.end());
+
+  return p->second->index();
+}
+
+// Return an allocated buffer holding the contents of the symbol
+// version section.
+
+template<int size, bool big_endian>
+void
+Versions::symbol_section_contents(const Stringpool* dynpool,
+                                 unsigned int local_symcount,
+                                 const std::vector<Symbol*>& syms,
+                                 unsigned char** pp,
+                                 unsigned int* psize) const
+{
+  gold_assert(this->is_finalized_);
+
+  unsigned int sz = (local_symcount + syms.size()) * 2;
+  unsigned char* pbuf = new unsigned char[sz];
+
+  for (unsigned int i = 0; i < local_symcount; ++i)
+    elfcpp::Swap<16, big_endian>::writeval(pbuf + i * 2,
+                                          elfcpp::VER_NDX_LOCAL);
+
+  for (std::vector<Symbol*>::const_iterator p = syms.begin();
+       p != syms.end();
+       ++p)
+    {
+      unsigned int version_index;
+      const char* version = (*p)->version();
+      if (version == NULL)
+       version_index = elfcpp::VER_NDX_GLOBAL;
+      else
+       version_index = this->version_index(dynpool, *p);
+      elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2,
+                                            version_index);
+    }
+
+  *pp = pbuf;
+  *psize = sz;
+}
+
+// Return an allocated buffer holding the contents of the version
+// definition section.
+
+template<int size, bool big_endian>
+void
+Versions::def_section_contents(const Stringpool* dynpool,
+                              unsigned char** pp, unsigned int* psize,
+                              unsigned int* pentries) const
+{
+  gold_assert(this->is_finalized_);
+  gold_assert(!this->defs_.empty());
+
+  const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+  const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+  unsigned int sz = 0;
+  for (Defs::const_iterator p = this->defs_.begin();
+       p != this->defs_.end();
+       ++p)
+    {
+      sz += verdef_size + verdaux_size;
+      sz += (*p)->count_dependencies() * verdaux_size;
+    }
+
+  unsigned char* pbuf = new unsigned char[sz];
+
+  unsigned char* pb = pbuf;
+  Defs::const_iterator p;
+  unsigned int i;
+  for (p = this->defs_.begin(), i = 0;
+       p != this->defs_.end();
+       ++p, ++i)
+    pb = (*p)->write<size, big_endian>(dynpool,
+                                      i + 1 >= this->defs_.size(),
+                                      pb);
+
+  gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+  *pp = pbuf;
+  *psize = sz;
+  *pentries = this->defs_.size();
+}
+
+// Return an allocated buffer holding the contents of the version
+// reference section.
+
+template<int size, bool big_endian>
+void
+Versions::need_section_contents(const Stringpool* dynpool,
+                               unsigned char** pp, unsigned int *psize,
+                               unsigned int *pentries) const
+{
+  gold_assert(this->is_finalized_);
+  gold_assert(!this->needs_.empty());
+
+  const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+  const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+  unsigned int sz = 0;
+  for (Needs::const_iterator p = this->needs_.begin();
+       p != this->needs_.end();
+       ++p)
+    {
+      sz += verneed_size;
+      sz += (*p)->count_versions() * vernaux_size;
+    }
+
+  unsigned char* pbuf = new unsigned char[sz];
+
+  unsigned char* pb = pbuf;
+  Needs::const_iterator p;
+  unsigned int i;
+  for (p = this->needs_.begin(), i = 0;
+       p != this->needs_.end();
+       ++p, ++i)
+    pb = (*p)->write<size, big_endian>(dynpool,
+                                      i + 1 >= this->needs_.size(),
+                                      pb);
+
+  gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+  *pp = pbuf;
+  *psize = sz;
+  *pentries = this->needs_.size();
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones for implemented targets.
 
@@ -1074,4 +1531,92 @@ class Sized_dynobj<64, false>;
 template
 class Sized_dynobj<64, true>;
 
+template
+void
+Versions::symbol_section_contents<32, false>(const Stringpool*,
+                                            unsigned int,
+                                            const std::vector<Symbol*>&,
+                                            unsigned char**,
+                                            unsigned int*) const;
+
+template
+void
+Versions::symbol_section_contents<32, true>(const Stringpool*,
+                                           unsigned int,
+                                           const std::vector<Symbol*>&,
+                                           unsigned char**,
+                                           unsigned int*) const;
+
+template
+void
+Versions::symbol_section_contents<64, false>(const Stringpool*,
+                                            unsigned int,
+                                            const std::vector<Symbol*>&,
+                                            unsigned char**,
+                                            unsigned int*) const;
+
+template
+void
+Versions::symbol_section_contents<64, true>(const Stringpool*,
+                                           unsigned int,
+                                           const std::vector<Symbol*>&,
+                                           unsigned char**,
+                                           unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<32, false>(const Stringpool*,
+                                         unsigned char**,
+                                         unsigned int*,
+                                         unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<32, true>(const Stringpool*,
+                                        unsigned char**,
+                                        unsigned int*,
+                                        unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<64, false>(const Stringpool*,
+                                         unsigned char**,
+                                         unsigned int*,
+                                         unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<64, true>(const Stringpool*,
+                                        unsigned char**,
+                                        unsigned int*,
+                                        unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<32, false>(const Stringpool*,
+                                          unsigned char**,
+                                          unsigned int*,
+                                          unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<32, true>(const Stringpool*,
+                                         unsigned char**,
+                                         unsigned int*,
+                                         unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<64, false>(const Stringpool*,
+                                          unsigned char**,
+                                          unsigned int*,
+                                          unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<64, true>(const Stringpool*,
+                                         unsigned char**,
+                                         unsigned int*,
+                                         unsigned int*) const;
+
 } // End namespace gold.
index bc877c412f54a87694f613097576680eeefa66a1..9e5dd43d70af39112e3cf80e741b724bb1d7842f 100644 (file)
@@ -5,11 +5,15 @@
 
 #include <vector>
 
+#include "stringpool.h"
 #include "object.h"
 
 namespace gold
 {
 
+class General_options;
+class Stringpool;
+
 // A dynamic object (ET_DYN).  This is an abstract base class itself.
 // The implementations is the template class Sized_dynobj.
 
@@ -24,6 +28,10 @@ class Dynobj : public Object
   const char*
   soname() const;
 
+  // Compute the ELF hash code for a string.
+  static uint32_t
+  elf_hash(const char*);
+
   // 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
@@ -50,10 +58,6 @@ class Dynobj : public Object
   { 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*);
@@ -166,6 +170,14 @@ class Sized_dynobj : public Dynobj
   void
   make_version_map(Read_symbols_data* sd, Version_map*) const;
 
+  // Add version definitions to the version map.
+  void
+  make_verdef_map(Read_symbols_data* sd, Version_map*) const;
+
+  // Add version references to the version map.
+  void
+  make_verneed_map(Read_symbols_data* sd, Version_map*) const;
+
   // Add an entry to the version map.
   void
   set_version_map(Version_map*, unsigned int ndx, const char* name) const;
@@ -174,6 +186,305 @@ class Sized_dynobj : public Dynobj
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
 };
 
+// A base class for Verdef and Verneed_version which just handles the
+// version index which will be stored in the SHT_GNU_versym section.
+
+class Version_base
+{
+ public:
+  Version_base()
+    : index_(-1U)
+  { }
+
+  virtual
+  ~Version_base()
+  { }
+
+  // Return the version index.
+  unsigned int
+  index() const
+  {
+    gold_assert(this->index_ != -1U);
+    return this->index_;
+  }
+
+  // Set the version index.
+  void
+  set_index(unsigned int index)
+  {
+    gold_assert(this->index_ == -1U);
+    this->index_ = index;
+  }
+
+  // Clear the weak flag in a version definition.
+  virtual void
+  clear_weak() = 0;
+
+ private:
+  Version_base(const Version_base&);
+  Version_base& operator=(const Version_base&);
+
+  // The index of the version definition or reference.
+  unsigned int index_;
+};
+
+// This class handles a version being defined in the file we are
+// generating.
+
+class Verdef : public Version_base
+{
+ public:
+  Verdef(const char* name, bool is_base, bool is_weak, bool is_symbol_created)
+    : name_(name), deps_(), is_base_(is_base), is_weak_(is_weak),
+      is_symbol_created_(is_symbol_created)
+  { }
+
+  // Return the version name.
+  const char*
+  name() const
+  { return this->name_; }
+
+  // Return the number of dependencies.
+  unsigned int
+  count_dependencies() const
+  { return this->deps_.size(); }
+
+  // Add a dependency to this version.  The NAME should be
+  // canonicalized in the dynamic Stringpool.
+  void
+  add_dependency(const char* name)
+  { this->deps_.push_back(name); }
+
+  // Return whether this definition is weak.
+  bool
+  is_weak() const
+  { return this->is_weak_; }
+
+  // Clear the weak flag.
+  void
+  clear_weak()
+  { this->is_weak_ = false; }
+
+  // Return whether a version symbol has been created for this
+  // definition.
+  bool
+  is_symbol_created() const
+  { return this->is_symbol_created_; }
+
+  // Write contents to buffer.
+  template<int size, bool big_endian>
+  unsigned char*
+  write(const Stringpool*, bool is_last, unsigned char*) const;
+
+ private:
+  Verdef(const Verdef&);
+  Verdef& operator=(const Verdef&);
+
+  // The type of the list of version dependencies.  Each dependency
+  // should be canonicalized in the dynamic Stringpool.
+  typedef std::vector<const char*> Deps;
+
+  // The name of this version.  This should be canonicalized in the
+  // dynamic Stringpool.
+  const char* name_;
+  // A list of other versions which this version depends upon.
+  Deps deps_;
+  // Whether this is the base version.
+  bool is_base_;
+  // Whether this version is weak.
+  bool is_weak_;
+  // Whether a version symbol has been created.
+  bool is_symbol_created_;
+};
+
+// A referened version.  This will be associated with a filename by
+// Verneed.
+
+class Verneed_version : public Version_base
+{
+ public:
+  Verneed_version(const char* version)
+    : version_(version)
+  { }
+
+  // Return the version name.
+  const char*
+  version() const
+  { return this->version_; }
+
+  // Clear the weak flag.  This is invalid for a reference.
+  void
+  clear_weak()
+  { gold_unreachable(); }
+
+ private:
+  Verneed_version(const Verneed_version&);
+  Verneed_version& operator=(const Verneed_version&);
+
+  const char* version_;
+};
+
+// Version references in a single dynamic object.
+
+class Verneed
+{
+ public:
+  Verneed(const char* filename)
+    : filename_(filename), need_versions_()
+  { }
+
+  ~Verneed();
+
+  // Return the file name.
+  const char*
+  filename() const
+  { return this->filename_; }
+
+  // Return the number of versions.
+  unsigned int
+  count_versions() const
+  { return this->need_versions_.size(); }
+
+  // Add a version name.  The name should be canonicalized in the
+  // dynamic Stringpool.  If the name is already present, this does
+  // nothing.
+  Verneed_version*
+  add_name(const char* name);
+
+  // Set the version indexes, starting at INDEX.  Return the updated
+  // INDEX.
+  unsigned int
+  finalize(unsigned int index);
+
+  // Write contents to buffer.
+  template<int size, bool big_endian>
+  unsigned char*
+  write(const Stringpool*, bool is_last, unsigned char*) const;
+
+ private:
+  Verneed(const Verneed&);
+  Verneed& operator=(const Verneed&);
+
+  // The type of the list of version names.  Each name should be
+  // canonicalized in the dynamic Stringpool.
+  typedef std::vector<Verneed_version*> Need_versions;
+
+  // The filename of the dynamic object.  This should be
+  // canonicalized in the dynamic Stringpool.
+  const char* filename_;
+  // The list of version names.
+  Need_versions need_versions_;
+};
+
+// This class handles version definitions and references which go into
+// the output file.
+
+class Versions
+{
+ public:
+  Versions()
+    : defs_(), needs_(), version_table_(), is_finalized_(false)
+  { }
+
+  ~Versions();
+
+  // SYM is going into the dynamic symbol table and has a version.
+  // Record the appropriate version information.
+  void
+  record_version(const General_options*, Stringpool*, const Symbol* sym);
+
+  // Set the version indexes.  DYNSYM_INDEX is the index we should use
+  // for the next dynamic symbol.  We add new dynamic symbols to SYMS
+  // and return an updated DYNSYM_INDEX.
+  unsigned int
+  finalize(const Target*, Symbol_table* symtab, unsigned int dynsym_index,
+          std::vector<Symbol*>* syms);
+
+  // Return whether there are any version definitions.
+  bool
+  any_defs() const
+  { return !this->defs_.empty(); }
+
+  // Return whether there are any version references.
+  bool
+  any_needs() const
+  { return !this->needs_.empty(); }
+
+  // Build an allocated buffer holding the contents of the symbol
+  // version section (.gnu.version).
+  template<int size, bool big_endian>
+  void
+  symbol_section_contents(const Stringpool*, unsigned int local_symcount,
+                         const std::vector<Symbol*>& syms,
+                         unsigned char**, unsigned int*) const;
+
+  // Build an allocated buffer holding the contents of the version
+  // definition section (.gnu.version_d).
+  template<int size, bool big_endian>
+  void
+  def_section_contents(const Stringpool*, unsigned char**,
+                      unsigned int* psize, unsigned int* pentries) const;
+
+  // Build an allocated buffer holding the contents of the version
+  // reference section (.gnu.version_r).
+  template<int size, bool big_endian>
+  void
+  need_section_contents(const Stringpool*, unsigned char**,
+                       unsigned int* psize, unsigned int* pentries) const;
+
+ private:
+  // The type of the list of version definitions.
+  typedef std::vector<Verdef*> Defs;
+
+  // The type of the list of version references.
+  typedef std::vector<Verneed*> Needs;
+
+  // Handle a symbol SYM defined with version VERSION.
+  void
+  add_def(const General_options*, const Symbol* sym, const char* version,
+         Stringpool::Key);
+
+  // Add a reference to version NAME in file FILENAME.
+  void
+  add_need(Stringpool*, const char* filename, const char* name,
+          Stringpool::Key);
+
+  // Return the version index to use for SYM.
+  unsigned int
+  version_index(const Stringpool*, const Symbol* sym) const;
+
+  // We keep a hash table mapping canonicalized name/version pairs to
+  // a version base.
+  typedef std::pair<Stringpool::Key, Stringpool::Key> Key;
+
+  struct Version_table_hash
+  {
+    size_t
+    operator()(const Key& k) const
+    { return k.first + k.second; }
+  };
+
+  struct Version_table_eq
+  {
+    bool
+    operator()(const Key& k1, const Key& k2) const
+    { return k1.first == k2.first && k1.second == k2.second; }
+  };
+
+  typedef Unordered_map<Key, Version_base*, Version_table_hash,
+                       Version_table_eq> Version_table;
+
+  // The version definitions.
+  Defs defs_;
+  // The version references.
+  Needs needs_;
+  // The mapping from a canonicalized version/filename pair to a
+  // version index.  The filename may be NULL.
+  Version_table version_table_;
+  // Whether the version indexes have been set.
+  bool is_finalized_;
+};
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_DYNOBJ_H)
index ee3654c5a05cd354d503e2fd04caf45ac4c772bc..dbbd2c09b73a0b727b377878759296ecf482a959 100644 (file)
@@ -247,7 +247,7 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab,
       this->got_plt_->set_space_size(3 * 4);
 
       // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
-      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_",
+      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
                                    this->got_plt_,
                                    0, 0, elfcpp::STT_OBJECT,
                                    elfcpp::STB_LOCAL,
@@ -607,10 +607,10 @@ Target_i386::copy_reloc(const General_options* options,
       dynbss->set_space_size(dynbss_size + symsize);
 
       // Define the symbol in the .dynbss section.
-      symtab->define_in_output_data(this, ssym->name(), dynbss, offset,
-                                   symsize, ssym->type(), ssym->binding(),
-                                   ssym->visibility(), ssym->nonvis(),
-                                   false, false);
+      symtab->define_in_output_data(this, ssym->name(), ssym->version(),
+                                   dynbss, offset, symsize, ssym->type(),
+                                   ssym->binding(), ssym->visibility(),
+                                   ssym->nonvis(), false, false);
 
       // Add the COPY reloc.
       ssym->set_needs_dynsym_entry();
@@ -819,7 +819,7 @@ Target_i386::Scan::global(const General_options& options,
       // relocation in order to avoid a COPY relocation.
       gold_assert(!options.is_shared());
 
-      if (gsym->is_defined_in_dynobj())
+      if (gsym->is_from_dynobj())
        {
          // This symbol is defined in a dynamic object.  If it is a
          // function, we make a PLT entry.  Otherwise we need to
@@ -1050,7 +1050,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
     }
 
   // Pick the value to use for symbols defined in shared objects.
-  if (gsym != NULL && gsym->is_defined_in_dynobj())
+  if (gsym != NULL && gsym->is_from_dynobj())
     {
       if (gsym->has_plt_offset())
        value = target->plt_section()->address() + gsym->plt_offset();
index f424bb4438e408ca02e8d27ab4f79208f4b78afe..2d7a3faff09c19d91fc5520fdd780e134bb95c30 100644 (file)
@@ -42,8 +42,8 @@ Layout::Layout(const General_options& options)
   : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
     section_name_map_(), segment_list_(), section_list_(),
     unattached_section_list_(), special_output_list_(),
-    tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL),
-    dynamic_section_(NULL), dynamic_data_(NULL)
+    tls_segment_(NULL), symtab_section_(NULL),
+    dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(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.
@@ -322,7 +322,7 @@ Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
                                                     (elfcpp::SHF_ALLOC
                                                      | elfcpp::SHF_WRITE));
 
-  symtab->define_in_output_data(input_objects->target(), "_DYNAMIC",
+  symtab->define_in_output_data(input_objects->target(), "_DYNAMIC", NULL,
                                this->dynamic_section_, 0, 0,
                                elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
                                elfcpp::STV_HIDDEN, 0, false, false);
@@ -405,9 +405,14 @@ 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);
 
-      // Create the dynamic symbol table, including the hash table,
-      // the dynamic relocations, and the version sections.
-      this->create_dynamic_symtab(target, symtab);
+      // Create the dynamic symbol table, including the hash table.
+      Output_section* dynstr;
+      std::vector<Symbol*> dynamic_symbols;
+      unsigned int local_dynamic_count;
+      Versions versions;
+      this->create_dynamic_symtab(target, symtab, &dynstr,
+                                 &local_dynamic_count, &dynamic_symbols,
+                                 &versions);
 
       // Create the .interp section to hold the name of the
       // interpreter, and put it in a PT_INTERP segment.
@@ -416,6 +421,15 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
       // Finish the .dynamic section to hold the dynamic data, and put
       // it in a PT_DYNAMIC segment.
       this->finish_dynamic_section(input_objects, symtab);
+
+      // We should have added everything we need to the dynamic string
+      // table.
+      this->dynpool_.set_string_offsets();
+
+      // Create the version sections.  We can't do this until the
+      // dynamic string table is complete.
+      this->create_version_sections(target, &versions, local_dynamic_count,
+                                   dynamic_symbols, dynstr);
     }
 
   // FIXME: Handle PT_GNU_STACK.
@@ -831,7 +845,11 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
 // Create the dynamic symbol table.
 
 void
-Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
+Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
+                             Output_section **pdynstr,
+                             unsigned int* plocal_dynamic_count,
+                             std::vector<Symbol*>* pdynamic_symbols,
+                             Versions* pversions)
 {
   // Count all the symbols in the dynamic symbol table, and set the
   // dynamic symbol indexes.
@@ -859,13 +877,13 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
   // this->dynpool_.
 
   unsigned int local_symcount = index;
-
-  std::vector<Symbol*> dynamic_symbols;
+  *plocal_dynamic_count = local_symcount;
 
   // 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_);
+  index = symtab->set_dynsym_indexes(&this->options_, target, index,
+                                    pdynamic_symbols, &this->dynpool_,
+                                    pversions);
 
   int symsize;
   unsigned int align;
@@ -883,6 +901,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
   else
     gold_unreachable();
 
+  // Create the dynamic symbol table section.
+
   const char* dynsym_name = this->namepool_.add(".dynsym", NULL);
   Output_section* dynsym = this->make_output_section(dynsym_name,
                                                     elfcpp::SHT_DYNSYM,
@@ -902,6 +922,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
   odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
   odyn->add_constant(elfcpp::DT_SYMENT, symsize);
 
+  // Create the dynamic string table section.
+
   const char* dynstr_name = this->namepool_.add(".dynstr", NULL);
   Output_section* dynstr = this->make_output_section(dynstr_name,
                                                     elfcpp::SHT_STRTAB,
@@ -916,11 +938,15 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
   odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
   odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
 
+  *pdynstr = dynstr;
+
+  // Create the hash tables.
+
   // 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,
+  Dynobj::create_elf_hash_table(target, *pdynamic_symbols, local_symcount,
                                &phash, &hashlen);
 
   const char* hash_name = this->namepool_.add(".hash", NULL);
@@ -939,6 +965,131 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
   odyn->add_section_address(elfcpp::DT_HASH, hashsec);
 }
 
+// Create the version sections.
+
+void
+Layout::create_version_sections(const Target* target, const Versions* versions,
+                               unsigned int local_symcount,
+                               const std::vector<Symbol*>& dynamic_symbols,
+                               const Output_section* dynstr)
+{
+  if (!versions->any_defs() && !versions->any_needs())
+    return;
+
+  if (target->get_size() == 32)
+    {
+      if (target->is_big_endian())
+       this->sized_create_version_sections<32, true>(versions,
+                                                     local_symcount,
+                                                     dynamic_symbols,
+                                                     dynstr);
+      else
+       this->sized_create_version_sections<32, false>(versions,
+                                                      local_symcount,
+                                                      dynamic_symbols,
+                                                      dynstr);
+    }
+  else if (target->get_size() == 64)
+    {
+      if (target->is_big_endian())
+       this->sized_create_version_sections<64, true>(versions,
+                                                     local_symcount,
+                                                     dynamic_symbols,
+                                                     dynstr);
+      else
+       this->sized_create_version_sections<64, false>(versions,
+                                                      local_symcount,
+                                                      dynamic_symbols,
+                                                      dynstr);
+    }
+  else
+    gold_unreachable();
+}
+
+// Create the version sections, sized version.
+
+template<int size, bool big_endian>
+void
+Layout::sized_create_version_sections(
+    const Versions* versions,
+    unsigned int local_symcount,
+    const std::vector<Symbol*>& dynamic_symbols,
+    const Output_section* dynstr)
+{
+  const char* vname = this->namepool_.add(".gnu.version", NULL);
+  Output_section* vsec = this->make_output_section(vname,
+                                                  elfcpp::SHT_GNU_versym,
+                                                  elfcpp::SHF_ALLOC);
+
+  unsigned char* vbuf;
+  unsigned int vsize;
+  versions->symbol_section_contents<size, big_endian>(&this->dynpool_,
+                                                     local_symcount,
+                                                     dynamic_symbols,
+                                                     &vbuf, &vsize);
+
+  Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2);
+
+  vsec->add_output_section_data(vdata);
+  vsec->set_entsize(2);
+  vsec->set_link_section(this->dynsym_section_);
+
+  Output_data_dynamic* const odyn = this->dynamic_data_;
+  odyn->add_section_address(elfcpp::DT_VERSYM, vsec);
+
+  if (versions->any_defs())
+    {
+      const char* vdname = this->namepool_.add(".gnu.version_d", NULL);
+      Output_section *vdsec;
+      vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef,
+                                       elfcpp::SHF_ALLOC);
+
+      unsigned char* vdbuf;
+      unsigned int vdsize;
+      unsigned int vdentries;
+      versions->def_section_contents<size, big_endian>(&this->dynpool_,
+                                                      &vdbuf, &vdsize,
+                                                      &vdentries);
+
+      Output_section_data* vddata = new Output_data_const_buffer(vdbuf,
+                                                                vdsize,
+                                                                4);
+
+      vdsec->add_output_section_data(vddata);
+      vdsec->set_link_section(dynstr);
+      vdsec->set_info(vdentries);
+
+      odyn->add_section_address(elfcpp::DT_VERDEF, vdsec);
+      odyn->add_constant(elfcpp::DT_VERDEFNUM, vdentries);
+    }
+
+  if (versions->any_needs())
+    {
+      const char* vnname = this->namepool_.add(".gnu.version_r", NULL);
+      Output_section* vnsec;
+      vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed,
+                                       elfcpp::SHF_ALLOC);
+
+      unsigned char* vnbuf;
+      unsigned int vnsize;
+      unsigned int vnentries;
+      versions->need_section_contents<size, big_endian>(&this->dynpool_,
+                                                       &vnbuf, &vnsize,
+                                                       &vnentries);
+
+      Output_section_data* vndata = new Output_data_const_buffer(vnbuf,
+                                                                vnsize,
+                                                                4);
+
+      vnsec->add_output_section_data(vndata);
+      vnsec->set_link_section(dynstr);
+      vnsec->set_info(vnentries);
+
+      odyn->add_section_address(elfcpp::DT_VERNEED, vnsec);
+      odyn->add_constant(elfcpp::DT_VERNEEDNUM, vnentries);
+    }
+}
+
 // Create the .interp section and PT_INTERP segment.
 
 void
@@ -990,11 +1141,11 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
 
   // FIXME: Support --init and --fini.
   Symbol* sym = symtab->lookup("_init");
-  if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
+  if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
     odyn->add_symbol(elfcpp::DT_INIT, sym);
 
   sym = symtab->lookup("_fini");
-  if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
+  if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
     odyn->add_symbol(elfcpp::DT_FINI, sym);
 
   // FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
index 4c54e005554eac3de42e882c3ca485f77635c764..44f9f4e756d800860d0d7a758f807d56046262cd 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "workqueue.h"
 #include "object.h"
+#include "dynobj.h"
 #include "stringpool.h"
 
 namespace gold
@@ -201,7 +202,10 @@ class Layout
 
   // Create the dynamic symbol table.
   void
-  create_dynamic_symtab(const Target*, Symbol_table*);
+  create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr,
+                       unsigned int* plocal_dynamic_count,
+                       std::vector<Symbol*>* pdynamic_symbols,
+                       Versions* versions);
 
   // Finish the .dynamic section and PT_DYNAMIC segment.
   void
@@ -211,6 +215,20 @@ class Layout
   void
   create_interp(const Target* target);
 
+  // Create the version sections.
+  void
+  create_version_sections(const Target*, const Versions*,
+                         unsigned int local_symcount,
+                         const std::vector<Symbol*>& dynamic_symbols,
+                         const Output_section* dynstr);
+
+  template<int size, bool big_endian>
+  void
+  sized_create_version_sections(const Versions* versions,
+                               unsigned int local_symcount,
+                               const std::vector<Symbol*>& dynamic_symbols,
+                               const Output_section* dynstr);
+
   // Return whether to include this section in the link.
   template<int size, bool big_endian>
   bool
@@ -242,7 +260,7 @@ class Layout
   off_t
   set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
 
-  // Set the final file offsets and section indices of all the
+  // Set the final file offsets and section indexes of all the
   // sections not associated with a segment.
   off_t
   set_section_offsets(off_t, unsigned int *pshndx);
index ceea87729f4599bb83de567434c99710eb34cec3..013a19f1b91028441bfafa2151eebef86db74674 100644 (file)
@@ -1165,7 +1165,7 @@ class Output_section : public Output_data
 
   // Set the link field to the output section index of a section.
   void
-  set_link_section(Output_data* od)
+  set_link_section(const Output_data* od)
   {
     gold_assert(this->link_ == 0
                && !this->should_link_to_symtab_
@@ -1213,7 +1213,7 @@ class Output_section : public Output_data
 
   // Set the info field to the output section index of a section.
   void
-  set_info_section(Output_data* od)
+  set_info_section(const Output_data* od)
   {
     gold_assert(this->info_ == 0);
     this->info_section_ = od;
@@ -1417,11 +1417,11 @@ class Output_section : public Output_data
   uint64_t entsize_;
   // The file offset is in the parent class.
   // Set the section link field to the index of this section.
-  Output_data* link_section_;
+  const Output_data* link_section_;
   // If link_section_ is NULL, this is the link field.
   unsigned int link_;
   // Set the section info field to the index of this section.
-  Output_data* info_section_;
+  const Output_data* info_section_;
   // If info_section_ is NULL, this is the section info field.
   unsigned int info_;
   // The section type.
index dbfa857cf1eb5da4d32424189c7c641467f361e2..abce13a1d8f07579c1c29eb887d8cf03bb1787eb 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-12-01 08:46-0800\n"
+"POT-Creation-Date: 2006-12-05 15: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"
@@ -106,56 +106,71 @@ msgstr ""
 msgid "%s: %s: bad section name offset for section %u: %lu\n"
 msgstr ""
 
-#: dynobj.cc:398
+#: dynobj.cc:399
 #, c-format
 msgid "%s: %s: duplicate definition for version %u\n"
 msgstr ""
 
-#: dynobj.cc:442 dynobj.cc:561
+#: dynobj.cc:431
 #, c-format
-msgid "%s: %s: verdef vd_next field out of range: %u\n"
+msgid "%s: %s: unexpected verdef version %u\n"
 msgstr ""
 
-#: dynobj.cc:466
+#: dynobj.cc:447
 #, c-format
-msgid "%s: %s: verneed vn_aux field out of range: %u\n"
+msgid "%s: %s: verdef vd_cnt field too small: %u\n"
 msgstr ""
 
-#: dynobj.cc:485
+#: dynobj.cc:456
 #, c-format
-msgid "%s: %s: verneed vna_next field out of range: %u\n"
+msgid "%s: %s: verdef vd_aux field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:498
+#: dynobj.cc:468
 #, c-format
-msgid "%s: %s: verneed vn_next field out of range: %u\n"
+msgid "%s: %s: verdaux vda_name field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:528
+#: dynobj.cc:479
 #, c-format
-msgid "%s: %s: verdef vd_cnt field too small: %u\n"
+msgid "%s: %s: verdef vd_next field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:537
+#: dynobj.cc:513
 #, c-format
-msgid "%s: %s: verdef vd_aux field out of range: %u\n"
+msgid "%s: %s: unexpected verneed version %u\n"
 msgstr ""
 
-#: dynobj.cc:549
+#: dynobj.cc:524
 #, c-format
-msgid "%s: %s: verdaux vda_name field out of range: %u\n"
+msgid "%s: %s: verneed vn_aux field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:591
+#: dynobj.cc:539
 #, c-format
 msgid "%s: %s: vernaux vna_name field out of range: %u\n"
 msgstr ""
 
-#: dynobj.cc:628
+#: dynobj.cc:552
+#, c-format
+msgid "%s: %s: verneed vna_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:565
+#, c-format
+msgid "%s: %s: verneed vn_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:613
 #, c-format
 msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n"
 msgstr ""
 
+#: dynobj.cc:1240
+#, c-format
+msgid "%s: symbol %s has undefined version %s\n"
+msgstr ""
+
 #: fileread.cc:55
 #, c-format
 msgid "%s: warning: close(%s) failed: %s"
@@ -567,12 +582,12 @@ msgstr ""
 msgid "%s: %s: reloc section %u size %lu uneven"
 msgstr ""
 
-#: resolve.cc:142
+#: resolve.cc:147
 #, c-format
 msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
 msgstr ""
 
-#: resolve.cc:148
+#: resolve.cc:153
 #, c-format
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
@@ -607,12 +622,12 @@ msgstr ""
 msgid "%s: %s: versym for symbol %zu has no name: %u\n"
 msgstr ""
 
-#: symtab.cc:1063 symtab.cc:1235
+#: symtab.cc:1093 symtab.cc:1265
 #, c-format
 msgid "%s: %s: unsupported symbol section 0x%x\n"
 msgstr ""
 
-#: symtab.cc:1423
+#: symtab.cc:1458
 #, c-format
 msgid "%s: %s: warning: %s\n"
 msgstr ""
index 5b4db46ccb3e901c79e507064c0c2fba0aec6f70..001fb01cc1e70584a480a3b3d576dae87ac6b5c7 100644 (file)
@@ -484,7 +484,7 @@ Copy_relocs<size, big_endian>::Copy_reloc_entry::should_emit()
 {
   if (this->sym_ == NULL)
     return false;
-  if (this->sym_->is_defined_in_dynobj())
+  if (this->sym_->is_from_dynobj())
     return true;
   this->sym_ = NULL;
   return false;
index b8e5e701cb74c58b5abce3a0c1d468228fabf8a5..1272e0588a9634d8d932a70f3f8228efa668831d 100644 (file)
@@ -17,10 +17,15 @@ namespace gold
 template<int size, bool big_endian>
 void
 Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
-                     Object* object)
+                     Object* object, const char* version)
 {
   gold_assert(this->source_ == FROM_OBJECT);
   this->u_.from_object.object = object;
+  if (version != NULL && this->version() != version)
+    {
+      gold_assert(this->version() == NULL);
+      this->version_ = version;
+    }
   // FIXME: Handle SHN_XINDEX.
   this->u_.from_object.shndx = sym.get_st_shndx();
   this->type_ = sym.get_st_type();
@@ -35,22 +40,22 @@ template<int size>
 template<bool big_endian>
 void
 Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
-                            Object* object)
+                            Object* object, const char* version)
 {
-  this->override_base(sym, object);
+  this->override_base(sym, object, version);
   this->value_ = sym.get_st_value();
   this->symsize_ = sym.get_st_size();
 }
 
 // Resolve a symbol.  This is called the second and subsequent times
 // we see a symbol.  TO is the pre-existing symbol.  SYM is the new
-// symbol, seen in OBJECT.
+// symbol, seen in OBJECT.  VERSION of the version of SYM.
 
 template<int size, bool big_endian>
 void
 Symbol_table::resolve(Sized_symbol<size>* to,
                      const elfcpp::Sym<size, big_endian>& sym,
-                     Object* object)
+                     Object* object, const char* version)
 {
   if (object->target()->has_resolve())
     {
@@ -58,7 +63,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       sized_target = object->sized_target
                      SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
                          SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
-      sized_target->resolve(to, sym, object);
+      sized_target->resolve(to, sym, object, version);
       return;
     }
 
@@ -212,7 +217,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       // are currently compatible with the GNU linker.  In the future
       // we should add a target specific option to change this.
       // FIXME.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case DYN_DEF * 16 + DEF:
@@ -221,7 +226,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       // definition in a regular object.  The definition in the
       // regular object overrides the definition in the dynamic
       // object.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case UNDEF * 16 + DEF:
@@ -230,7 +235,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_UNDEF * 16 + DEF:
       // We've seen an undefined reference, and now we see a
       // definition.  We use the definition.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + DEF:
@@ -238,9 +243,9 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_COMMON * 16 + DEF:
     case DYN_WEAK_COMMON * 16 + DEF:
       // We've seen a common symbol and now we see a definition.  The
-      // definition overrides.  FIXME: We should optionally issue a
+      // definition overrides.  FIXME: We should optionally issue, version a
       // warning.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case DEF * 16 + WEAK_DEF:
@@ -253,7 +258,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_DEF * 16 + WEAK_DEF:
       // We've seen a dynamic definition and now we see a regular weak
       // definition.  The regular weak definition overrides.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case UNDEF * 16 + WEAK_DEF:
@@ -261,7 +266,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + WEAK_DEF:
     case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
       // A weak definition of a currently undefined symbol.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + WEAK_DEF:
@@ -273,7 +278,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_COMMON * 16 + WEAK_DEF:
       // A weak definition does override a definition in a dynamic
       // object.  FIXME: We should optionally issue a warning.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case DEF * 16 + DYN_DEF:
@@ -288,7 +293,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + DYN_DEF:
     case DYN_WEAK_UNDEF * 16 + DYN_DEF:
       // Use a dynamic definition if we have a reference.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + DYN_DEF:
@@ -312,7 +317,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + DYN_WEAK_DEF:
     case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
       // Use a weak dynamic definition if we have a reference.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + DYN_WEAK_DEF:
@@ -335,7 +340,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + UNDEF:
     case DYN_WEAK_UNDEF * 16 + UNDEF:
       // A strong undef overrides a dynamic or weak undef.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + UNDEF:
@@ -399,7 +404,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_DEF * 16 + COMMON:
       // A common symbol does override a weak definition or a dynamic
       // definition.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case UNDEF * 16 + COMMON:
@@ -407,7 +412,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + COMMON:
     case DYN_WEAK_UNDEF * 16 + COMMON:
       // A common symbol is a definition for a reference.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + COMMON:
@@ -419,7 +424,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case WEAK_COMMON * 16 + COMMON:
       // I'm not sure just what a weak common symbol means, but
       // presumably it can be overridden by a regular common symbol.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case DYN_COMMON * 16 + COMMON:
@@ -427,7 +432,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       {
        // Use the real common symbol, but adjust the size if necessary.
        typename Sized_symbol<size>::Size_type symsize = to->symsize();
-       to->override(sym, object);
+       to->override(sym, object, version);
        if (to->symsize() < symsize)
          to->set_symsize(symsize);
       }
@@ -446,7 +451,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + WEAK_COMMON:
     case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
       // A weak common symbol is better than an undefined symbol.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + WEAK_COMMON:
@@ -470,7 +475,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + DYN_COMMON:
     case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
       // A dynamic common symbol is a definition of sorts.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + DYN_COMMON:
@@ -494,7 +499,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
       // I guess a weak common symbol is better than a definition.
-      to->override(sym, object);
+      to->override(sym, object, version);
       return;
 
     case COMMON * 16 + DYN_WEAK_COMMON:
@@ -520,27 +525,31 @@ void
 Symbol_table::resolve<32, true>(
     Sized_symbol<32>* to,
     const elfcpp::Sym<32, true>& sym,
-    Object* object);
+    Object* object,
+    const char* version);
 
 template
 void
 Symbol_table::resolve<32, false>(
     Sized_symbol<32>* to,
     const elfcpp::Sym<32, false>& sym,
-    Object* object);
+    Object* object,
+    const char* version);
 
 template
 void
 Symbol_table::resolve<64, true>(
     Sized_symbol<64>* to,
     const elfcpp::Sym<64, true>& sym,
-    Object* object);
+    Object* object,
+    const char* version);
 
 template
 void
 Symbol_table::resolve<64, false>(
     Sized_symbol<64>* to,
     const elfcpp::Sym<64, false>& sym,
-    Object* object);
+    Object* object,
+    const char* version);
 
 } // End namespace gold.
index ededad3ed819832d0746ac554edc5f6f3988cd70..5b61152652d568abacd90cc708a25ef2b8b8ef32 100644 (file)
@@ -248,8 +248,8 @@ Symbol_table::lookup(const char* name, const char* version) const
 
 template<int size, bool big_endian>
 void
-Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
-                      ACCEPT_SIZE_ENDIAN)
+Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
+                     const char* version ACCEPT_SIZE_ENDIAN)
 {
   unsigned char buf[elfcpp::Elf_sizes<size>::sym_size];
   elfcpp::Sym_write<size, big_endian> esym(buf);
@@ -259,7 +259,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
   esym.put_st_info(from->binding(), from->type());
   esym.put_st_other(from->visibility(), from->nonvis());
   esym.put_st_shndx(from->shndx());
-  Symbol_table::resolve(to, esym.sym(), from->object());
+  Symbol_table::resolve(to, esym.sym(), from->object(), version);
 }
 
 // Add one symbol from OBJECT to the symbol table.  NAME is symbol
@@ -328,7 +328,7 @@ Symbol_table::add_from_object(Object* object,
       was_undefined = ret->is_undefined();
       was_common = ret->is_common();
 
-      Symbol_table::resolve(ret, sym, object);
+      Symbol_table::resolve(ret, sym, object, version);
 
       if (def)
        {
@@ -347,7 +347,7 @@ Symbol_table::add_from_object(Object* object,
                insdef.first->second
                 SELECT_SIZE(size));
              Symbol_table::resolve SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
-               ret, sym2 SELECT_SIZE_ENDIAN(size, big_endian));
+               ret, sym2, version SELECT_SIZE_ENDIAN(size, big_endian));
              this->make_forwarder(insdef.first->second, ret);
              insdef.first->second = ret;
            }
@@ -363,12 +363,12 @@ Symbol_table::add_from_object(Object* object,
 
       if (def && !insdef.second)
        {
-         // We already have an entry for NAME/NULL.  Make
-         // NAME/VERSION point to it.
+         // We already have an entry for NAME/NULL.  If we override
+         // it, then change it to NAME/VERSION.
          ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (
               insdef.first->second
               SELECT_SIZE(size));
-         Symbol_table::resolve(ret, sym, object);
+         Symbol_table::resolve(ret, sym, object, version);
          ins.first->second = ret;
        }
       else
@@ -649,8 +649,8 @@ Symbol_table::add_from_dynobj(
 
 template<int size, bool big_endian>
 Sized_symbol<size>*
-Symbol_table::define_special_symbol(Target* target, const char* name,
-                                   bool only_if_ref
+Symbol_table::define_special_symbol(const Target* target, const char* name,
+                                   const char* version, bool only_if_ref
                                     ACCEPT_SIZE_ENDIAN)
 {
   gold_assert(this->size_ == size);
@@ -660,29 +660,34 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
 
   if (only_if_ref)
     {
-      oldsym = this->lookup(name, NULL);
+      oldsym = this->lookup(name, version);
       if (oldsym == NULL || !oldsym->is_undefined())
        return NULL;
       sym = NULL;
 
-      // Canonicalize NAME.
+      // Canonicalize NAME and VERSION.
       name = oldsym->name();
+      version = oldsym->version();
     }
   else
     {
-      // Canonicalize NAME.
+      // Canonicalize NAME and VERSION.
       Stringpool::Key name_key;
       name = this->namepool_.add(name, &name_key);
 
+      Stringpool::Key version_key = 0;
+      if (version != NULL)
+       version = this->namepool_.add(version, &version_key);
+
       Symbol* const snull = NULL;
-      const Stringpool::Key ver_key = 0;
       std::pair<typename Symbol_table_type::iterator, bool> ins =
-       this->table_.insert(std::make_pair(std::make_pair(name_key, ver_key),
+       this->table_.insert(std::make_pair(std::make_pair(name_key,
+                                                         version_key),
                                           snull));
 
       if (!ins.second)
        {
-         // We already have a symbol table entry for NAME.
+         // We already have a symbol table entry for NAME/VERSION.
          oldsym = ins.first->second;
          gold_assert(oldsym != NULL);
          sym = NULL;
@@ -699,7 +704,8 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
              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);
+             const My_target* sized_target =
+               static_cast<const My_target*>(target);
              sym = sized_target->make_symbol();
              if (sym == NULL)
                return NULL;
@@ -737,9 +743,9 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
 
 // Define a symbol based on an Output_data.
 
-void
-Symbol_table::define_in_output_data(Target* target, const char* name,
-                                   Output_data* od,
+Symbol*
+Symbol_table::define_in_output_data(const Target* target, const char* name,
+                                   const char* version, Output_data* od,
                                    uint64_t value, uint64_t symsize,
                                    elfcpp::STT type, elfcpp::STB binding,
                                    elfcpp::STV visibility,
@@ -749,13 +755,15 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
 {
   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,
-                                      offset_is_from_end, only_if_ref);
+    return this->do_define_in_output_data<32>(target, name, version, od, value,
+                                             symsize, type, binding,
+                                             visibility, nonvis,
+                                             offset_is_from_end, only_if_ref);
   else if (this->size_ == 64)
-    this->do_define_in_output_data<64>(target, name, od, value, symsize,
-                                      type, binding, visibility, nonvis,
-                                      offset_is_from_end, only_if_ref);
+    return this->do_define_in_output_data<64>(target, name, version, od, value,
+                                             symsize, type, binding,
+                                             visibility, nonvis,
+                                             offset_is_from_end, only_if_ref);
   else
     gold_unreachable();
 }
@@ -763,10 +771,11 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
 // Define a symbol in an Output_data, sized version.
 
 template<int size>
-void
+Sized_symbol<size>*
 Symbol_table::do_define_in_output_data(
-    Target* target,
+    const Target* target,
     const char* name,
+    const char* version,
     Output_data* od,
     typename elfcpp::Elf_types<size>::Elf_Addr value,
     typename elfcpp::Elf_types<size>::Elf_WXword symsize,
@@ -781,25 +790,27 @@ Symbol_table::do_define_in_output_data(
 
   if (target->is_big_endian())
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, name, only_if_ref
+       target, name, version, only_if_ref
         SELECT_SIZE_ENDIAN(size, true));
   else
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, name, only_if_ref
+        target, name, version, only_if_ref
         SELECT_SIZE_ENDIAN(size, false));
 
   if (sym == NULL)
-    return;
+    return NULL;
 
   sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
            offset_is_from_end);
+
+  return sym;
 }
 
 // Define a symbol based on an Output_segment.
 
-void
-Symbol_table::define_in_output_segment(Target* target, const char* name,
-                                      Output_segment* os,
+Symbol*
+Symbol_table::define_in_output_segment(const Target* target, const char* name,
+                                      const char* version, Output_segment* os,
                                       uint64_t value, uint64_t symsize,
                                       elfcpp::STT type, elfcpp::STB binding,
                                       elfcpp::STV visibility,
@@ -809,13 +820,15 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
 {
   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,
-                                         offset_base, only_if_ref);
+    return this->do_define_in_output_segment<32>(target, name, version, os,
+                                                value, symsize, type, binding,
+                                                visibility, nonvis,
+                                                offset_base, only_if_ref);
   else if (this->size_ == 64)
-    this->do_define_in_output_segment<64>(target, name, os, value, symsize,
-                                         type, binding, visibility, nonvis,
-                                         offset_base, only_if_ref);
+    return this->do_define_in_output_segment<64>(target, name, version, os,
+                                                value, symsize, type, binding,
+                                                visibility, nonvis,
+                                                offset_base, only_if_ref);
   else
     gold_unreachable();
 }
@@ -823,10 +836,11 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
 // Define a symbol in an Output_segment, sized version.
 
 template<int size>
-void
+Sized_symbol<size>*
 Symbol_table::do_define_in_output_segment(
-    Target* target,
+    const Target* target,
     const char* name,
+    const char* version,
     Output_segment* os,
     typename elfcpp::Elf_types<size>::Elf_Addr value,
     typename elfcpp::Elf_types<size>::Elf_WXword symsize,
@@ -841,39 +855,41 @@ Symbol_table::do_define_in_output_segment(
 
   if (target->is_big_endian())
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, name, only_if_ref
+        target, name, version, only_if_ref
         SELECT_SIZE_ENDIAN(size, true));
   else
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, name, only_if_ref
+        target, name, version, only_if_ref
         SELECT_SIZE_ENDIAN(size, false));
 
   if (sym == NULL)
-    return;
+    return NULL;
 
   sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
            offset_base);
+
+  return sym;
 }
 
 // Define a special symbol with a constant value.  It is a multiple
 // definition error if this symbol is already defined.
 
-void
-Symbol_table::define_as_constant(Target* target, const char* name,
-                                uint64_t value, uint64_t symsize,
-                                elfcpp::STT type, elfcpp::STB binding,
-                                elfcpp::STV visibility, unsigned char nonvis,
-                                bool only_if_ref)
+Symbol*
+Symbol_table::define_as_constant(const Target* target, const char* name,
+                                const char* version, uint64_t value,
+                                uint64_t symsize, elfcpp::STT type,
+                                elfcpp::STB binding, elfcpp::STV visibility,
+                                unsigned char nonvis, bool only_if_ref)
 {
   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,
-                                   only_if_ref);
+    return this->do_define_as_constant<32>(target, name, version, value,
+                                          symsize, type, binding, visibility,
+                                          nonvis, only_if_ref);
   else if (this->size_ == 64)
-    this->do_define_as_constant<64>(target, name, value, symsize,
-                                   type, binding, visibility, nonvis,
-                                   only_if_ref);
+    return this->do_define_as_constant<64>(target, name, version, value,
+                                          symsize, type, binding, visibility,
+                                          nonvis, only_if_ref);
   else
     gold_unreachable();
 }
@@ -881,10 +897,11 @@ Symbol_table::define_as_constant(Target* target, const char* name,
 // Define a symbol as a constant, sized version.
 
 template<int size>
-void
+Sized_symbol<size>*
 Symbol_table::do_define_as_constant(
-    Target* target,
+    const Target* target,
     const char* name,
+    const char* version,
     typename elfcpp::Elf_types<size>::Elf_Addr value,
     typename elfcpp::Elf_types<size>::Elf_WXword symsize,
     elfcpp::STT type,
@@ -897,35 +914,37 @@ Symbol_table::do_define_as_constant(
 
   if (target->is_big_endian())
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, name, only_if_ref
+        target, name, version, only_if_ref
         SELECT_SIZE_ENDIAN(size, true));
   else
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, name, only_if_ref
+        target, name, version, only_if_ref
         SELECT_SIZE_ENDIAN(size, false));
 
   if (sym == NULL)
-    return;
+    return NULL;
 
   sym->init(name, value, symsize, type, binding, visibility, nonvis);
+
+  return sym;
 }
 
 // Define a set of symbols in output sections.
 
 void
-Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
-                            const Define_symbol_in_section* p)
+Symbol_table::define_symbols(const Layout* layout, const Target* target,
+                            int count, const Define_symbol_in_section* p)
 {
   for (int i = 0; i < count; ++i, ++p)
     {
       Output_section* os = layout->find_output_section(p->output_section);
       if (os != NULL)
-       this->define_in_output_data(target, p->name, os, p->value, p->size,
-                                   p->type, p->binding, p->visibility,
-                                   p->nonvis, p->offset_is_from_end,
-                                   p->only_if_ref);
+       this->define_in_output_data(target, p->name, NULL, os, p->value,
+                                   p->size, p->type, p->binding,
+                                   p->visibility, p->nonvis,
+                                   p->offset_is_from_end, p->only_if_ref);
       else
-       this->define_as_constant(target, p->name, 0, p->size, p->type,
+       this->define_as_constant(target, p->name, NULL, 0, p->size, p->type,
                                 p->binding, p->visibility, p->nonvis,
                                 p->only_if_ref);
     }
@@ -934,8 +953,8 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
 // Define a set of symbols in output segments.
 
 void
-Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
-                            const Define_symbol_in_segment* p)
+Symbol_table::define_symbols(const Layout* layout, const Target* target,
+                            int count, const Define_symbol_in_segment* p)
 {
   for (int i = 0; i < count; ++i, ++p)
     {
@@ -943,12 +962,12 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
                                                       p->segment_flags_set,
                                                       p->segment_flags_clear);
       if (os != NULL)
-       this->define_in_output_segment(target, p->name, os, p->value, p->size,
-                                      p->type, p->binding, p->visibility,
-                                      p->nonvis, p->offset_base,
-                                      p->only_if_ref);
+       this->define_in_output_segment(target, p->name, NULL, os, p->value,
+                                      p->size, p->type, p->binding,
+                                      p->visibility, p->nonvis,
+                                      p->offset_base, p->only_if_ref);
       else
-       this->define_as_constant(target, p->name, 0, p->size, p->type,
+       this->define_as_constant(target, p->name, NULL, 0, p->size, p->type,
                                 p->binding, p->visibility, p->nonvis,
                                 p->only_if_ref);
     }
@@ -960,9 +979,12 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
 // updated dynamic symbol index.
 
 unsigned int
-Symbol_table::set_dynsym_indexes(unsigned int index,
+Symbol_table::set_dynsym_indexes(const General_options* options,
+                                const Target* target,
+                                unsigned int index,
                                 std::vector<Symbol*>* syms,
-                                Stringpool* dynpool)
+                                Stringpool* dynpool,
+                                Versions* versions)
 {
   for (Symbol_table_type::iterator p = this->table_.begin();
        p != this->table_.end();
@@ -982,9 +1004,17 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
          ++index;
          syms->push_back(sym);
          dynpool->add(sym->name(), NULL);
+
+         // Record any version information.
+         if (sym->version() != NULL)
+           versions->record_version(options, dynpool, sym);
        }
     }
 
+  // Finish up the versions.  In some cases this may add new dynamic
+  // symbols.
+  index = versions->finalize(target, this, index, syms);
+
   return index;
 }
 
index f7a5c4c65039d2532308a9f3e14316ea085170b0..6e4344d4be2260d44cb4da2fc507e486bea9d058 100644 (file)
@@ -24,6 +24,7 @@ class Sized_relobj;
 class Dynobj;
 template<int size, bool big_endian>
 class Sized_dynobj;
+class Versions;
 class Output_data;
 class Output_section;
 class Output_segment;
@@ -303,13 +304,11 @@ class Symbol
                && this->shndx() != elfcpp::SHN_COMMON));
   }
 
-  // Return whether this symbol is defined in a dynamic object.
+  // Return true if this symbol is from a dynamic object.
   bool
-  is_defined_in_dynobj() const
+  is_from_dynobj() const
   {
-    return (this->source_ == FROM_OBJECT
-           && this->object()->is_dynamic()
-           && this->is_defined());
+    return this->source_ == FROM_OBJECT && this->object()->is_dynamic();
   }
 
   // Return whether this is an undefined symbol.
@@ -376,7 +375,8 @@ class Symbol
   // Override existing symbol.
   template<int size, bool big_endian>
   void
-  override_base(const elfcpp::Sym<size, big_endian>&, Object* object);
+  override_base(const elfcpp::Sym<size, big_endian>&, Object* object,
+               const char* version);
 
  private:
   Symbol(const Symbol&);
@@ -518,7 +518,8 @@ class Sized_symbol : public Symbol
   // Override existing symbol.
   template<bool big_endian>
   void
-  override(const elfcpp::Sym<size, big_endian>&, Object* object);
+  override(const elfcpp::Sym<size, big_endian>&, Object* object,
+          const char* version);
 
   // Return the symbol's value.
   Value_type
@@ -730,25 +731,20 @@ class Symbol_table
                  const unsigned char* versym, size_t versym_size,
                  const std::vector<const char*>*);
 
-  // Define a special symbol.
-  template<int size, bool big_endian>
-  Sized_symbol<size>*
-  define_special_symbol(Target* target, const char* name, bool only_if_ref
-                        ACCEPT_SIZE_ENDIAN);
-
   // Define a special symbol based on an Output_data.  It is a
   // multiple definition error if this symbol is already defined.
-  void
-  define_in_output_data(Target*, const char* name, Output_data*,
-                       uint64_t value, uint64_t symsize,
+  Symbol*
+  define_in_output_data(const Target*, const char* name, const char* version,
+                       Output_data*, uint64_t value, uint64_t symsize,
                        elfcpp::STT type, elfcpp::STB binding,
                        elfcpp::STV visibility, unsigned char nonvis,
                        bool offset_is_from_end, bool only_if_ref);
 
   // Define a special symbol based on an Output_segment.  It is a
   // multiple definition error if this symbol is already defined.
-  void
-  define_in_output_segment(Target*, const char* name, Output_segment*,
+  Symbol*
+  define_in_output_segment(const Target*, const char* name,
+                          const char* version, Output_segment*,
                           uint64_t value, uint64_t symsize,
                           elfcpp::STT type, elfcpp::STB binding,
                           elfcpp::STV visibility, unsigned char nonvis,
@@ -756,20 +752,20 @@ class Symbol_table
 
   // Define a special symbol with a constant value.  It is a multiple
   // definition error if this symbol is already defined.
-  void
-  define_as_constant(Target*, const char* name, uint64_t value,
-                    uint64_t symsize, elfcpp::STT type, elfcpp::STB binding,
-                    elfcpp::STV visibility, unsigned char nonvis,
-                    bool only_if_ref);
+  Symbol*
+  define_as_constant(const Target*, const char* name, const char* version,
+                    uint64_t value, uint64_t symsize, elfcpp::STT type,
+                    elfcpp::STB binding, elfcpp::STV visibility,
+                    unsigned char nonvis, bool only_if_ref);
 
   // Define a set of symbols in output sections.
   void
-  define_symbols(const Layout*, Target*, int count,
+  define_symbols(const Layout*, const Target*, int count,
                 const Define_symbol_in_section*);
 
   // Define a set of symbols in output segments.
   void
-  define_symbols(const Layout*, Target*, int count,
+  define_symbols(const Layout*, const Target*, int count,
                 const Define_symbol_in_segment*);  
 
   // Look up a symbol.
@@ -824,8 +820,8 @@ class Symbol_table
   // 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*);
+  set_dynsym_indexes(const General_options*, const Target*, unsigned int index,
+                    std::vector<Symbol*>*, Stringpool*, Versions*);
 
   // Finalize the symbol table after we have set the final addresses
   // of all the input sections.  This sets the final symbol indexes,
@@ -874,17 +870,25 @@ class Symbol_table
   static void
   resolve(Sized_symbol<size>* to,
          const elfcpp::Sym<size, big_endian>& sym,
-         Object*);
+         Object*, const char* version);
 
   template<int size, bool big_endian>
   static void
-  resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
-          ACCEPT_SIZE_ENDIAN);
+  resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
+          const char* version ACCEPT_SIZE_ENDIAN);
+
+  // Define a special symbol.
+  template<int size, bool big_endian>
+  Sized_symbol<size>*
+  define_special_symbol(const Target* target, const char* name,
+                       const char* version, bool only_if_ref
+                       ACCEPT_SIZE_ENDIAN);
 
   // Define a symbol in an Output_data, sized version.
   template<int size>
-  void
-  do_define_in_output_data(Target*, const char* name, Output_data*,
+  Sized_symbol<size>*
+  do_define_in_output_data(const Target*, const char* name,
+                          const char* version, Output_data*,
                           typename elfcpp::Elf_types<size>::Elf_Addr value,
                           typename elfcpp::Elf_types<size>::Elf_WXword ssize,
                           elfcpp::STT type, elfcpp::STB binding,
@@ -893,9 +897,9 @@ class Symbol_table
 
   // Define a symbol in an Output_segment, sized version.
   template<int size>
-  void
+  Sized_symbol<size>*
   do_define_in_output_segment(
-    Target*, const char* name, Output_segment* os,
+    const Target*, const char* name, const char* version, Output_segment* os,
     typename elfcpp::Elf_types<size>::Elf_Addr value,
     typename elfcpp::Elf_types<size>::Elf_WXword ssize,
     elfcpp::STT type, elfcpp::STB binding,
@@ -904,9 +908,9 @@ class Symbol_table
 
   // Define a symbol as a constant, sized version.
   template<int size>
-  void
+  Sized_symbol<size>*
   do_define_as_constant(
-    Target*, const char* name,
+    const Target*, const char* name, const char* version,
     typename elfcpp::Elf_types<size>::Elf_Addr value,
     typename elfcpp::Elf_types<size>::Elf_WXword ssize,
     elfcpp::STT type, elfcpp::STB binding,
index 42bed9ed37df88d8bf4b9a0619695de9d74653e2..9181a93193d53fd5e4d5f673e48105ec56ac10ef 100644 (file)
@@ -145,15 +145,17 @@ class Sized_target : public Target
   // symbol table.  This will only be called if has_make_symbol()
   // returns true.
   virtual Sized_symbol<size>*
-  make_symbol()
+  make_symbol() const
   { gold_unreachable(); }
 
   // Resolve a symbol for the target.  This should be overridden by a
   // target which needs to take special action.  TO is the
   // pre-existing symbol.  SYM is the new symbol, seen in OBJECT.
-  // This will only be called if has_resolve() returns true.
+  // VERSION is the version of SYM.  This will only be called if
+  // has_resolve() returns true.
   virtual void
-  resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
+  resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*,
+         const char*)
   { gold_unreachable(); }
 
   // Scan the relocs for a section, and record any information