Support special always-defined symbols for targets.
[binutils-gdb.git] / gold / symtab.cc
index c68b9ca5eb270fd3b3b09332f7845d4295ae1c7e..24430237d62865b7ef9544916517df8d9c54cb6c 100644 (file)
 #include "gold.h"
 
 #include <stdint.h>
+#include <set>
 #include <string>
 #include <utility>
 
 #include "object.h"
+#include "dwarf_reader.h"
 #include "dynobj.h"
 #include "output.h"
 #include "target.h"
@@ -59,12 +61,15 @@ 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;
   this->has_got_offset_ = false;
   this->has_plt_offset_ = false;
   this->has_warning_ = false;
+  this->is_copied_from_dynobj_ = false;
+  this->needs_value_in_got_ = false;
 }
 
 // Initialize the fields in the base class Symbol for SYM in OBJECT.
@@ -187,10 +192,64 @@ Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
   this->symsize_ = symsize;
 }
 
+// Return true if this symbol should be added to the dynamic symbol
+// table.
+
+inline bool
+Symbol::should_add_dynsym_entry() const
+{
+  // If the symbol is used by a dynamic relocation, we need to add it.
+  if (this->needs_dynsym_entry())
+    return true;
+
+  // If exporting all symbols or building a shared library,
+  // and the symbol is defined in a regular object and is
+  // externally visible, we need to add it.
+  if ((parameters->export_dynamic() || parameters->output_is_shared())
+      && !this->is_from_dynobj()
+      && this->is_externally_visible())
+    return true;
+
+  return false;
+}
+
+// Return true if the final value of this symbol is known at link
+// time.
+
+bool
+Symbol::final_value_is_known() const
+{
+  // If we are not generating an executable, then no final values are
+  // known, since they will change at runtime.
+  if (!parameters->output_is_executable())
+    return false;
+
+  // If the symbol is not from an object file, then it is defined, and
+  // known.
+  if (this->source_ != FROM_OBJECT)
+    return true;
+
+  // If the symbol is from a dynamic object, then the final value is
+  // not known.
+  if (this->object()->is_dynamic())
+    return false;
+
+  // If the symbol is not undefined (it is defined or common), then
+  // the final value is known.
+  if (!this->is_undefined())
+    return true;
+
+  // If the symbol is undefined, then whether the final value is known
+  // depends on whether we are doing a static link.  If we are doing a
+  // dynamic link, then the final value could be filled in at runtime.
+  // This could reasonably be the case for a weak undefined symbol.
+  return parameters->doing_static_link();
+}
+
 // Class Symbol_table.
 
 Symbol_table::Symbol_table()
-  : size_(0), saw_undefined_(0), offset_(0), table_(), namepool_(),
+  : saw_undefined_(0), offset_(0), table_(), namepool_(),
     forwarders_(), commons_(), warnings_()
 {
 }
@@ -286,7 +345,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(), esym.sym(), from->object(), version);
   if (from->in_reg())
     to->set_in_reg();
   if (from->in_dyn())
@@ -315,16 +374,22 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
 // object file as a forwarder, and record it in the forwarders_ map.
 // Note that entries in the hash table will never be marked as
 // forwarders.
+//
+// SYM and ORIG_SYM are almost always the same.  ORIG_SYM is the
+// symbol exactly as it existed in the input file.  SYM is usually
+// that as well, but can be modified, for instance if we determine
+// it's in a to-be-discarded section.
 
 template<int size, bool big_endian>
-Symbol*
+Sized_symbol<size>*
 Symbol_table::add_from_object(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)
+                             const elfcpp::Sym<size, big_endian>& sym,
+                             const elfcpp::Sym<size, big_endian>& orig_sym)
 {
   Symbol* const snull = NULL;
   std::pair<typename Symbol_table_type::iterator, bool> ins =
@@ -359,7 +424,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, orig_sym, object, version);
 
       if (def)
        {
@@ -399,7 +464,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, orig_sym, object, version);
          ins.first->second = ret;
        }
       else
@@ -465,18 +530,10 @@ Symbol_table::add_from_relobj(
     size_t count,
     const char* sym_names,
     size_t sym_name_size,
-    Symbol** sympointers)
+    typename Sized_relobj<size, big_endian>::Symbols* sympointers)
 {
-  // We take the size from the first object we see.
-  if (this->get_size() == 0)
-    this->set_size(size);
-
-  if (size != this->get_size() || size != relobj->target()->get_size())
-    {
-      fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
-             program_name, relobj->name().c_str());
-      gold_exit(false);
-    }
+  gold_assert(size == relobj->target()->get_size());
+  gold_assert(size == parameters->get_size());
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
 
@@ -489,11 +546,9 @@ Symbol_table::add_from_relobj(
       unsigned int st_name = psym->get_st_name();
       if (st_name >= sym_name_size)
        {
-         fprintf(stderr,
-                 _("%s: %s: bad global symbol name offset %u at %lu\n"),
-                 program_name, relobj->name().c_str(), st_name,
-                 static_cast<unsigned long>(i));
-         gold_exit(false);
+         relobj->error(_("bad global symbol name offset %u at %zu"),
+                       st_name, i);
+         continue;
        }
 
       const char* name = sym_names + st_name;
@@ -518,18 +573,18 @@ 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;
-         name = this->namepool_.add(name, &name_key);
+         name = this->namepool_.add(name, true, &name_key);
          res = this->add_from_object(relobj, name, name_key, NULL, 0,
-                                     false, *psym);
+                                     false, *psym, sym);
        }
       else
        {
          Stringpool::Key name_key;
-         name = this->namepool_.add(name, ver - name, &name_key);
+         name = this->namepool_.add_prefix(name, ver - name, &name_key);
 
          bool def = false;
          ++ver;
@@ -540,13 +595,13 @@ Symbol_table::add_from_relobj(
            }
 
          Stringpool::Key ver_key;
-         ver = this->namepool_.add(ver, &ver_key);
+         ver = this->namepool_.add(ver, true, &ver_key);
 
          res = this->add_from_object(relobj, name, name_key, ver, ver_key,
-                                     def, *psym);
+                                     def, *psym, sym);
        }
 
-      *sympointers++ = res;
+      (*sympointers)[i] = res;
     }
 }
 
@@ -564,26 +619,27 @@ Symbol_table::add_from_dynobj(
     size_t versym_size,
     const std::vector<const char*>* version_map)
 {
-  // We take the size from the first object we see.
-  if (this->get_size() == 0)
-    this->set_size(size);
-
-  if (size != this->get_size() || size != dynobj->target()->get_size())
-    {
-      fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
-             program_name, dynobj->name().c_str());
-      gold_exit(false);
-    }
+  gold_assert(size == dynobj->target()->get_size());
+  gold_assert(size == parameters->get_size());
 
   if (versym != NULL && versym_size / 2 < count)
     {
-      fprintf(stderr, _("%s: %s: too few symbol versions\n"),
-             program_name, dynobj->name().c_str());
-      gold_exit(false);
+      dynobj->error(_("too few symbol versions"));
+      return;
     }
 
   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)
@@ -597,90 +653,179 @@ Symbol_table::add_from_dynobj(
       unsigned int st_name = sym.get_st_name();
       if (st_name >= sym_name_size)
        {
-         fprintf(stderr, _("%s: %s: bad symbol name offset %u at %lu\n"),
-                 program_name, dynobj->name().c_str(), st_name,
-                 static_cast<unsigned long>(i));
-         gold_exit(false);
+         dynobj->error(_("bad symbol name offset %u at %zu"),
+                       st_name, i);
+         continue;
        }
 
       const char* name = sym_names + st_name;
 
+      Sized_symbol<size>* res;
+
       if (versym == NULL)
        {
          Stringpool::Key name_key;
-         name = this->namepool_.add(name, &name_key);
-         this->add_from_object(dynobj, name, name_key, NULL, 0,
-                               false, sym);
-         continue;
+         name = this->namepool_.add(name, true, &name_key);
+         res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+                                     false, sym, 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, &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, 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())
-       {
-         fprintf(stderr,
-                 _("%s: %s: versym for symbol %zu out of range: %u\n"),
-                 program_name, dynobj->name().c_str(), i, v);
-         gold_exit(false);
+             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, 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, sym);
+               }
+           }
        }
 
-      const char* version = (*version_map)[v];
-      if (version == NULL)
-       {
-         fprintf(stderr, _("%s: %s: versym for symbol %zu has no name: %u\n"),
-                 program_name, dynobj->name().c_str(), i, v);
-         gold_exit(false);
-       }
+      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.
 
-      Stringpool::Key version_key;
-      version = this->namepool_.add(version, &version_key);
+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());
+}
 
-      // 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)
+// 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.
+
+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;
     }
 }
 
@@ -696,8 +841,6 @@ Symbol_table::define_special_symbol(const Target* target, const char** pname,
                                     Sized_symbol<size>** poldsym
                                     ACCEPT_SIZE_ENDIAN)
 {
-  gold_assert(this->size_ == size);
-
   Symbol* oldsym;
   Sized_symbol<size>* sym;
   bool add_to_table = false;
@@ -716,11 +859,11 @@ Symbol_table::define_special_symbol(const Target* target, const char** pname,
     {
       // Canonicalize NAME and VERSION.
       Stringpool::Key name_key;
-      *pname = this->namepool_.add(*pname, &name_key);
+      *pname = this->namepool_.add(*pname, true, &name_key);
 
       Stringpool::Key version_key = 0;
       if (*pversion != NULL)
-       *pversion = this->namepool_.add(*pversion, &version_key);
+       *pversion = this->namepool_.add(*pversion, true, &version_key);
 
       Symbol* const snull = NULL;
       std::pair<typename Symbol_table_type::iterator, bool> ins =
@@ -781,8 +924,7 @@ Symbol_table::define_in_output_data(const Target* target, const char* name,
                                    bool offset_is_from_end,
                                    bool only_if_ref)
 {
-  gold_assert(target->get_size() == this->size_);
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
       return this->do_define_in_output_data<32>(target, name, version, od,
@@ -794,7 +936,7 @@ Symbol_table::define_in_output_data(const Target* target, const char* name,
       gold_unreachable();
 #endif
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
       return this->do_define_in_output_data<64>(target, name, version, od,
@@ -831,7 +973,7 @@ Symbol_table::do_define_in_output_data(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
 
-  if (target->is_big_endian())
+  if (parameters->is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
@@ -861,7 +1003,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;
 }
@@ -878,8 +1020,7 @@ Symbol_table::define_in_output_segment(const Target* target, const char* name,
                                       Symbol::Segment_offset_base offset_base,
                                       bool only_if_ref)
 {
-  gold_assert(target->get_size() == this->size_);
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
       return this->do_define_in_output_segment<32>(target, name, version, os,
@@ -890,7 +1031,7 @@ Symbol_table::define_in_output_segment(const Target* target, const char* name,
       gold_unreachable();
 #endif
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
       return this->do_define_in_output_segment<64>(target, name, version, os,
@@ -926,14 +1067,26 @@ Symbol_table::do_define_in_output_segment(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
 
-  if (target->is_big_endian())
-    sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, &name, &version, only_if_ref, &oldsym
-        SELECT_SIZE_ENDIAN(size, true));
+  if (parameters->is_big_endian())
+    {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+      sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
+          target, &name, &version, only_if_ref, &oldsym
+          SELECT_SIZE_ENDIAN(size, true));
+#else
+      gold_unreachable();
+#endif
+    }
   else
-    sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, &name, &version, only_if_ref, &oldsym
-        SELECT_SIZE_ENDIAN(size, false));
+    {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+      sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
+          target, &name, &version, only_if_ref, &oldsym
+          SELECT_SIZE_ENDIAN(size, false));
+#else
+      gold_unreachable();
+#endif
+    }
 
   if (sym == NULL)
     return NULL;
@@ -944,7 +1097,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;
 }
@@ -959,8 +1112,7 @@ Symbol_table::define_as_constant(const Target* target, const char* name,
                                 elfcpp::STB binding, elfcpp::STV visibility,
                                 unsigned char nonvis, bool only_if_ref)
 {
-  gold_assert(target->get_size() == this->size_);
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
       return this->do_define_as_constant<32>(target, name, version, value,
@@ -970,7 +1122,7 @@ Symbol_table::define_as_constant(const Target* target, const char* name,
       gold_unreachable();
 #endif
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
       return this->do_define_as_constant<64>(target, name, version, value,
@@ -1003,14 +1155,26 @@ Symbol_table::do_define_as_constant(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
 
-  if (target->is_big_endian())
-    sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, &name, &version, only_if_ref, &oldsym
-        SELECT_SIZE_ENDIAN(size, true));
+  if (parameters->is_big_endian())
+    {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+      sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
+          target, &name, &version, only_if_ref, &oldsym
+          SELECT_SIZE_ENDIAN(size, true));
+#else
+      gold_unreachable();
+#endif
+    }
   else
-    sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, &name, &version, only_if_ref, &oldsym
-        SELECT_SIZE_ENDIAN(size, false));
+    {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+      sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
+          target, &name, &version, only_if_ref, &oldsym
+          SELECT_SIZE_ENDIAN(size, false));
+#else
+      gold_unreachable();
+#endif
+    }
 
   if (sym == NULL)
     return NULL;
@@ -1020,7 +1184,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;
 }
@@ -1069,14 +1233,77 @@ Symbol_table::define_symbols(const Layout* layout, const Target* target,
     }
 }
 
+// Define CSYM using a COPY reloc.  POSD is the Output_data where the
+// symbol should be defined--typically a .dyn.bss section.  VALUE is
+// the offset within POSD.
+
+template<int size>
+void
+Symbol_table::define_with_copy_reloc(const Target* target,
+                                    Sized_symbol<size>* csym,
+                                    Output_data* posd, uint64_t value)
+{
+  gold_assert(csym->is_from_dynobj());
+  gold_assert(!csym->is_copied_from_dynobj());
+  Object* object = csym->object();
+  gold_assert(object->is_dynamic());
+  Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+  // Our copied variable has to override any variable in a shared
+  // library.
+  elfcpp::STB binding = csym->binding();
+  if (binding == elfcpp::STB_WEAK)
+    binding = elfcpp::STB_GLOBAL;
+
+  this->define_in_output_data(target, csym->name(), csym->version(),
+                             posd, value, csym->symsize(),
+                             csym->type(), binding,
+                             csym->visibility(), csym->nonvis(),
+                             false, false);
+
+  csym->set_is_copied_from_dynobj();
+  csym->set_needs_dynsym_entry();
+
+  this->copied_symbol_dynobjs_[csym] = dynobj;
+
+  // We have now defined all aliases, but we have not entered them all
+  // in the copied_symbol_dynobjs_ map.
+  if (csym->has_alias())
+    {
+      Symbol* sym = csym;
+      while (true)
+       {
+         sym = this->weak_aliases_[sym];
+         if (sym == csym)
+           break;
+         gold_assert(sym->output_data() == posd);
+
+         sym->set_is_copied_from_dynobj();
+         this->copied_symbol_dynobjs_[sym] = dynobj;
+       }
+    }
+}
+
+// SYM is defined using a COPY reloc.  Return the dynamic object where
+// the original definition was found.
+
+Dynobj*
+Symbol_table::get_copy_source(const Symbol* sym) const
+{
+  gold_assert(sym->is_copied_from_dynobj());
+  Copied_symbol_dynobjs::const_iterator p =
+    this->copied_symbol_dynobjs_.find(sym);
+  gold_assert(p != this->copied_symbol_dynobjs_.end());
+  return p->second;
+}
+
 // Set the dynamic symbol indexes.  INDEX is the index of the first
 // global dynamic symbol.  Pointers to the symbols are stored into the
 // vector SYMS.  The names are added to DYNPOOL.  This returns an
 // updated dynamic symbol index.
 
 unsigned int
-Symbol_table::set_dynsym_indexes(const General_options* options,
-                                const Target* target,
+Symbol_table::set_dynsym_indexes(const Target* target,
                                 unsigned int index,
                                 std::vector<Symbol*>* syms,
                                 Stringpool* dynpool,
@@ -1092,21 +1319,18 @@ Symbol_table::set_dynsym_indexes(const General_options* options,
       // some symbols appear more than once in the symbol table, with
       // and without a version.
 
-      if (!sym->needs_dynsym_entry()
-          && (!options->export_dynamic()
-              || !sym->in_reg()
-              || !sym->is_externally_visible()))
+      if (!sym->should_add_dynsym_entry())
        sym->set_dynsym_index(-1U);
       else if (!sym->has_dynsym_index())
        {
          sym->set_dynsym_index(index);
          ++index;
          syms->push_back(sym);
-         dynpool->add(sym->name(), NULL);
+         dynpool->add(sym->name(), false, NULL);
 
          // Record any version information.
          if (sym->version() != NULL)
-           versions->record_version(options, dynpool, sym);
+           versions->record_version(this, dynpool, sym);
        }
     }
 
@@ -1135,10 +1359,22 @@ Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff,
   this->first_dynamic_global_index_ = dyn_global_index;
   this->dynamic_count_ = dyncount;
 
-  if (this->size_ == 32)
-    ret = this->sized_finalize<32>(index, off, pool);
-  else if (this->size_ == 64)
-    ret = this->sized_finalize<64>(index, off, pool);
+  if (parameters->get_size() == 32)
+    {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_32_LITTLE)
+      ret = this->sized_finalize<32>(index, off, pool);
+#else
+      gold_unreachable();
+#endif
+    }
+  else if (parameters->get_size() == 64)
+    {
+#if defined(HAVE_TARGET_64_BIG) || defined(HAVE_TARGET_64_LITTLE)
+      ret = this->sized_finalize<64>(index, off, pool);
+#else
+      gold_unreachable();
+#endif
+    }
   else
     gold_unreachable();
 
@@ -1197,9 +1433,9 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
            if (shndx >= elfcpp::SHN_LORESERVE
                && shndx != elfcpp::SHN_ABS)
              {
-               fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
-                       program_name, sym->name(), shndx);
-               gold_exit(false);
+               gold_error(_("%s: unsupported symbol section 0x%x"),
+                          sym->name(), shndx);
+               shndx = elfcpp::SHN_UNDEF;
              }
 
            Object* symobj = sym->object();
@@ -1268,10 +1504,16 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
        }
 
       sym->set_value(value);
-      sym->set_symtab_index(index);
-      pool->add(sym->name(), NULL);
-      ++index;
-      off += sym_size;
+
+      if (parameters->strip_all())
+       sym->set_symtab_index(-1U);
+      else
+       {
+         sym->set_symtab_index(index);
+         pool->add(sym->name(), false, NULL);
+         ++index;
+         off += sym_size;
+       }
     }
 
   this->output_count_ = index - orig_index;
@@ -1285,19 +1527,43 @@ void
 Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
                            const Stringpool* dynpool, Output_file* of) const
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (target->is_big_endian())
-       this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (target->is_big_endian())
-       this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -1333,6 +1599,27 @@ Symbol_table::sized_write_globals(const Target* target,
     {
       Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
 
+      // Optionally check for unresolved symbols in shared libraries.
+      // This is controlled by the --allow-shlib-undefined option.  We
+      // only warn about libraries for which we have seen all the
+      // DT_NEEDED entries.  We don't try to track down DT_NEEDED
+      // entries which were not seen in this link.  If we didn't see a
+      // DT_NEEDED entry, we aren't going to be able to reliably
+      // report whether the symbol is undefined.
+      if (sym->source() == Symbol::FROM_OBJECT
+          && sym->object()->is_dynamic()
+          && sym->shndx() == elfcpp::SHN_UNDEF
+         && sym->binding() != elfcpp::STB_WEAK
+         && !parameters->allow_shlib_undefined()
+         && !target->is_always_defined(sym))
+       {
+         // A very ugly cast.
+         Dynobj* dynobj = static_cast<Dynobj*>(sym->object());
+         if (!dynobj->has_unknown_needed_entries())
+           gold_error(_("%s: undefined reference to '%s'"),
+                      sym->object()->name().c_str(), sym->name());
+       }
+
       unsigned int sym_index = sym->symtab_index();
       unsigned int dynsym_index;
       if (dynamic_view == NULL)
@@ -1370,28 +1657,31 @@ Symbol_table::sized_write_globals(const Target* target,
            if (in_shndx >= elfcpp::SHN_LORESERVE
                && in_shndx != elfcpp::SHN_ABS)
              {
-               fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
-                       program_name, sym->name(), in_shndx);
-               gold_exit(false);
-             }
-
-           Object* symobj = sym->object();
-           if (symobj->is_dynamic())
-             {
-               if (sym->needs_dynsym_value())
-                 value = target->dynsym_value(sym);
-               shndx = elfcpp::SHN_UNDEF;
+               gold_error(_("%s: unsupported symbol section 0x%x"),
+                          sym->name(), in_shndx);
+               shndx = in_shndx;
              }
-           else if (in_shndx == elfcpp::SHN_UNDEF
-                    || in_shndx == elfcpp::SHN_ABS)
-             shndx = in_shndx;
            else
              {
-               Relobj* relobj = static_cast<Relobj*>(symobj);
-               off_t secoff;
-               Output_section* os = relobj->output_section(in_shndx, &secoff);
-               gold_assert(os != NULL);
-               shndx = os->out_shndx();
+               Object* symobj = sym->object();
+               if (symobj->is_dynamic())
+                 {
+                   if (sym->needs_dynsym_value())
+                     value = target->dynsym_value(sym);
+                   shndx = elfcpp::SHN_UNDEF;
+                 }
+               else if (in_shndx == elfcpp::SHN_UNDEF
+                        || in_shndx == elfcpp::SHN_ABS)
+                 shndx = in_shndx;
+               else
+                 {
+                   Relobj* relobj = static_cast<Relobj*>(symobj);
+                   off_t secoff;
+                   Output_section* os = relobj->output_section(in_shndx,
+                                                               &secoff);
+                   gold_assert(os != NULL);
+                   shndx = os->out_shndx();
+                 }
              }
          }
          break;
@@ -1463,24 +1753,47 @@ Symbol_table::sized_write_symbol(
 // Write out a section symbol.  Return the update offset.
 
 void
-Symbol_table::write_section_symbol(const Target* target,
-                                  const Output_section *os,
+Symbol_table::write_section_symbol(const Output_section *os,
                                   Output_file* of,
                                   off_t offset) const
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (target->is_big_endian())
-       this->sized_write_section_symbol<32, true>(os, of, offset);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->sized_write_section_symbol<32, true>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_section_symbol<32, false>(os, of, offset);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->sized_write_section_symbol<32, false>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (target->is_big_endian())
-       this->sized_write_section_symbol<64, true>(os, of, offset);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->sized_write_section_symbol<64, true>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_section_symbol<64, false>(os, of, offset);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->sized_write_section_symbol<64, false>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -1510,6 +1823,49 @@ Symbol_table::sized_write_section_symbol(const Output_section* os,
   of->write_output_view(offset, sym_size, pov);
 }
 
+// Check candidate_odr_violations_ to find symbols with the same name
+// but apparently different definitions (different source-file/line-no).
+
+void
+Symbol_table::detect_odr_violations() const
+{
+  for (Odr_map::const_iterator it = candidate_odr_violations_.begin();
+       it != candidate_odr_violations_.end();
+       ++it)
+    {
+      const char* symbol_name = it->first;
+      // We use a sorted set so the output is deterministic.
+      std::set<std::string> line_nums;
+
+      Unordered_set<Symbol_location, Symbol_location_hash>::const_iterator
+       locs;
+      for (locs = it->second.begin(); locs != it->second.end(); ++locs)
+        {
+         // We need to lock the object in order to read it.  This
+         // means that we can not run inside a Task.  If we want to
+         // run this in a Task for better performance, we will need
+         // one Task for object, plus appropriate locking to ensure
+         // that we don't conflict with other uses of the object.
+          locs->object->lock();
+          std::string lineno = Dwarf_line_info::one_addr2line(
+              locs->object, locs->shndx, locs->offset);
+          locs->object->unlock();
+          if (!lineno.empty())
+            line_nums.insert(lineno);
+        }
+
+      if (line_nums.size() > 1)
+        {
+          gold_warning(_("symbol %s defined in multiple places "
+                        "(possible ODR violation):"), symbol_name);
+          for (std::set<std::string>::const_iterator it2 = line_nums.begin();
+               it2 != line_nums.end();
+               ++it2)
+            fprintf(stderr, "  %s\n", it2->c_str());
+        }
+    }
+}
+
 // Warnings functions.
 
 // Add a new warning.
@@ -1561,14 +1917,17 @@ Warnings::note_warnings(Symbol_table* symtab)
 // Issue a warning.  This is called when we see a relocation against a
 // symbol for which has a warning.
 
+template<int size, bool big_endian>
 void
-Warnings::issue_warning(const Symbol* sym, const std::string& location) const
+Warnings::issue_warning(const Symbol* sym,
+                       const Relocate_info<size, big_endian>* relinfo,
+                       size_t relnum, off_t reloffset) const
 {
   gold_assert(sym->has_warning());
   Warning_table::const_iterator p = this->warnings_.find(sym->name());
   gold_assert(p != this->warnings_.end());
-  fprintf(stderr, _("%s: %s: warning: %s\n"), program_name, location.c_str(),
-         p->second.text.c_str());
+  gold_warning_at_location(relinfo, relnum, reloffset,
+                          "%s", p->second.text.c_str());
 }
 
 // Instantiate the templates we need.  We could use the configure
@@ -1584,7 +1943,7 @@ Symbol_table::add_from_relobj<32, false>(
     size_t count,
     const char* sym_names,
     size_t sym_name_size,
-    Symbol** sympointers);
+    Sized_relobj<32, true>::Symbols* sympointers);
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
@@ -1596,7 +1955,7 @@ Symbol_table::add_from_relobj<32, true>(
     size_t count,
     const char* sym_names,
     size_t sym_name_size,
-    Symbol** sympointers);
+    Sized_relobj<32, false>::Symbols* sympointers);
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
@@ -1608,7 +1967,7 @@ Symbol_table::add_from_relobj<64, false>(
     size_t count,
     const char* sym_names,
     size_t sym_name_size,
-    Symbol** sympointers);
+    Sized_relobj<64, true>::Symbols* sympointers);
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
@@ -1620,7 +1979,7 @@ Symbol_table::add_from_relobj<64, true>(
     size_t count,
     const char* sym_names,
     size_t sym_name_size,
-    Symbol** sympointers);
+    Sized_relobj<64, false>::Symbols* sympointers);
 #endif
 
 #ifdef HAVE_TARGET_32_LITTLE
@@ -1679,4 +2038,52 @@ Symbol_table::add_from_dynobj<64, true>(
     const std::vector<const char*>* version_map);
 #endif
 
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<32>(const Target* target,
+                                        Sized_symbol<32>* sym,
+                                        Output_data* posd, uint64_t value);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<64>(const Target* target,
+                                        Sized_symbol<64>* sym,
+                                        Output_data* posd, uint64_t value);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Warnings::issue_warning<32, false>(const Symbol* sym,
+                                  const Relocate_info<32, false>* relinfo,
+                                  size_t relnum, off_t reloffset) const;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Warnings::issue_warning<32, true>(const Symbol* sym,
+                                 const Relocate_info<32, true>* relinfo,
+                                 size_t relnum, off_t reloffset) const;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Warnings::issue_warning<64, false>(const Symbol* sym,
+                                  const Relocate_info<64, false>* relinfo,
+                                  size_t relnum, off_t reloffset) const;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Warnings::issue_warning<64, true>(const Symbol* sym,
+                                 const Relocate_info<64, true>* relinfo,
+                                 size_t relnum, off_t reloffset) const;
+#endif
+
 } // End namespace gold.