Keep track of weak aliases, so that overriding environ works.
authorIan Lance Taylor <iant@google.com>
Sun, 14 Oct 2007 15:35:27 +0000 (15:35 +0000)
committerIan Lance Taylor <iant@google.com>
Sun, 14 Oct 2007 15:35:27 +0000 (15:35 +0000)
gold/resolve.cc
gold/symtab.cc
gold/symtab.h

index b890ed0952c1e1a949b60a19a72503250744008f..8836a3afed7cf87c5e1c0019a01bfc4e350523c1 100644 (file)
@@ -71,6 +71,35 @@ Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
   this->symsize_ = sym.get_st_size();
 }
 
+// Override TOSYM with symbol FROMSYM, defined in OBJECT, with version
+// VERSION.  This handles all aliases of TOSYM.
+
+template<int size, bool big_endian>
+void
+Symbol_table::override(Sized_symbol<size>* tosym,
+                      const elfcpp::Sym<size, big_endian>& fromsym,
+                      Object* object, const char* version)
+{
+  tosym->override(fromsym, object, version);
+  if (tosym->has_alias())
+    {
+      Symbol* sym = this->weak_aliases_[tosym];
+      gold_assert(sym != NULL);
+      Sized_symbol<size>* ssym;
+      ssym = this->get_sized_symbol SELECT_SIZE_NAME(size) (sym
+                                                           SELECT_SIZE(size));
+      do
+       {
+         ssym->override(fromsym, object, version);
+         sym = this->weak_aliases_[ssym];
+         gold_assert(sym != NULL);
+         ssym = this->get_sized_symbol SELECT_SIZE_NAME(size) (
+                                               sym SELECT_SIZE(size));
+       }
+      while (ssym != tosym);
+    }
+}
+
 // The resolve functions build a little code for each symbol.
 // Bit 0: 0 for global, 1 for weak.
 // Bit 1: 0 for regular object, 1 for shared object
@@ -175,7 +204,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     {
       typename Sized_symbol<size>::Size_type tosize = to->symsize();
 
-      to->override(sym, object, version);
+      this->override(to, sym, object, version);
 
       if (adjust_common_sizes && tosize > to->symsize())
         to->set_symsize(tosize);
@@ -636,6 +665,34 @@ Sized_symbol<size>::override_with_special(const Sized_symbol<size>* from)
   this->symsize_ = from->symsize_;
 }
 
+// Override TOSYM with the special symbol FROMSYM.  This handles all
+// aliases of TOSYM.
+
+template<int size>
+void
+Symbol_table::override_with_special(Sized_symbol<size>* tosym,
+                                   const Sized_symbol<size>* fromsym)
+{
+  tosym->override_with_special(fromsym);
+  if (tosym->has_alias())
+    {
+      Symbol* sym = this->weak_aliases_[tosym];
+      gold_assert(sym != NULL);
+      Sized_symbol<size>* ssym;
+      ssym = this->get_sized_symbol SELECT_SIZE_NAME(size) (sym
+                                                           SELECT_SIZE(size));
+      do
+       {
+         ssym->override_with_special(fromsym);
+         sym = this->weak_aliases_[ssym];
+         gold_assert(sym != NULL);
+         ssym = this->get_sized_symbol SELECT_SIZE_NAME(size) (
+                                               sym SELECT_SIZE(size));
+       }
+      while (ssym != tosym);
+    }
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones needed for implemented
 // targets.
@@ -683,13 +740,15 @@ Symbol_table::resolve<64, true>(
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
 template
 void
-Sized_symbol<32>::override_with_special(const Sized_symbol<32>*);
+Symbol_table::override_with_special<32>(Sized_symbol<32>*,
+                                       const Sized_symbol<32>*);
 #endif
 
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
 template
 void
-Sized_symbol<64>::override_with_special(const Sized_symbol<64>*);
+Symbol_table::override_with_special<64>(Sized_symbol<64>*,
+                                       const Sized_symbol<64>*);
 #endif
 
 } // End namespace gold.
index 28729a88021431d197f3927295809b06c1b4556e..7e0af342a88c6388d671aec88b53f29f16e3b30c 100644 (file)
@@ -59,6 +59,7 @@ Symbol::init_fields(const char* name, const char* version,
   this->is_target_special_ = false;
   this->is_def_ = false;
   this->is_forwarder_ = false;
+  this->has_alias_ = false;
   this->needs_dynsym_entry_ = false;
   this->in_reg_ = false;
   this->in_dyn_ = false;
@@ -319,7 +320,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(), version);
+  this->resolve(to, esym.sym(), from->object(), version);
   if (from->in_reg())
     to->set_in_reg();
   if (from->in_dyn())
@@ -350,7 +351,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
 // forwarders.
 
 template<int size, bool big_endian>
-Symbol*
+Sized_symbol<size>*
 Symbol_table::add_from_object(Object* object,
                              const char *name,
                              Stringpool::Key name_key,
@@ -392,7 +393,7 @@ Symbol_table::add_from_object(Object* object,
       was_undefined = ret->is_undefined();
       was_common = ret->is_common();
 
-      Symbol_table::resolve(ret, sym, object, version);
+      this->resolve(ret, sym, object, version);
 
       if (def)
        {
@@ -432,7 +433,7 @@ Symbol_table::add_from_object(Object* object,
          ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (
               insdef.first->second
               SELECT_SIZE(size));
-         Symbol_table::resolve(ret, sym, object, version);
+         this->resolve(ret, sym, object, version);
          ins.first->second = ret;
        }
       else
@@ -541,7 +542,7 @@ Symbol_table::add_from_relobj(
       // this is the default version.
       const char* ver = strchr(name, '@');
 
-      Symbol* res;
+      Sized_symbol<size>* res;
       if (ver == NULL)
        {
          Stringpool::Key name_key;
@@ -598,6 +599,16 @@ Symbol_table::add_from_dynobj(
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
 
+  // We keep a list of all STT_OBJECT symbols, so that we can resolve
+  // weak aliases.  This is necessary because if the dynamic object
+  // provides the same variable under two names, one of which is a
+  // weak definition, and the regular object refers to the weak
+  // definition, we have to put both the weak definition and the
+  // strong definition into the dynamic symbol table.  Given a weak
+  // definition, the only way that we can find the corresponding
+  // strong definition, if any, is to search the symbol table.
+  std::vector<Sized_symbol<size>*> object_symbols;
+
   const unsigned char* p = syms;
   const unsigned char* vs = versym;
   for (size_t i = 0; i < count; ++i, p += sym_size, vs += 2)
@@ -618,79 +629,172 @@ Symbol_table::add_from_dynobj(
 
       const char* name = sym_names + st_name;
 
+      Sized_symbol<size>* res;
+
       if (versym == NULL)
        {
          Stringpool::Key name_key;
          name = this->namepool_.add(name, true, &name_key);
-         this->add_from_object(dynobj, name, name_key, NULL, 0,
-                               false, sym);
-         continue;
+         res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+                                     false, sym);
        }
+      else
+       {
+         // Read the version information.
 
-      // Read the version information.
+         unsigned int v = elfcpp::Swap<16, big_endian>::readval(vs);
 
-      unsigned int v = elfcpp::Swap<16, big_endian>::readval(vs);
+         bool hidden = (v & elfcpp::VERSYM_HIDDEN) != 0;
+         v &= elfcpp::VERSYM_VERSION;
 
-      bool hidden = (v & elfcpp::VERSYM_HIDDEN) != 0;
-      v &= elfcpp::VERSYM_VERSION;
+         // The Sun documentation says that V can be VER_NDX_LOCAL,
+         // or VER_NDX_GLOBAL, or a version index.  The meaning of
+         // VER_NDX_LOCAL is defined as "Symbol has local scope."
+         // The old GNU linker will happily generate VER_NDX_LOCAL
+         // for an undefined symbol.  I don't know what the Sun
+         // linker will generate.
 
-      // The Sun documentation says that V can be VER_NDX_LOCAL, or
-      // VER_NDX_GLOBAL, or a version index.  The meaning of
-      // VER_NDX_LOCAL is defined as "Symbol has local scope."  The
-      // old GNU linker will happily generate VER_NDX_LOCAL for an
-      // undefined symbol.  I don't know what the Sun linker will
-      // generate.
+         if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
+             && sym.get_st_shndx() != elfcpp::SHN_UNDEF)
+           {
+             // This symbol should not be visible outside the object.
+             continue;
+           }
 
-      if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
-          && sym.get_st_shndx() != elfcpp::SHN_UNDEF)
-       {
-         // This symbol should not be visible outside the object.
-         continue;
-       }
+         // At this point we are definitely going to add this symbol.
+         Stringpool::Key name_key;
+         name = this->namepool_.add(name, true, &name_key);
 
-      // At this point we are definitely going to add this symbol.
-      Stringpool::Key name_key;
-      name = this->namepool_.add(name, true, &name_key);
+         if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
+             || v == static_cast<unsigned int>(elfcpp::VER_NDX_GLOBAL))
+           {
+             // This symbol does not have a version.
+             res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+                                         false, sym);
+           }
+         else
+           {
+             if (v >= version_map->size())
+               {
+                 dynobj->error(_("versym for symbol %zu out of range: %u"),
+                               i, v);
+                 continue;
+               }
 
-      if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
-          || v == static_cast<unsigned int>(elfcpp::VER_NDX_GLOBAL))
-       {
-         // This symbol does not have a version.
-         this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym);
-         continue;
-       }
+             const char* version = (*version_map)[v];
+             if (version == NULL)
+               {
+                 dynobj->error(_("versym for symbol %zu has no name: %u"),
+                               i, v);
+                 continue;
+               }
 
-      if (v >= version_map->size())
-       {
-         dynobj->error(_("versym for symbol %zu out of range: %u"), i, v);
-         continue;
+             Stringpool::Key version_key;
+             version = this->namepool_.add(version, true, &version_key);
+
+             // If this is an absolute symbol, and the version name
+             // and symbol name are the same, then this is the
+             // version definition symbol.  These symbols exist to
+             // support using -u to pull in particular versions.  We
+             // do not want to record a version for them.
+             if (sym.get_st_shndx() == elfcpp::SHN_ABS
+                 && name_key == version_key)
+               res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+                                           false, sym);
+             else
+               {
+                 const bool def = (!hidden
+                                   && (sym.get_st_shndx()
+                                       != elfcpp::SHN_UNDEF));
+                 res = this->add_from_object(dynobj, name, name_key, version,
+                                             version_key, def, sym);
+               }
+           }
        }
 
-      const char* version = (*version_map)[v];
-      if (version == NULL)
-       {
-         dynobj->error(_("versym for symbol %zu has no name: %u"), i, v);
-         continue;
-       }
+      if (sym.get_st_shndx() != elfcpp::SHN_UNDEF
+         && sym.get_st_type() == elfcpp::STT_OBJECT)
+       object_symbols.push_back(res);
+    }
+
+  this->record_weak_aliases(&object_symbols);
+}
+
+// This is used to sort weak aliases.  We sort them first by section
+// index, then by offset, then by weak ahead of strong.
+
+template<int size>
+class Weak_alias_sorter
+{
+ public:
+  bool operator()(const Sized_symbol<size>*, const Sized_symbol<size>*) const;
+};
+
+template<int size>
+bool
+Weak_alias_sorter<size>::operator()(const Sized_symbol<size>* s1,
+                                   const Sized_symbol<size>* s2) const
+{
+  if (s1->shndx() != s2->shndx())
+    return s1->shndx() < s2->shndx();
+  if (s1->value() != s2->value())
+    return s1->value() < s2->value();
+  if (s1->binding() != s2->binding())
+    {
+      if (s1->binding() == elfcpp::STB_WEAK)
+       return true;
+      if (s2->binding() == elfcpp::STB_WEAK)
+       return false;
+    }
+  return std::string(s1->name()) < std::string(s2->name());
+}
 
-      Stringpool::Key version_key;
-      version = this->namepool_.add(version, true, &version_key);
+// SYMBOLS is a list of object symbols from a dynamic object.  Look
+// for any weak aliases, and record them so that if we add the weak
+// alias to the dynamic symbol table, we also add the corresponding
+// strong symbol.
 
-      // If this is an absolute symbol, and the version name and
-      // symbol name are the same, then this is the version definition
-      // symbol.  These symbols exist to support using -u to pull in
-      // particular versions.  We do not want to record a version for
-      // them.
-      if (sym.get_st_shndx() == elfcpp::SHN_ABS && name_key == version_key)
+template<int size>
+void
+Symbol_table::record_weak_aliases(std::vector<Sized_symbol<size>*>* symbols)
+{
+  // Sort the vector by section index, then by offset, then by weak
+  // ahead of strong.
+  std::sort(symbols->begin(), symbols->end(), Weak_alias_sorter<size>());
+
+  // Walk through the vector.  For each weak definition, record
+  // aliases.
+  for (typename std::vector<Sized_symbol<size>*>::const_iterator p =
+        symbols->begin();
+       p != symbols->end();
+       ++p)
+    {
+      if ((*p)->binding() != elfcpp::STB_WEAK)
+       continue;
+
+      // Build a circular list of weak aliases.  Each symbol points to
+      // the next one in the circular list.
+
+      Sized_symbol<size>* from_sym = *p;
+      typename std::vector<Sized_symbol<size>*>::const_iterator q;
+      for (q = p + 1; q != symbols->end(); ++q)
        {
-         this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym);
-         continue;
+         if ((*q)->shndx() != from_sym->shndx()
+             || (*q)->value() != from_sym->value())
+           break;
+
+         this->weak_aliases_[from_sym] = *q;
+         from_sym->set_has_alias();
+         from_sym = *q;
        }
 
-      const bool def = !hidden && sym.get_st_shndx() != elfcpp::SHN_UNDEF;
+      if (from_sym != *p)
+       {
+         this->weak_aliases_[from_sym] = *p;
+         from_sym->set_has_alias();
+       }
 
-      this->add_from_object(dynobj, name, name_key, version, version_key,
-                           def, sym);
+      p = q - 1;
     }
 }
 
@@ -868,7 +972,7 @@ Symbol_table::do_define_in_output_data(
 
   if (oldsym != NULL
       && Symbol_table::should_override_with_special(oldsym))
-    oldsym->override_with_special(sym);
+    this->override_with_special(oldsym, sym);
 
   return sym;
 }
@@ -962,7 +1066,7 @@ Symbol_table::do_define_in_output_segment(
 
   if (oldsym != NULL
       && Symbol_table::should_override_with_special(oldsym))
-    oldsym->override_with_special(sym);
+    this->override_with_special(oldsym, sym);
 
   return sym;
 }
@@ -1049,7 +1153,7 @@ Symbol_table::do_define_as_constant(
 
   if (oldsym != NULL
       && Symbol_table::should_override_with_special(oldsym))
-    oldsym->override_with_special(sym);
+    this->override_with_special(oldsym, sym);
 
   return sym;
 }
index b215f5d58eb1682f774b2411aa4eec5015b5d47d..b46510d4c9dd563e04438634d121e903d9725161 100644 (file)
@@ -195,6 +195,17 @@ class Symbol
   set_forwarder()
   { this->is_forwarder_ = true; }
 
+  // Return whether this symbol has an alias in the weak aliases table
+  // in Symbol_table.
+  bool
+  has_alias() const
+  { return this->has_alias_; }
+
+  // Mark this symbol as having an alias.
+  void
+  set_has_alias()
+  { this->has_alias_ = true; }
+
   // Return whether this symbol needs an entry in the dynamic symbol
   // table.
   bool
@@ -528,6 +539,9 @@ class Symbol
   // It forwards to the symbol found in the forwarders_ map of
   // Symbol_table.
   bool is_forwarder_ : 1;
+  // True if the symbol has an alias in the weak_aliases table in
+  // Symbol_table.
+  bool has_alias_ : 1;
   // True if this symbol needs to be in the dynamic symbol table.
   bool needs_dynsym_entry_ : 1;
   // True if we've seen this symbol in a regular object.
@@ -924,20 +938,20 @@ class Symbol_table
 
   // Add a symbol.
   template<int size, bool big_endian>
-  Symbol*
+  Sized_symbol<size>*
   add_from_object(Object*, const char *name, Stringpool::Key name_key,
                  const char *version, Stringpool::Key version_key,
                  bool def, const elfcpp::Sym<size, big_endian>& sym);
 
   // Resolve symbols.
   template<int size, bool big_endian>
-  static void
+  void
   resolve(Sized_symbol<size>* to,
          const elfcpp::Sym<size, big_endian>& sym,
          Object*, const char* version);
 
   template<int size, bool big_endian>
-  static void
+  void
   resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
           const char* version ACCEPT_SIZE_ENDIAN);
 
@@ -946,11 +960,29 @@ class Symbol_table
   static bool
   should_override(const Symbol*, unsigned int, Object*, bool*);
 
+  // Override a symbol.
+  template<int size, bool big_endian>
+  void
+  override(Sized_symbol<size>* tosym,
+          const elfcpp::Sym<size, big_endian>& fromsym,
+          Object* object, const char* version);
+
   // Whether we should override a symbol with a special symbol which
   // is automatically defined by the linker.
   static bool
   should_override_with_special(const Symbol*);
 
+  // Override a symbol with a special symbol.
+  template<int size>
+  void
+  override_with_special(Sized_symbol<size>* tosym,
+                       const Sized_symbol<size>* fromsym);
+
+  // Record all weak alias sets for a dynamic object.
+  template<int size>
+  void
+  record_weak_aliases(std::vector<Sized_symbol<size>*>*);
+
   // Define a special symbol.
   template<int size, bool big_endian>
   Sized_symbol<size>*
@@ -1077,6 +1109,10 @@ class Symbol_table
   // Forwarding symbols.
   Unordered_map<const Symbol*, Symbol*> forwarders_;
 
+  // Weak aliases.  A symbol in this list points to the next alias.
+  // The aliases point to each other in a circular list.
+  Unordered_map<Symbol*, Symbol*> weak_aliases_;
+
   // We don't expect there to be very many common symbols, so we keep
   // a list of them.  When we find a common symbol we add it to this
   // list.  It is possible that by the time we process the list the