Add -Wshadow to the gcc command line options used when compiling the binutils.
[deliverable/binutils-gdb.git] / gold / symtab.cc
index 46bed6892116eb57ebf0dfe6fb6c6ae130fa7c87..30ed8f787411dee2c22a2bb7b3e9f5cbe4dbeb8b 100644 (file)
@@ -50,20 +50,20 @@ namespace gold
 // and source_.
 
 void
-Symbol::init_fields(const char* name, const char* version,
-                   elfcpp::STT type, elfcpp::STB binding,
-                   elfcpp::STV visibility, unsigned char nonvis)
+Symbol::init_fields(const char* aname, const char* aversion,
+                   elfcpp::STT atype, elfcpp::STB abinding,
+                   elfcpp::STV avisibility, unsigned char non_vis)
 {
-  this->name_ = name;
-  this->version_ = version;
+  this->name_ = aname;
+  this->version_ = aversion;
   this->symtab_index_ = 0;
   this->dynsym_index_ = 0;
   this->got_offsets_.init();
   this->plt_offset_ = 0;
-  this->type_ = type;
-  this->binding_ = binding;
-  this->visibility_ = visibility;
-  this->nonvis_ = nonvis;
+  this->type_ = atype;
+  this->binding_ = abinding;
+  this->visibility_ = avisibility;
+  this->nonvis_ = non_vis;
   this->is_target_special_ = false;
   this->is_def_ = false;
   this->is_forwarder_ = false;
@@ -83,16 +83,16 @@ Symbol::init_fields(const char* name, const char* version,
 // if the --demangle flag was set.
 
 static std::string
-demangle(const char* name)
+demangle(const char* aname)
 {
   if (!parameters->options().do_demangle())
-    return name;
+    return aname;
 
   // cplus_demangle allocates memory for the result it returns,
   // and returns NULL if the name is already demangled.
-  char* demangled_name = cplus_demangle(name, DMGL_ANSI | DMGL_PARAMS);
+  char* demangled_name = cplus_demangle(aname, DMGL_ANSI | DMGL_PARAMS);
   if (demangled_name == NULL)
-    return name;
+    return aname;
 
   std::string retval(demangled_name);
   free(demangled_name);
@@ -109,33 +109,33 @@ Symbol::demangled_name() const
 
 template<int size, bool big_endian>
 void
-Symbol::init_base_object(const char* name, const char* version, Object* object,
+Symbol::init_base_object(const char* aname, const char* aversion, Object* aobject,
                         const elfcpp::Sym<size, big_endian>& sym,
                         unsigned int st_shndx, bool is_ordinary)
 {
-  this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
+  this->init_fields(aname, aversion, sym.get_st_type(), sym.get_st_bind(),
                    sym.get_st_visibility(), sym.get_st_nonvis());
-  this->u_.from_object.object = object;
+  this->u_.from_object.object = aobject;
   this->u_.from_object.shndx = st_shndx;
   this->is_ordinary_shndx_ = is_ordinary;
   this->source_ = FROM_OBJECT;
-  this->in_reg_ = !object->is_dynamic();
-  this->in_dyn_ = object->is_dynamic();
-  this->in_real_elf_ = object->pluginobj() == NULL;
+  this->in_reg_ = !aobject->is_dynamic();
+  this->in_dyn_ = aobject->is_dynamic();
+  this->in_real_elf_ = aobject->pluginobj() == NULL;
 }
 
 // Initialize the fields in the base class Symbol for a symbol defined
 // in an Output_data.
 
 void
-Symbol::init_base_output_data(const char* name, const char* version,
-                             Output_data* od, elfcpp::STT type,
-                             elfcpp::STB binding, elfcpp::STV visibility,
-                             unsigned char nonvis, bool offset_is_from_end)
+Symbol::init_base_output_data(const char* aname, const char* aversion,
+                             Output_data* od, elfcpp::STT atype,
+                             elfcpp::STB abinding, elfcpp::STV avisibility,
+                             unsigned char non_vis, bool offset_is_from_the_end)
 {
-  this->init_fields(name, version, type, binding, visibility, nonvis);
+  this->init_fields(aname, aversion, atype, abinding, avisibility, non_vis);
   this->u_.in_output_data.output_data = od;
-  this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
+  this->u_.in_output_data.offset_is_from_end = offset_is_from_the_end;
   this->source_ = IN_OUTPUT_DATA;
   this->in_reg_ = true;
   this->in_real_elf_ = true;
@@ -145,15 +145,15 @@ Symbol::init_base_output_data(const char* name, const char* version,
 // in an Output_segment.
 
 void
-Symbol::init_base_output_segment(const char* name, const char* version,
-                                Output_segment* os, elfcpp::STT type,
-                                elfcpp::STB binding, elfcpp::STV visibility,
-                                unsigned char nonvis,
-                                Segment_offset_base offset_base)
+Symbol::init_base_output_segment(const char* aname, const char* aversion,
+                                Output_segment* os, elfcpp::STT atype,
+                                elfcpp::STB abinding, elfcpp::STV avisibility,
+                                unsigned char non_vis,
+                                Segment_offset_base offsetbase)
 {
-  this->init_fields(name, version, type, binding, visibility, nonvis);
+  this->init_fields(aname, aversion, atype, abinding, avisibility, non_vis);
   this->u_.in_output_segment.output_segment = os;
-  this->u_.in_output_segment.offset_base = offset_base;
+  this->u_.in_output_segment.offset_base = offsetbase;
   this->source_ = IN_OUTPUT_SEGMENT;
   this->in_reg_ = true;
   this->in_real_elf_ = true;
@@ -163,11 +163,11 @@ Symbol::init_base_output_segment(const char* name, const char* version,
 // as a constant.
 
 void
-Symbol::init_base_constant(const char* name, const char* version,
-                          elfcpp::STT type, elfcpp::STB binding,
-                          elfcpp::STV visibility, unsigned char nonvis)
+Symbol::init_base_constant(const char* aname, const char* aversion,
+                          elfcpp::STT atype, elfcpp::STB abinding,
+                          elfcpp::STV avisibility, unsigned char non_vis)
 {
-  this->init_fields(name, version, type, binding, visibility, nonvis);
+  this->init_fields(aname, aversion, atype, abinding, avisibility, non_vis);
   this->source_ = IS_CONSTANT;
   this->in_reg_ = true;
   this->in_real_elf_ = true;
@@ -177,11 +177,11 @@ Symbol::init_base_constant(const char* name, const char* version,
 // symbol.
 
 void
-Symbol::init_base_undefined(const char* name, const char* version,
-                           elfcpp::STT type, elfcpp::STB binding,
-                           elfcpp::STV visibility, unsigned char nonvis)
+Symbol::init_base_undefined(const char* aname, const char* aversion,
+                           elfcpp::STT atype, elfcpp::STB abinding,
+                           elfcpp::STV avisibility, unsigned char non_vis)
 {
-  this->init_fields(name, version, type, binding, visibility, nonvis);
+  this->init_fields(aname, aversion, atype, abinding, avisibility, non_vis);
   this->dynsym_index_ = -1U;
   this->source_ = IS_UNDEFINED;
   this->in_reg_ = true;
@@ -204,12 +204,12 @@ Symbol::allocate_base_common(Output_data* od)
 template<int size>
 template<bool big_endian>
 void
-Sized_symbol<size>::init_object(const char* name, const char* version,
-                               Object* object,
+Sized_symbol<size>::init_object(const char* aname, const char* aversion,
+                               Object* aobject,
                                const elfcpp::Sym<size, big_endian>& sym,
                                unsigned int st_shndx, bool is_ordinary)
 {
-  this->init_base_object(name, version, object, sym, st_shndx, is_ordinary);
+  this->init_base_object(aname, aversion, aobject, sym, st_shndx, is_ordinary);
   this->value_ = sym.get_st_value();
   this->symsize_ = sym.get_st_size();
 }
@@ -219,18 +219,18 @@ Sized_symbol<size>::init_object(const char* name, const char* version,
 
 template<int size>
 void
-Sized_symbol<size>::init_output_data(const char* name, const char* version,
-                                    Output_data* od, Value_type value,
-                                    Size_type symsize, elfcpp::STT type,
-                                    elfcpp::STB binding,
-                                    elfcpp::STV visibility,
-                                    unsigned char nonvis,
-                                    bool offset_is_from_end)
+Sized_symbol<size>::init_output_data(const char* aname, const char* aversion,
+                                    Output_data* od, Value_type avalue,
+                                    Size_type sym_size, elfcpp::STT atype,
+                                    elfcpp::STB abinding,
+                                    elfcpp::STV avisibility,
+                                    unsigned char non_vis,
+                                    bool offset_is_from_the_end)
 {
-  this->init_base_output_data(name, version, od, type, binding, visibility,
-                             nonvis, offset_is_from_end);
-  this->value_ = value;
-  this->symsize_ = symsize;
+  this->init_base_output_data(aname, aversion, od, atype, abinding, avisibility,
+                             non_vis, offset_is_from_the_end);
+  this->value_ = avalue;
+  this->symsize_ = sym_size;
 }
 
 // Initialize the fields in Sized_symbol for a symbol defined in an
@@ -238,18 +238,18 @@ Sized_symbol<size>::init_output_data(const char* name, const char* version,
 
 template<int size>
 void
-Sized_symbol<size>::init_output_segment(const char* name, const char* version,
-                                       Output_segment* os, Value_type value,
-                                       Size_type symsize, elfcpp::STT type,
-                                       elfcpp::STB binding,
-                                       elfcpp::STV visibility,
-                                       unsigned char nonvis,
-                                       Segment_offset_base offset_base)
+Sized_symbol<size>::init_output_segment(const char* aname, const char* aversion,
+                                       Output_segment* os, Value_type avalue,
+                                       Size_type sym_size, elfcpp::STT atype,
+                                       elfcpp::STB abinding,
+                                       elfcpp::STV avisibility,
+                                       unsigned char non_vis,
+                                       Segment_offset_base offsetbase)
 {
-  this->init_base_output_segment(name, version, os, type, binding, visibility,
-                                nonvis, offset_base);
-  this->value_ = value;
-  this->symsize_ = symsize;
+  this->init_base_output_segment(aname, aversion, os, atype, abinding, avisibility,
+                                non_vis, offsetbase);
+  this->value_ = avalue;
+  this->symsize_ = sym_size;
 }
 
 // Initialize the fields in Sized_symbol for a symbol defined as a
@@ -257,37 +257,47 @@ Sized_symbol<size>::init_output_segment(const char* name, const char* version,
 
 template<int size>
 void
-Sized_symbol<size>::init_constant(const char* name, const char* version,
-                                 Value_type value, Size_type symsize,
-                                 elfcpp::STT type, elfcpp::STB binding,
-                                 elfcpp::STV visibility, unsigned char nonvis)
+Sized_symbol<size>::init_constant(const char* aname, const char* aversion,
+                                 Value_type avalue, Size_type sym_size,
+                                 elfcpp::STT atype, elfcpp::STB abinding,
+                                 elfcpp::STV avisibility, unsigned char non_vis)
 {
-  this->init_base_constant(name, version, type, binding, visibility, nonvis);
-  this->value_ = value;
-  this->symsize_ = symsize;
+  this->init_base_constant(aname, aversion, atype, abinding, avisibility, non_vis);
+  this->value_ = avalue;
+  this->symsize_ = sym_size;
 }
 
 // Initialize the fields in Sized_symbol for an undefined symbol.
 
 template<int size>
 void
-Sized_symbol<size>::init_undefined(const char* name, const char* version,
-                                  elfcpp::STT type, elfcpp::STB binding,
-                                  elfcpp::STV visibility, unsigned char nonvis)
+Sized_symbol<size>::init_undefined(const char* aname, const char* aversion,
+                                  elfcpp::STT atype, elfcpp::STB abinding,
+                                  elfcpp::STV avisibility, unsigned char non_vis)
 {
-  this->init_base_undefined(name, version, type, binding, visibility, nonvis);
+  this->init_base_undefined(aname, aversion, atype, abinding, avisibility, non_vis);
   this->value_ = 0;
   this->symsize_ = 0;
 }
 
+// Return true if SHNDX represents a common symbol.
+
+bool
+Symbol::is_common_shndx(unsigned int sec_shndx)
+{
+  return (sec_shndx == elfcpp::SHN_COMMON
+         || sec_shndx == parameters->target().small_common_shndx()
+         || sec_shndx == parameters->target().large_common_shndx());
+}
+
 // Allocate a common symbol.
 
 template<int size>
 void
-Sized_symbol<size>::allocate_common(Output_data* od, Value_type value)
+Sized_symbol<size>::allocate_common(Output_data* od, Value_type avalue)
 {
   this->allocate_base_common(od);
-  this->value_ = value;
+  this->value_ = avalue;
 }
 
 // The ""'s around str ensure str is a string literal, so sizeof works.
@@ -313,9 +323,9 @@ Symbol::should_add_dynsym_entry() const
     {
       Relobj* relobj = static_cast<Relobj*>(this->object());
       bool is_ordinary;
-      unsigned int shndx = this->shndx(&is_ordinary);
-      if (is_ordinary && shndx != elfcpp::SHN_UNDEF
-          && !relobj->is_section_included(shndx))
+      unsigned int sec_shndx = this->shndx(&is_ordinary);
+      if (is_ordinary && sec_shndx != elfcpp::SHN_UNDEF
+          && !relobj->is_section_included(sec_shndx))
         return false;
     }
 
@@ -341,28 +351,28 @@ Symbol::should_add_dynsym_entry() const
     {
       // TODO(csilvers): We could probably figure out if we're an operator
       //                 new/delete or typeinfo without the need to demangle.
-      char* demangled_name = cplus_demangle(this->name(),
-                                            DMGL_ANSI | DMGL_PARAMS);
-      if (demangled_name == NULL)
+      char* ademangled_name = cplus_demangle(this->name(),
+                                            DMGL_ANSI | DMGL_PARAMS);
+      if (ademangled_name == NULL)
         {
           // Not a C++ symbol, so it can't satisfy these flags
         }
       else if (parameters->options().dynamic_list_cpp_new()
-               && (strprefix(demangled_name, "operator new")
-                   || strprefix(demangled_name, "operator delete")))
+               && (strprefix(ademangled_name, "operator new")
+                   || strprefix(ademangled_name, "operator delete")))
         {
-          free(demangled_name);
+          free(ademangled_name);
           return true;
         }
       else if (parameters->options().dynamic_list_cpp_typeinfo()
-               && (strprefix(demangled_name, "typeinfo name for")
-                   || strprefix(demangled_name, "typeinfo for")))
+               && (strprefix(ademangled_name, "typeinfo name for")
+                   || strprefix(ademangled_name, "typeinfo for")))
         {
-          free(demangled_name);
+          free(ademangled_name);
           return true;
         }
       else
-        free(demangled_name);
+        free(ademangled_name);
     }
 
   // If exporting all symbols or building a shared library,
@@ -384,7 +394,8 @@ 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->options().shared() || parameters->options().relocatable())
+  if (parameters->options().output_is_position_independent()
+      || parameters->options().relocatable())
     return false;
 
   // If the symbol is not from an object file, and is not undefined,
@@ -423,13 +434,13 @@ Symbol::output_section() const
     {
     case FROM_OBJECT:
       {
-       unsigned int shndx = this->u_.from_object.shndx;
-       if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
+       unsigned int sec_shndx = this->u_.from_object.shndx;
+       if (sec_shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
          {
            gold_assert(!this->u_.from_object.object->is_dynamic());
            gold_assert(this->u_.from_object.object->pluginobj() == NULL);
            Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
-           return relobj->output_section(shndx);
+           return relobj->output_section(sec_shndx);
          }
        return NULL;
       }
@@ -475,10 +486,11 @@ Symbol::set_output_section(Output_section* os)
 // Class Symbol_table.
 
 Symbol_table::Symbol_table(unsigned int count,
-                           const Version_script_info& version_script)
+                           const Version_script_info& aversion_script)
   : saw_undefined_(0), offset_(0), table_(count), namepool_(),
-    forwarders_(), commons_(), tls_commons_(), forced_locals_(), warnings_(),
-    version_script_(version_script), gc_(NULL)
+    forwarders_(), commons_(), tls_commons_(), small_commons_(),
+    large_commons_(), forced_locals_(), warnings_(),
+    version_script_(aversion_script), gc_(NULL), icf_(NULL)
 {
   namepool_.reserve(count);
 }
@@ -505,6 +517,13 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
   return k1.first == k2.first && k1.second == k2.second;
 }
 
+bool
+Symbol_table::is_section_folded(Object* obj, unsigned int sec_shndx) const
+{
+  return (parameters->options().icf_enabled()
+          && this->icf_->is_section_folded(obj, sec_shndx));
+}
+
 // For symbols that have been listed with -u option, add them to the
 // work list to avoid gc'ing them.
 
@@ -516,19 +535,19 @@ Symbol_table::gc_mark_undef_symbols()
        p != parameters->options().undefined_end();
        ++p)
     {
-      const char* name = p->c_str();
-      Symbol* sym = this->lookup(name);
+      const char* aname = p->c_str();
+      Symbol* sym = this->lookup(aname);
       gold_assert (sym != NULL);
       if (sym->source() == Symbol::FROM_OBJECT 
           && !sym->object()->is_dynamic())
         {
           Relobj* obj = static_cast<Relobj*>(sym->object());
           bool is_ordinary;
-          unsigned int shndx = sym->shndx(&is_ordinary);
+          unsigned int sec_shndx = sym->shndx(&is_ordinary);
           if (is_ordinary)
             {
               gold_assert(this->gc_ != NULL);
-              this->gc_->worklist().push(Section_id(obj, shndx));
+              this->gc_->worklist().push(Section_id(obj, sec_shndx));
             }
         }
     }
@@ -543,11 +562,11 @@ Symbol_table::gc_mark_symbol_for_shlib(Symbol* sym)
       //Add the object and section to the work list.
       Relobj* obj = static_cast<Relobj*>(sym->object());
       bool is_ordinary;
-      unsigned int shndx = sym->shndx(&is_ordinary);
-      if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
+      unsigned int sec_shndx = sym->shndx(&is_ordinary);
+      if (is_ordinary && sec_shndx != elfcpp::SHN_UNDEF)
         {
           gold_assert(this->gc_!= NULL);
-          this->gc_->worklist().push(Section_id(obj, shndx));
+          this->gc_->worklist().push(Section_id(obj, sec_shndx));
         }
     }
 }
@@ -562,11 +581,11 @@ Symbol_table::gc_mark_dyn_syms(Symbol* sym)
     {
       Relobj *obj = static_cast<Relobj*>(sym->object()); 
       bool is_ordinary;
-      unsigned int shndx = sym->shndx(&is_ordinary);
-      if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
+      unsigned int sec_shndx = sym->shndx(&is_ordinary);
+      if (is_ordinary && sec_shndx != elfcpp::SHN_UNDEF)
         {
           gold_assert(this->gc_ != NULL);
-          this->gc_->worklist().push(Section_id(obj, shndx));
+          this->gc_->worklist().push(Section_id(obj, sec_shndx));
         }
     }
 }
@@ -597,18 +616,18 @@ Symbol_table::resolve_forwards(const Symbol* from) const
 // Look up a symbol by name.
 
 Symbol*
-Symbol_table::lookup(const char* name, const char* version) const
+Symbol_table::lookup(const char* aname, const char* aversion) const
 {
   Stringpool::Key name_key;
-  name = this->namepool_.find(name, &name_key);
-  if (name == NULL)
+  aname = this->namepool_.find(aname, &name_key);
+  if (aname == NULL)
     return NULL;
 
   Stringpool::Key version_key = 0;
-  if (version != NULL)
+  if (aversion != NULL)
     {
-      version = this->namepool_.find(version, &version_key);
-      if (version == NULL)
+      aversion = this->namepool_.find(aversion, &version_key);
+      if (aversion == NULL)
        return NULL;
     }
 
@@ -637,8 +656,8 @@ 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());
   bool is_ordinary;
-  unsigned int shndx = from->shndx(&is_ordinary);
-  this->resolve(to, esym.sym(), shndx, is_ordinary, shndx, from->object(),
+  unsigned int sec_shndx = from->shndx(&is_ordinary);
+  this->resolve(to, esym.sym(), sec_shndx, is_ordinary, sec_shndx, from->object(),
                from->version());
   if (from->in_reg())
     to->set_in_reg();
@@ -670,26 +689,25 @@ Symbol_table::force_local(Symbol* sym)
 // option was used.
 
 const char*
-Symbol_table::wrap_symbol(Object* object, const char* name,
-                         Stringpool::Key* name_key)
+Symbol_table::wrap_symbol(const char* aname, Stringpool::Key* name_key)
 {
   // For some targets, we need to ignore a specific character when
   // wrapping, and add it back later.
   char prefix = '\0';
-  if (name[0] == object->target()->wrap_char())
+  if (aname[0] == parameters->target().wrap_char())
     {
-      prefix = name[0];
-      ++name;
+      prefix = aname[0];
+      ++aname;
     }
 
-  if (parameters->options().is_wrap(name))
+  if (parameters->options().is_wrap(aname))
     {
       // Turn NAME into __wrap_NAME.
       std::string s;
       if (prefix != '\0')
        s += prefix;
       s += "__wrap_";
-      s += name;
+      s += aname;
 
       // This will give us both the old and new name in NAMEPOOL_, but
       // that is OK.  Only the versions we need will wind up in the
@@ -699,18 +717,94 @@ Symbol_table::wrap_symbol(Object* object, const char* name,
 
   const char* const real_prefix = "__real_";
   const size_t real_prefix_length = strlen(real_prefix);
-  if (strncmp(name, real_prefix, real_prefix_length) == 0
-      && parameters->options().is_wrap(name + real_prefix_length))
+  if (strncmp(aname, real_prefix, real_prefix_length) == 0
+      && parameters->options().is_wrap(aname + real_prefix_length))
     {
       // Turn __real_NAME into NAME.
       std::string s;
       if (prefix != '\0')
        s += prefix;
-      s += name + real_prefix_length;
+      s += aname + real_prefix_length;
       return this->namepool_.add(s.c_str(), true, name_key);
     }
 
-  return name;
+  return aname;
+}
+
+// This is called when we see a symbol NAME/VERSION, and the symbol
+// already exists in the symbol table, and VERSION is marked as being
+// the default version.  SYM is the NAME/VERSION symbol we just added.
+// DEFAULT_IS_NEW is true if this is the first time we have seen the
+// symbol NAME/NULL.  PDEF points to the entry for NAME/NULL.
+
+template<int size, bool big_endian>
+void
+Symbol_table::define_default_version(Sized_symbol<size>* sym,
+                                    bool default_is_new,
+                                    Symbol_table_type::iterator pdef)
+{
+  if (default_is_new)
+    {
+      // This is the first time we have seen NAME/NULL.  Make
+      // NAME/NULL point to NAME/VERSION, and mark SYM as the default
+      // version.
+      pdef->second = sym;
+      sym->set_is_default();
+    }
+  else if (pdef->second == sym)
+    {
+      // NAME/NULL already points to NAME/VERSION.  Don't mark the
+      // symbol as the default if it is not already the default.
+    }
+  else
+    {
+      // This is the unfortunate case where we already have entries
+      // for both NAME/VERSION and NAME/NULL.  We now see a symbol
+      // NAME/VERSION where VERSION is the default version.  We have
+      // already resolved this new symbol with the existing
+      // NAME/VERSION symbol.
+
+      // It's possible that NAME/NULL and NAME/VERSION are both
+      // defined in regular objects.  This can only happen if one
+      // object file defines foo and another defines foo@@ver.  This
+      // is somewhat obscure, but we call it a multiple definition
+      // error.
+
+      // It's possible that NAME/NULL actually has a version, in which
+      // case it won't be the same as VERSION.  This happens with
+      // ver_test_7.so in the testsuite for the symbol t2_2.  We see
+      // t2_2@@VER2, so we define both t2_2/VER2 and t2_2/NULL.  We
+      // then see an unadorned t2_2 in an object file and give it
+      // version VER1 from the version script.  This looks like a
+      // default definition for VER1, so it looks like we should merge
+      // t2_2/NULL with t2_2/VER1.  That doesn't make sense, but it's
+      // not obvious that this is an error, either.  So we just punt.
+
+      // If one of the symbols has non-default visibility, and the
+      // other is defined in a shared object, then they are different
+      // symbols.
+
+      // Otherwise, we just resolve the symbols as though they were
+      // the same.
+
+      if (pdef->second->version() != NULL)
+       gold_assert(pdef->second->version() != sym->version());
+      else if (sym->visibility() != elfcpp::STV_DEFAULT
+              && pdef->second->is_from_dynobj())
+       ;
+      else if (pdef->second->visibility() != elfcpp::STV_DEFAULT
+              && sym->is_from_dynobj())
+       ;
+      else
+       {
+         const Sized_symbol<size>* symdef;
+         symdef = this->get_sized_symbol<size>(pdef->second);
+         Symbol_table::resolve<size, big_endian>(sym, symdef);
+         this->make_forwarder(pdef->second, sym);
+         pdef->second = sym;
+         sym->set_is_default();
+       }
+    }
 }
 
 // Add one symbol from OBJECT to the symbol table.  NAME is symbol
@@ -745,10 +839,10 @@ Symbol_table::wrap_symbol(Object* object, const char* name,
 
 template<int size, bool big_endian>
 Sized_symbol<size>*
-Symbol_table::add_from_object(Object* object,
-                             const char *name,
+Symbol_table::add_from_object(Object* aobject,
+                             const char *aname,
                              Stringpool::Key name_key,
-                             const char *version,
+                             const char *aversion,
                              Stringpool::Key version_key,
                              bool def,
                              const elfcpp::Sym<size, big_endian>& sym,
@@ -757,12 +851,12 @@ Symbol_table::add_from_object(Object* object,
                              unsigned int orig_st_shndx)
 {
   // Print a message if this symbol is being traced.
-  if (parameters->options().is_trace_symbol(name))
+  if (parameters->options().is_trace_symbol(aname))
     {
       if (orig_st_shndx == elfcpp::SHN_UNDEF)
-        gold_info(_("%s: reference to %s"), object->name().c_str(), name);
+        gold_info(_("%s: reference to %s"), aobject->name().c_str(), aname);
       else
-        gold_info(_("%s: definition of %s"), object->name().c_str(), name);
+        gold_info(_("%s: definition of %s"), aobject->name().c_str(), aname);
     }
 
   // For an undefined symbol, we may need to adjust the name using
@@ -770,17 +864,17 @@ Symbol_table::add_from_object(Object* object,
   if (orig_st_shndx == elfcpp::SHN_UNDEF
       && parameters->options().any_wrap())
     {
-      const char* wrap_name = this->wrap_symbol(object, name, &name_key);
-      if (wrap_name != name)
+      const char* wrap_name = this->wrap_symbol(aname, &name_key);
+      if (wrap_name != aname)
        {
          // If we see a reference to malloc with version GLIBC_2.0,
          // and we turn it into a reference to __wrap_malloc, then we
          // discard the version number.  Otherwise the user would be
          // required to specify the correct version for
          // __wrap_malloc.
-         version = NULL;
+         aversion = NULL;
          version_key = 0;
-         name = wrap_name;
+         aname = wrap_name;
        }
     }
 
@@ -816,75 +910,14 @@ Symbol_table::add_from_object(Object* object,
       was_undefined = ret->is_undefined();
       was_common = ret->is_common();
 
-      this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
-                   version);
+      this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, aobject,
+                   aversion);
       if (parameters->options().gc_sections())
         this->gc_mark_dyn_syms(ret);
 
       if (def)
-       {
-         if (insdef.second)
-           {
-             // This is the first time we have seen NAME/NULL.  Make
-             // NAME/NULL point to NAME/VERSION.
-             insdef.first->second = ret;
-           }
-         else if (insdef.first->second != ret)
-           {
-             // This is the unfortunate case where we already have
-             // entries for both NAME/VERSION and NAME/NULL.  We now
-             // see a symbol NAME/VERSION where VERSION is the
-             // default version.  We have already resolved this new
-             // symbol with the existing NAME/VERSION symbol.
-
-             // It's possible that NAME/NULL and NAME/VERSION are
-             // both defined in regular objects.  This can only
-             // happen if one object file defines foo and another
-             // defines foo@@ver.  This is somewhat obscure, but we
-             // call it a multiple definition error.
-
-             // It's possible that NAME/NULL actually has a version,
-             // in which case it won't be the same as VERSION.  This
-             // happens with ver_test_7.so in the testsuite for the
-             // symbol t2_2.  We see t2_2@@VER2, so we define both
-             // t2_2/VER2 and t2_2/NULL.  We then see an unadorned
-             // t2_2 in an object file and give it version VER1 from
-             // the version script.  This looks like a default
-             // definition for VER1, so it looks like we should merge
-             // t2_2/NULL with t2_2/VER1.  That doesn't make sense,
-             // but it's not obvious that this is an error, either.
-             // So we just punt.
-
-             // If one of the symbols has non-default visibility, and
-             // the other is defined in a shared object, then they
-             // are different symbols.
-
-             // Otherwise, we just resolve the symbols as though they
-             // were the same.
-
-             if (insdef.first->second->version() != NULL)
-               {
-                 gold_assert(insdef.first->second->version() != version);
-                 def = false;
-               }
-             else if (ret->visibility() != elfcpp::STV_DEFAULT
-                 && insdef.first->second->is_from_dynobj())
-               def = false;
-             else if (insdef.first->second->visibility() != elfcpp::STV_DEFAULT
-                      && ret->is_from_dynobj())
-               def = false;
-             else
-               {
-                 const Sized_symbol<size>* sym2;
-                 sym2 = this->get_sized_symbol<size>(insdef.first->second);
-                 Symbol_table::resolve<size, big_endian>(ret, sym2);
-                 this->make_forwarder(insdef.first->second, ret);
-                 insdef.first->second = ret;
-               }
-           }
-         else
-           def = false;
-       }
+       this->define_default_version<size, big_endian>(ret, insdef.second,
+                                                      insdef.first);
     }
   else
     {
@@ -900,8 +933,8 @@ Symbol_table::add_from_object(Object* object,
          was_undefined = ret->is_undefined();
          was_common = ret->is_common();
 
-         this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
-                       version);
+         this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, aobject,
+                       aversion);
           if (parameters->options().gc_sections())
             this->gc_mark_dyn_syms(ret);
          ins.first->second = ret;
@@ -912,7 +945,7 @@ Symbol_table::add_from_object(Object* object,
          was_common = false;
 
          Sized_target<size, big_endian>* target =
-           object->sized_target<size, big_endian>();
+           parameters->sized_target<size, big_endian>();
          if (!target->has_make_symbol())
            ret = new Sized_symbol<size>();
          else
@@ -935,7 +968,7 @@ Symbol_table::add_from_object(Object* object,
                }
            }
 
-         ret->init_object(name, version, object, sym, st_shndx, is_ordinary);
+         ret->init_object(aname, aversion, aobject, sym, st_shndx, is_ordinary);
 
          ins.first->second = ret;
          if (def)
@@ -946,6 +979,9 @@ Symbol_table::add_from_object(Object* object,
              insdef.first->second = ret;
            }
        }
+
+      if (def)
+       ret->set_is_default();
     }
 
   // Record every time we see a new undefined symbol, to speed up
@@ -957,10 +993,16 @@ Symbol_table::add_from_object(Object* object,
   // allocation.
   if (!was_common && ret->is_common())
     {
-      if (ret->type() != elfcpp::STT_TLS)
-       this->commons_.push_back(ret);
-      else
+      if (ret->type() == elfcpp::STT_TLS)
        this->tls_commons_.push_back(ret);
+      else if (!is_ordinary
+              && st_shndx == parameters->target().small_common_shndx())
+       this->small_commons_.push_back(ret);
+      else if (!is_ordinary
+              && st_shndx == parameters->target().large_common_shndx())
+       this->large_commons_.push_back(ret);
+      else
+       this->commons_.push_back(ret);
     }
 
   // If we're not doing a relocatable link, then any symbol with
@@ -968,12 +1010,11 @@ Symbol_table::add_from_object(Object* object,
   if ((ret->visibility() == elfcpp::STV_HIDDEN
        || ret->visibility() == elfcpp::STV_INTERNAL)
       && (ret->binding() == elfcpp::STB_GLOBAL
+         || ret->binding() == elfcpp::STB_GNU_UNIQUE
          || ret->binding() == elfcpp::STB_WEAK)
       && !parameters->options().relocatable())
     this->force_local(ret);
 
-  if (def)
-    ret->set_is_default();
   return ret;
 }
 
@@ -993,7 +1034,6 @@ Symbol_table::add_from_relobj(
 {
   *defined = 0;
 
-  gold_assert(size == relobj->target()->get_size());
   gold_assert(size == parameters->target().get_size());
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
@@ -1015,7 +1055,7 @@ Symbol_table::add_from_relobj(
          continue;
        }
 
-      const char* name = sym_names + st_name;
+      const char* aname = sym_names + st_name;
 
       bool is_ordinary;
       unsigned int st_shndx = relobj->adjust_sym_shndx(i + symndx_offset,
@@ -1038,7 +1078,7 @@ Symbol_table::add_from_relobj(
       // In an object file, an '@' in the name separates the symbol
       // name from the version name.  If there are two '@' characters,
       // this is the default version.
-      const char* ver = strchr(name, '@');
+      const char* ver = strchr(aname, '@');
       Stringpool::Key ver_key = 0;
       int namelen = 0;
       // DEF: is the version default?  LOCAL: is the symbol forced local?
@@ -1048,7 +1088,7 @@ Symbol_table::add_from_relobj(
       if (ver != NULL)
         {
           // The symbol name is of the form foo@VERSION or foo@@VERSION
-          namelen = ver - name;
+          namelen = ver - aname;
           ++ver;
          if (*ver == '@')
            {
@@ -1062,27 +1102,27 @@ Symbol_table::add_from_relobj(
       // about a common symbol?
       else
        {
-         namelen = strlen(name);
+         namelen = strlen(aname);
          if (!this->version_script_.empty()
              && st_shndx != elfcpp::SHN_UNDEF)
            {
              // The symbol name did not have a version, but the
              // version script may assign a version anyway.
-             std::string version;
-             if (this->version_script_.get_symbol_version(name, &version))
+             std::string aversion;
+             if (this->version_script_.get_symbol_version(aname, &aversion))
                {
                  // The version can be empty if the version script is
                  // only used to force some symbols to be local.
-                 if (!version.empty())
+                 if (!aversion.empty())
                    {
-                     ver = this->namepool_.add_with_length(version.c_str(),
-                                                           version.length(),
+                     ver = this->namepool_.add_with_length(aversion.c_str(),
+                                                           aversion.length(),
                                                            true,
                                                            &ver_key);
                      def = true;
                    }
                }
-             else if (this->version_script_.symbol_is_local(name))
+             else if (this->version_script_.symbol_is_local(aname))
                local = true;
            }
        }
@@ -1110,12 +1150,32 @@ Symbol_table::add_from_relobj(
          psym = &sym2;
        }
 
+      // Fix up visibility if object has no-export set.
+      if (relobj->no_export())
+        {
+         // We may have copied symbol already above.
+         if (psym != &sym2)
+           {
+             memcpy(symbuf, p, sym_size);
+             psym = &sym2;
+           }
+
+         elfcpp::STV visibility = sym2.get_st_visibility();
+         if (visibility == elfcpp::STV_DEFAULT
+             || visibility == elfcpp::STV_PROTECTED)
+           {
+             elfcpp::Sym_write<size, big_endian> sw(symbuf);
+             unsigned char nonvis = sym2.get_st_nonvis();
+             sw.put_st_other(elfcpp::STV_HIDDEN, nonvis);
+           }
+        }
+
       Stringpool::Key name_key;
-      name = this->namepool_.add_with_length(name, namelen, true,
+      aname = this->namepool_.add_with_length(aname, namelen, true,
                                             &name_key);
 
       Sized_symbol<size>* res;
-      res = this->add_from_object(relobj, name, name_key, ver, ver_key,
+      res = this->add_from_object(relobj, aname, name_key, ver, ver_key,
                                  def, *psym, st_shndx, is_ordinary,
                                  orig_st_shndx);
       
@@ -1138,11 +1198,12 @@ template<int size, bool big_endian>
 Symbol*
 Symbol_table::add_from_pluginobj(
     Sized_pluginobj<size, big_endian>* obj,
-    const char* name,
+    const char* aname,
     const char* ver,
     elfcpp::Sym<size, big_endian>* sym)
 {
   unsigned int st_shndx = sym->get_st_shndx();
+  bool is_ordinary = st_shndx < elfcpp::SHN_LORESERVE;
 
   Stringpool::Key ver_key = 0;
   bool def = false;
@@ -1162,31 +1223,31 @@ Symbol_table::add_from_pluginobj(
         {
           // The symbol name did not have a version, but the
           // version script may assign a version anyway.
-          std::string version;
-          if (this->version_script_.get_symbol_version(name, &version))
+          std::string aversion;
+          if (this->version_script_.get_symbol_version(aname, &aversion))
             {
               // The version can be empty if the version script is
               // only used to force some symbols to be local.
-              if (!version.empty())
+              if (!aversion.empty())
                 {
-                  ver = this->namepool_.add_with_length(version.c_str(),
-                                                        version.length(),
+                  ver = this->namepool_.add_with_length(aversion.c_str(),
+                                                        aversion.length(),
                                                         true,
                                                         &ver_key);
                   def = true;
                 }
             }
-          else if (this->version_script_.symbol_is_local(name))
+          else if (this->version_script_.symbol_is_local(aname))
             local = true;
         }
     }
 
   Stringpool::Key name_key;
-  name = this->namepool_.add(name, true, &name_key);
+  aname = this->namepool_.add(aname, true, &name_key);
 
   Sized_symbol<size>* res;
-  res = this->add_from_object(obj, name, name_key, ver, ver_key,
-                             def, *sym, st_shndx, true, st_shndx);
+  res = this->add_from_object(obj, aname, name_key, ver, ver_key,
+                             def, *sym, st_shndx, is_ordinary, st_shndx);
 
   if (local)
     this->force_local(res);
@@ -1212,7 +1273,6 @@ Symbol_table::add_from_dynobj(
 {
   *defined = 0;
 
-  gold_assert(size == dynobj->target()->get_size());
   gold_assert(size == parameters->target().get_size());
 
   if (dynobj->just_symbols())
@@ -1277,7 +1337,7 @@ Symbol_table::add_from_dynobj(
          continue;
        }
 
-      const char* name = sym_names + st_name;
+      const char* aname = sym_names + st_name;
 
       bool is_ordinary;
       unsigned int st_shndx = dynobj->adjust_sym_shndx(i, psym->get_st_shndx(),
@@ -1291,8 +1351,8 @@ Symbol_table::add_from_dynobj(
       if (versym == NULL)
        {
          Stringpool::Key name_key;
-         name = this->namepool_.add(name, true, &name_key);
-         res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+         aname = this->namepool_.add(aname, true, &name_key);
+         res = this->add_from_object(dynobj, aname, name_key, NULL, 0,
                                      false, *psym, st_shndx, is_ordinary,
                                      st_shndx);
        }
@@ -1321,13 +1381,13 @@ Symbol_table::add_from_dynobj(
 
          // At this point we are definitely going to add this symbol.
          Stringpool::Key name_key;
-         name = this->namepool_.add(name, true, &name_key);
+         aname = this->namepool_.add(aname, 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,
+             res = this->add_from_object(dynobj, aname, name_key, NULL, 0,
                                          false, *psym, st_shndx, is_ordinary,
                                          st_shndx);
            }
@@ -1340,8 +1400,8 @@ Symbol_table::add_from_dynobj(
                  continue;
                }
 
-             const char* version = (*version_map)[v];
-             if (version == NULL)
+             const char* aversion = (*version_map)[v];
+             if (aversion == NULL)
                {
                  dynobj->error(_("versym for symbol %zu has no name: %u"),
                                i, v);
@@ -1349,7 +1409,7 @@ Symbol_table::add_from_dynobj(
                }
 
              Stringpool::Key version_key;
-             version = this->namepool_.add(version, true, &version_key);
+             aversion = this->namepool_.add(aversion, true, &version_key);
 
              // If this is an absolute symbol, and the version name
              // and symbol name are the same, then this is the
@@ -1359,14 +1419,14 @@ Symbol_table::add_from_dynobj(
              if (st_shndx == elfcpp::SHN_ABS
                  && !is_ordinary
                  && name_key == version_key)
-               res = this->add_from_object(dynobj, name, name_key, NULL, 0,
+               res = this->add_from_object(dynobj, aname, name_key, NULL, 0,
                                            false, *psym, st_shndx, is_ordinary,
                                            st_shndx);
              else
                {
                  const bool def = (!hidden
                                    && st_shndx != elfcpp::SHN_UNDEF);
-                 res = this->add_from_object(dynobj, name, name_key, version,
+                 res = this->add_from_object(dynobj, aname, name_key, aversion,
                                              version_key, def, *psym, st_shndx,
                                              is_ordinary, st_shndx);
                }
@@ -1477,39 +1537,55 @@ Symbol_table::record_weak_aliases(std::vector<Sized_symbol<size>*>* symbols)
 // Create and return a specially defined symbol.  If ONLY_IF_REF is
 // true, then only create the symbol if there is a reference to it.
 // If this does not return NULL, it sets *POLDSYM to the existing
-// symbol if there is one.  This canonicalizes *PNAME and *PVERSION.
+// symbol if there is one.  This sets *RESOLVE_OLDSYM if we should
+// resolve the newly created symbol to the old one.  This
+// canonicalizes *PNAME and *PVERSION.
 
 template<int size, bool big_endian>
 Sized_symbol<size>*
 Symbol_table::define_special_symbol(const char** pname, const char** pversion,
                                    bool only_if_ref,
-                                    Sized_symbol<size>** poldsym)
+                                    Sized_symbol<size>** poldsym,
+                                   bool *resolve_oldsym)
 {
-  Symbol* oldsym;
-  Sized_symbol<size>* sym;
-  bool add_to_table = false;
-  typename Symbol_table_type::iterator add_loc = this->table_.end();
+  *resolve_oldsym = false;
 
   // If the caller didn't give us a version, see if we get one from
   // the version script.
   std::string v;
+  bool is_default_version = false;
   if (*pversion == NULL)
     {
       if (this->version_script_.get_symbol_version(*pname, &v))
        {
          if (!v.empty())
            *pversion = v.c_str();
+
+         // If we get the version from a version script, then we are
+         // also the default version.
+         is_default_version = true;
        }
     }
 
+  Symbol* oldsym;
+  Sized_symbol<size>* sym;
+
+  bool add_to_table = false;
+  typename Symbol_table_type::iterator add_loc = this->table_.end();
+  bool add_def_to_table = false;
+  typename Symbol_table_type::iterator add_def_loc = this->table_.end();
+
   if (only_if_ref)
     {
       oldsym = this->lookup(*pname, *pversion);
+      if (oldsym == NULL && is_default_version)
+       oldsym = this->lookup(*pname, NULL);
       if (oldsym == NULL || !oldsym->is_undefined())
        return NULL;
 
       *pname = oldsym->name();
-      *pversion = oldsym->version();
+      if (!is_default_version)
+       *pversion = oldsym->version();
     }
   else
     {
@@ -1527,19 +1603,56 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
                                                          version_key),
                                           snull));
 
+      std::pair<typename Symbol_table_type::iterator, bool> insdef =
+       std::make_pair(this->table_.end(), false);
+      if (is_default_version)
+       {
+         const Stringpool::Key vnull = 0;
+         insdef = this->table_.insert(std::make_pair(std::make_pair(name_key,
+                                                                    vnull),
+                                                     snull));
+       }
+
       if (!ins.second)
        {
          // We already have a symbol table entry for NAME/VERSION.
          oldsym = ins.first->second;
          gold_assert(oldsym != NULL);
+
+         if (is_default_version)
+           {
+             Sized_symbol<size>* soldsym =
+               this->get_sized_symbol<size>(oldsym);
+             this->define_default_version<size, big_endian>(soldsym,
+                                                            insdef.second,
+                                                            insdef.first);
+           }
        }
       else
        {
          // We haven't seen this symbol before.
          gold_assert(ins.first->second == NULL);
-          add_to_table = true;
-          add_loc = ins.first;
-         oldsym = NULL;
+
+         add_to_table = true;
+         add_loc = ins.first;
+
+         if (is_default_version && !insdef.second)
+           {
+             // We are adding NAME/VERSION, and it is the default
+             // version.  We already have an entry for NAME/NULL.
+             oldsym = insdef.first->second;
+             *resolve_oldsym = true;
+           }
+         else
+           {
+             oldsym = NULL;
+
+             if (is_default_version)
+               {
+                 add_def_to_table = true;
+                 add_def_loc = insdef.first;
+               }
+           }
        }
     }
 
@@ -1548,11 +1661,8 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
     sym = new Sized_symbol<size>();
   else
     {
-      gold_assert(target.get_size() == size);
-      gold_assert(target.is_big_endian() ? big_endian : !big_endian);
-      typedef Sized_target<size, big_endian> My_target;
-      const My_target* sized_target =
-          static_cast<const My_target*>(&target);
+      Sized_target<size, big_endian>* sized_target =
+       parameters->sized_target<size, big_endian>();
       sym = sized_target->make_symbol();
       if (sym == NULL)
         return NULL;
@@ -1563,6 +1673,9 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
   else
     gold_assert(oldsym != NULL);
 
+  if (add_def_to_table)
+    add_def_loc->second = sym;
+
   *poldsym = this->get_sized_symbol<size>(oldsym);
 
   return sym;
@@ -1571,25 +1684,25 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
 // Define a symbol based on an Output_data.
 
 Symbol*
-Symbol_table::define_in_output_data(const char* name,
-                                   const char* version,
+Symbol_table::define_in_output_data(const char* aname,
+                                   const char* aversion,
                                    Output_data* od,
-                                   uint64_t value,
-                                   uint64_t symsize,
+                                   uint64_t avalue,
+                                   uint64_t sym_size,
                                    elfcpp::STT type,
                                    elfcpp::STB binding,
                                    elfcpp::STV visibility,
                                    unsigned char nonvis,
-                                   bool offset_is_from_end,
+                                   bool offset_is_from_the_end,
                                    bool only_if_ref)
 {
   if (parameters->target().get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
-      return this->do_define_in_output_data<32>(name, version, od,
-                                                value, symsize, type, binding,
+      return this->do_define_in_output_data<32>(aname, aversion, od,
+                                                avalue, sym_size, type, binding,
                                                 visibility, nonvis,
-                                                offset_is_from_end,
+                                                offset_is_from_the_end,
                                                 only_if_ref);
 #else
       gold_unreachable();
@@ -1598,10 +1711,10 @@ Symbol_table::define_in_output_data(const char* name,
   else if (parameters->target().get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
-      return this->do_define_in_output_data<64>(name, version, od,
-                                                value, symsize, type, binding,
+      return this->do_define_in_output_data<64>(aname, aversion, od,
+                                                avalue, sym_size, type, binding,
                                                 visibility, nonvis,
-                                                offset_is_from_end,
+                                                offset_is_from_the_end,
                                                 only_if_ref);
 #else
       gold_unreachable();
@@ -1616,26 +1729,28 @@ Symbol_table::define_in_output_data(const char* name,
 template<int size>
 Sized_symbol<size>*
 Symbol_table::do_define_in_output_data(
-    const char* name,
-    const char* version,
+    const char* aname,
+    const char* aversion,
     Output_data* od,
-    typename elfcpp::Elf_types<size>::Elf_Addr value,
-    typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+    typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+    typename elfcpp::Elf_types<size>::Elf_WXword sym_size,
     elfcpp::STT type,
     elfcpp::STB binding,
     elfcpp::STV visibility,
     unsigned char nonvis,
-    bool offset_is_from_end,
+    bool offset_is_from_the_end,
     bool only_if_ref)
 {
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
+  bool resolve_oldsym;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
-      sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym);
+      sym = this->define_special_symbol<size, true>(&aname, &aversion,
+                                                   only_if_ref, &oldsym,
+                                                   &resolve_oldsym);
 #else
       gold_unreachable();
 #endif
@@ -1643,8 +1758,9 @@ Symbol_table::do_define_in_output_data(
   else
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
-      sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    only_if_ref, &oldsym);
+      sym = this->define_special_symbol<size, false>(&aname, &aversion,
+                                                    only_if_ref, &oldsym,
+                                                    &resolve_oldsym);
 #else
       gold_unreachable();
 #endif
@@ -1653,46 +1769,52 @@ Symbol_table::do_define_in_output_data(
   if (sym == NULL)
     return NULL;
 
-  sym->init_output_data(name, version, od, value, symsize, type, binding,
-                       visibility, nonvis, offset_is_from_end);
+  sym->init_output_data(aname, aversion, od, avalue, sym_size, type, binding,
+                       visibility, nonvis, offset_is_from_the_end);
 
   if (oldsym == NULL)
     {
       if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+         || this->version_script_.symbol_is_local(aname))
        this->force_local(sym);
-      else if (version != NULL)
+      else if (aversion != NULL)
        sym->set_is_default();
       return sym;
     }
 
   if (Symbol_table::should_override_with_special(oldsym))
     this->override_with_special(oldsym, sym);
-  delete sym;
-  return oldsym;
+
+  if (resolve_oldsym)
+    return sym;
+  else
+    {
+      delete sym;
+      return oldsym;
+    }
 }
 
 // Define a symbol based on an Output_segment.
 
 Symbol*
-Symbol_table::define_in_output_segment(const char* name,
-                                      const char* version, Output_segment* os,
-                                      uint64_t value,
-                                      uint64_t symsize,
+Symbol_table::define_in_output_segment(const char* aname,
+                                      const char* aversion, Output_segment* os,
+                                      uint64_t avalue,
+                                      uint64_t sym_size,
                                       elfcpp::STT type,
                                       elfcpp::STB binding,
                                       elfcpp::STV visibility,
                                       unsigned char nonvis,
-                                      Symbol::Segment_offset_base offset_base,
+                                      Symbol::Segment_offset_base offsetbase,
                                       bool only_if_ref)
 {
   if (parameters->target().get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
-      return this->do_define_in_output_segment<32>(name, version, os,
-                                                   value, symsize, type,
+      return this->do_define_in_output_segment<32>(aname, aversion, os,
+                                                   avalue, sym_size, type,
                                                    binding, visibility, nonvis,
-                                                   offset_base, only_if_ref);
+                                                   offsetbase, only_if_ref);
 #else
       gold_unreachable();
 #endif
@@ -1700,10 +1822,10 @@ Symbol_table::define_in_output_segment(const char* name,
   else if (parameters->target().get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
-      return this->do_define_in_output_segment<64>(name, version, os,
-                                                   value, symsize, type,
+      return this->do_define_in_output_segment<64>(aname, aversion, os,
+                                                   avalue, sym_size, type,
                                                    binding, visibility, nonvis,
-                                                   offset_base, only_if_ref);
+                                                   offsetbase, only_if_ref);
 #else
       gold_unreachable();
 #endif
@@ -1717,26 +1839,28 @@ Symbol_table::define_in_output_segment(const char* name,
 template<int size>
 Sized_symbol<size>*
 Symbol_table::do_define_in_output_segment(
-    const char* name,
-    const char* version,
+    const char* aname,
+    const char* aversion,
     Output_segment* os,
-    typename elfcpp::Elf_types<size>::Elf_Addr value,
-    typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+    typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+    typename elfcpp::Elf_types<size>::Elf_WXword sym_size,
     elfcpp::STT type,
     elfcpp::STB binding,
     elfcpp::STV visibility,
     unsigned char nonvis,
-    Symbol::Segment_offset_base offset_base,
+    Symbol::Segment_offset_base offsetbase,
     bool only_if_ref)
 {
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
+  bool resolve_oldsym;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
-      sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym);
+      sym = this->define_special_symbol<size, true>(&aname, &aversion,
+                                                   only_if_ref, &oldsym,
+                                                   &resolve_oldsym);
 #else
       gold_unreachable();
 #endif
@@ -1744,8 +1868,9 @@ Symbol_table::do_define_in_output_segment(
   else
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
-      sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    only_if_ref, &oldsym);
+      sym = this->define_special_symbol<size, false>(&aname, &aversion,
+                                                    only_if_ref, &oldsym,
+                                                    &resolve_oldsym);
 #else
       gold_unreachable();
 #endif
@@ -1754,33 +1879,39 @@ Symbol_table::do_define_in_output_segment(
   if (sym == NULL)
     return NULL;
 
-  sym->init_output_segment(name, version, os, value, symsize, type, binding,
-                          visibility, nonvis, offset_base);
+  sym->init_output_segment(aname, aversion, os, avalue, sym_size, type, binding,
+                          visibility, nonvis, offsetbase);
 
   if (oldsym == NULL)
     {
       if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+         || this->version_script_.symbol_is_local(aname))
        this->force_local(sym);
-      else if (version != NULL)
+      else if (aversion != NULL)
        sym->set_is_default();
       return sym;
     }
 
   if (Symbol_table::should_override_with_special(oldsym))
     this->override_with_special(oldsym, sym);
-  delete sym;
-  return oldsym;
+
+  if (resolve_oldsym)
+    return sym;
+  else
+    {
+      delete sym;
+      return oldsym;
+    }
 }
 
 // Define a special symbol with a constant value.  It is a multiple
 // definition error if this symbol is already defined.
 
 Symbol*
-Symbol_table::define_as_constant(const char* name,
-                                const char* version,
-                                uint64_t value,
-                                uint64_t symsize,
+Symbol_table::define_as_constant(const char* aname,
+                                const char* aversion,
+                                uint64_t avalue,
+                                uint64_t sym_size,
                                 elfcpp::STT type,
                                 elfcpp::STB binding,
                                 elfcpp::STV visibility,
@@ -1791,8 +1922,8 @@ Symbol_table::define_as_constant(const char* name,
   if (parameters->target().get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
-      return this->do_define_as_constant<32>(name, version, value,
-                                             symsize, type, binding,
+      return this->do_define_as_constant<32>(aname, aversion, avalue,
+                                             sym_size, type, binding,
                                              visibility, nonvis, only_if_ref,
                                              force_override);
 #else
@@ -1802,8 +1933,8 @@ Symbol_table::define_as_constant(const char* name,
   else if (parameters->target().get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
-      return this->do_define_as_constant<64>(name, version, value,
-                                             symsize, type, binding,
+      return this->do_define_as_constant<64>(aname, aversion, avalue,
+                                             sym_size, type, binding,
                                              visibility, nonvis, only_if_ref,
                                              force_override);
 #else
@@ -1819,10 +1950,10 @@ Symbol_table::define_as_constant(const char* name,
 template<int size>
 Sized_symbol<size>*
 Symbol_table::do_define_as_constant(
-    const char* name,
-    const char* version,
-    typename elfcpp::Elf_types<size>::Elf_Addr value,
-    typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+    const char* aname,
+    const char* aversion,
+    typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+    typename elfcpp::Elf_types<size>::Elf_WXword sym_size,
     elfcpp::STT type,
     elfcpp::STB binding,
     elfcpp::STV visibility,
@@ -1832,12 +1963,14 @@ Symbol_table::do_define_as_constant(
 {
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
+  bool resolve_oldsym;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
-      sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym);
+      sym = this->define_special_symbol<size, true>(&aname, &aversion,
+                                                   only_if_ref, &oldsym,
+                                                   &resolve_oldsym);
 #else
       gold_unreachable();
 #endif
@@ -1845,8 +1978,9 @@ Symbol_table::do_define_as_constant(
   else
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
-      sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    only_if_ref, &oldsym);
+      sym = this->define_special_symbol<size, false>(&aname, &aversion,
+                                                    only_if_ref, &oldsym,
+                                                    &resolve_oldsym);
 #else
       gold_unreachable();
 #endif
@@ -1855,29 +1989,35 @@ Symbol_table::do_define_as_constant(
   if (sym == NULL)
     return NULL;
 
-  sym->init_constant(name, version, value, symsize, type, binding, visibility,
+  sym->init_constant(aname, aversion, avalue, sym_size, type, binding, visibility,
                     nonvis);
 
   if (oldsym == NULL)
     {
       // Version symbols are absolute symbols with name == version.
       // We don't want to force them to be local.
-      if ((version == NULL
-          || name != version
-          || value != 0)
+      if ((aversion == NULL
+          || aname != aversion
+          || avalue != 0)
          && (binding == elfcpp::STB_LOCAL
-             || this->version_script_.symbol_is_local(name)))
+             || this->version_script_.symbol_is_local(aname)))
        this->force_local(sym);
-      else if (version != NULL
-              && (name != version || value != 0))
+      else if (aversion != NULL
+              && (aname != aversion || avalue != 0))
        sym->set_is_default();
       return sym;
     }
 
   if (force_override || Symbol_table::should_override_with_special(oldsym))
     this->override_with_special(oldsym, sym);
-  delete sym;
-  return oldsym;
+
+  if (resolve_oldsym)
+    return sym;
+  else
+    {
+      delete sym;
+      return oldsym;
+    }
 }
 
 // Define a set of symbols in output sections.
@@ -1939,13 +2079,13 @@ void
 Symbol_table::define_with_copy_reloc(
     Sized_symbol<size>* csym,
     Output_data* posd,
-    typename elfcpp::Elf_types<size>::Elf_Addr value)
+    typename elfcpp::Elf_types<size>::Elf_Addr avalue)
 {
   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);
+  Object* aobject = csym->object();
+  gold_assert(aobject->is_dynamic());
+  Dynobj* dynobj = static_cast<Dynobj*>(aobject);
 
   // Our copied variable has to override any variable in a shared
   // library.
@@ -1954,7 +2094,7 @@ Symbol_table::define_with_copy_reloc(
     binding = elfcpp::STB_GLOBAL;
 
   this->define_in_output_data(csym->name(), csym->version(),
-                             posd, value, csym->symsize(),
+                             posd, avalue, csym->symsize(),
                              csym->type(), binding,
                              csym->visibility(), csym->nonvis(),
                              false, false);
@@ -2032,20 +2172,22 @@ Symbol_table::do_add_undefined_symbols_from_command_line()
        p != parameters->options().undefined_end();
        ++p)
     {
-      const char* name = p->c_str();
+      const char* aname = p->c_str();
 
-      if (this->lookup(name) != NULL)
+      if (this->lookup(aname) != NULL)
        continue;
 
-      const char* version = NULL;
+      const char* aversion = NULL;
 
       Sized_symbol<size>* sym;
       Sized_symbol<size>* oldsym;
+      bool resolve_oldsym;
       if (parameters->target().is_big_endian())
        {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
-         sym = this->define_special_symbol<size, true>(&name, &version,
-                                                       false, &oldsym);
+         sym = this->define_special_symbol<size, true>(&aname, &aversion,
+                                                       false, &oldsym,
+                                                       &resolve_oldsym);
 #else
          gold_unreachable();
 #endif
@@ -2053,8 +2195,9 @@ Symbol_table::do_add_undefined_symbols_from_command_line()
       else
        {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
-         sym = this->define_special_symbol<size, false>(&name, &version,
-                                                        false, &oldsym);
+         sym = this->define_special_symbol<size, false>(&aname, &aversion,
+                                                        false, &oldsym,
+                                                        &resolve_oldsym);
 #else
          gold_unreachable();
 #endif
@@ -2062,7 +2205,7 @@ Symbol_table::do_add_undefined_symbols_from_command_line()
 
       gold_assert(oldsym == NULL);
 
-      sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+      sym->init_undefined(aname, aversion, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
                          elfcpp::STV_DEFAULT, 0);
       ++this->saw_undefined_;
     }
@@ -2101,6 +2244,12 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
          // Record any version information.
           if (sym->version() != NULL)
             versions->record_version(this, dynpool, sym);
+
+         // If the symbol is defined in a dynamic object and is
+         // referenced in a regular object, then mark the dynamic
+         // object as needed.  This is used to implement --as-needed.
+         if (sym->is_from_dynobj() && sym->in_reg())
+           sym->object()->set_is_needed();
        }
     }
 
@@ -2215,94 +2364,94 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool,
   return off;
 }
 
-// Finalize the symbol SYM.  This returns true if the symbol should be
-// added to the symbol table, false otherwise.
+// Compute the final value of SYM and store status in location PSTATUS.
+// During relaxation, this may be called multiple times for a symbol to
+// compute its would-be final value in each relaxation pass.
 
 template<int size>
-bool
-Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+typename Sized_symbol<size>::Value_type
+Symbol_table::compute_final_value(
+    const Sized_symbol<size>* sym,
+    Compute_final_value_status* pstatus) const
 {
   typedef typename Sized_symbol<size>::Value_type Value_type;
-
-  Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
-
-  // The default version of a symbol may appear twice in the symbol
-  // table.  We only need to finalize it once.
-  if (sym->has_symtab_index())
-    return false;
-
-  if (!sym->in_reg())
-    {
-      gold_assert(!sym->has_symtab_index());
-      sym->set_symtab_index(-1U);
-      gold_assert(sym->dynsym_index() == -1U);
-      return false;
-    }
-
-  Value_type value;
+  Value_type avalue;
 
   switch (sym->source())
     {
     case Symbol::FROM_OBJECT:
       {
        bool is_ordinary;
-       unsigned int shndx = sym->shndx(&is_ordinary);
+       unsigned int sec_shndx = sym->shndx(&is_ordinary);
 
-       // FIXME: We need some target specific support here.
        if (!is_ordinary
-           && shndx != elfcpp::SHN_ABS
-           && shndx != elfcpp::SHN_COMMON)
+           && sec_shndx != elfcpp::SHN_ABS
+           && !Symbol::is_common_shndx(sec_shndx))
          {
-           gold_error(_("%s: unsupported symbol section 0x%x"),
-                      sym->demangled_name().c_str(), shndx);
-           shndx = elfcpp::SHN_UNDEF;
+           *pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION;
+           return 0;
          }
 
        Object* symobj = sym->object();
        if (symobj->is_dynamic())
          {
-           value = 0;
-           shndx = elfcpp::SHN_UNDEF;
+           avalue = 0;
+           sec_shndx = elfcpp::SHN_UNDEF;
          }
        else if (symobj->pluginobj() != NULL)
          {
-           value = 0;
-           shndx = elfcpp::SHN_UNDEF;
+           avalue = 0;
+           sec_shndx = elfcpp::SHN_UNDEF;
          }
-       else if (shndx == elfcpp::SHN_UNDEF)
-         value = 0;
+       else if (sec_shndx == elfcpp::SHN_UNDEF)
+         avalue = 0;
        else if (!is_ordinary
-                && (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON))
-         value = sym->value();
+                && (sec_shndx == elfcpp::SHN_ABS
+                    || Symbol::is_common_shndx(sec_shndx)))
+         avalue = sym->value();
        else
          {
            Relobj* relobj = static_cast<Relobj*>(symobj);
-           Output_section* os = relobj->output_section(shndx);
+           Output_section* os = relobj->output_section(sec_shndx);
+            uint64_t secoff64 = relobj->output_section_offset(sec_shndx);
 
-           if (os == NULL)
+            if (this->is_section_folded(relobj, sec_shndx))
+              {
+                gold_assert(os == NULL);
+                // Get the os of the section it is folded onto.
+                Section_id folded = this->icf_->get_folded_section(relobj,
+                                                                   sec_shndx);
+                gold_assert(folded.first != NULL);
+                Relobj* folded_obj = reinterpret_cast<Relobj*>(folded.first);
+                os = folded_obj->output_section(folded.second);  
+                gold_assert(os != NULL);
+                secoff64 = folded_obj->output_section_offset(folded.second);
+              }
+
+           if (os == NULL)
              {
-               sym->set_symtab_index(-1U);
                 bool static_or_reloc = (parameters->doing_static_link() ||
                                         parameters->options().relocatable());
                 gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
 
-               return false;
+               *pstatus = CFVS_NO_OUTPUT_SECTION;
+               return 0;
              }
 
-            uint64_t secoff64 = relobj->output_section_offset(shndx);
             if (secoff64 == -1ULL)
               {
                 // The section needs special handling (e.g., a merge section).
-               value = os->output_address(relobj, shndx, sym->value());
+
+               avalue = os->output_address(relobj, sec_shndx, sym->value());
              }
             else
               {
                 Value_type secoff =
                   convert_types<Value_type, uint64_t>(secoff64);
                if (sym->type() == elfcpp::STT_TLS)
-                 value = sym->value() + os->tls_offset() + secoff;
+                 avalue = sym->value() + os->tls_offset() + secoff;
                else
-                 value = sym->value() + os->address() + secoff;
+                 avalue = sym->value() + os->address() + secoff;
              }
          }
       }
@@ -2311,35 +2460,35 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
     case Symbol::IN_OUTPUT_DATA:
       {
        Output_data* od = sym->output_data();
-       value = sym->value();
+       avalue = sym->value();
        if (sym->type() != elfcpp::STT_TLS)
-         value += od->address();
+         avalue += od->address();
        else
          {
            Output_section* os = od->output_section();
            gold_assert(os != NULL);
-           value += os->tls_offset() + (od->address() - os->address());
+           avalue += os->tls_offset() + (od->address() - os->address());
          }
        if (sym->offset_is_from_end())
-         value += od->data_size();
+         avalue += od->data_size();
       }
       break;
 
     case Symbol::IN_OUTPUT_SEGMENT:
       {
        Output_segment* os = sym->output_segment();
-       value = sym->value();
+       avalue = sym->value();
         if (sym->type() != elfcpp::STT_TLS)
-         value += os->vaddr();
+         avalue += os->vaddr();
        switch (sym->offset_base())
          {
          case Symbol::SEGMENT_START:
            break;
          case Symbol::SEGMENT_END:
-           value += os->memsz();
+           avalue += os->memsz();
            break;
          case Symbol::SEGMENT_BSS:
-           value += os->filesz();
+           avalue += os->filesz();
            break;
          default:
            gold_unreachable();
@@ -2348,20 +2497,72 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
       break;
 
     case Symbol::IS_CONSTANT:
-      value = sym->value();
+      avalue = sym->value();
       break;
 
     case Symbol::IS_UNDEFINED:
-      value = 0;
+      avalue = 0;
       break;
 
     default:
       gold_unreachable();
     }
 
-  sym->set_value(value);
+  *pstatus = CFVS_OK;
+  return avalue;
+}
+
+// Finalize the symbol SYM.  This returns true if the symbol should be
+// added to the symbol table, false otherwise.
+
+template<int size>
+bool
+Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+{
+  typedef typename Sized_symbol<size>::Value_type Value_type;
+
+  Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
+
+  // The default version of a symbol may appear twice in the symbol
+  // table.  We only need to finalize it once.
+  if (sym->has_symtab_index())
+    return false;
+
+  if (!sym->in_reg())
+    {
+      gold_assert(!sym->has_symtab_index());
+      sym->set_symtab_index(-1U);
+      gold_assert(sym->dynsym_index() == -1U);
+      return false;
+    }
+
+  // Compute final symbol value.
+  Compute_final_value_status status;
+  Value_type avalue = this->compute_final_value(sym, &status);
+
+  switch (status)
+    {
+    case CFVS_OK:
+      break;
+    case CFVS_UNSUPPORTED_SYMBOL_SECTION:
+      {
+       bool is_ordinary;
+       unsigned int sec_shndx = sym->shndx(&is_ordinary);
+       gold_error(_("%s: unsupported symbol section 0x%x"),
+                  sym->demangled_name().c_str(), sec_shndx);
+      }
+      break;
+    case CFVS_NO_OUTPUT_SECTION:
+      sym->set_symtab_index(-1U);
+      return false;
+    default:
+      gold_unreachable();
+    }
 
-  if (parameters->options().strip_all())
+  sym->set_value(avalue);
+
+  if (parameters->options().strip_all()
+      || !parameters->options().should_retain_symbol(sym->name()))
     {
       sym->set_symtab_index(-1U);
       return false;
@@ -2465,7 +2666,7 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
          continue;
        }
 
-      unsigned int shndx;
+      unsigned int sec_shndx;
       typename elfcpp::Elf_types<size>::Elf_Addr sym_value = sym->value();
       typename elfcpp::Elf_types<size>::Elf_Addr dynsym_value = sym_value;
       switch (sym->source())
@@ -2475,14 +2676,13 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
            bool is_ordinary;
            unsigned int in_shndx = sym->shndx(&is_ordinary);
 
-           // FIXME: We need some target specific support here.
            if (!is_ordinary
                && in_shndx != elfcpp::SHN_ABS
-               && in_shndx != elfcpp::SHN_COMMON)
+               && !Symbol::is_common_shndx(in_shndx))
              {
                gold_error(_("%s: unsupported symbol section 0x%x"),
                           sym->demangled_name().c_str(), in_shndx);
-               shndx = in_shndx;
+               sec_shndx = in_shndx;
              }
            else
              {
@@ -2491,29 +2691,42 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
                  {
                    if (sym->needs_dynsym_value())
                      dynsym_value = target.dynsym_value(sym);
-                   shndx = elfcpp::SHN_UNDEF;
+                   sec_shndx = elfcpp::SHN_UNDEF;
                  }
                else if (symobj->pluginobj() != NULL)
-                 shndx = elfcpp::SHN_UNDEF;
+                 sec_shndx = elfcpp::SHN_UNDEF;
                else if (in_shndx == elfcpp::SHN_UNDEF
                         || (!is_ordinary
                             && (in_shndx == elfcpp::SHN_ABS
-                                || in_shndx == elfcpp::SHN_COMMON)))
-                 shndx = in_shndx;
+                                || Symbol::is_common_shndx(in_shndx))))
+                 sec_shndx = in_shndx;
                else
                  {
                    Relobj* relobj = static_cast<Relobj*>(symobj);
                    Output_section* os = relobj->output_section(in_shndx);
+                    if (this->is_section_folded(relobj, in_shndx))
+                      {
+                        // This global symbol must be written out even though
+                        // it is folded.
+                        // Get the os of the section it is folded onto.
+                        Section_id folded =
+                             this->icf_->get_folded_section(relobj, in_shndx);
+                        gold_assert(folded.first !=NULL);
+                        Relobj* folded_obj = 
+                          reinterpret_cast<Relobj*>(folded.first);
+                        os = folded_obj->output_section(folded.second);  
+                        gold_assert(os != NULL);
+                      }
                    gold_assert(os != NULL);
-                   shndx = os->out_shndx();
+                   sec_shndx = os->out_shndx();
 
-                   if (shndx >= elfcpp::SHN_LORESERVE)
+                   if (sec_shndx >= elfcpp::SHN_LORESERVE)
                      {
                        if (sym_index != -1U)
-                         symtab_xindex->add(sym_index, shndx);
+                         symtab_xindex->add(sym_index, sec_shndx);
                        if (dynsym_index != -1U)
-                         dynsym_xindex->add(dynsym_index, shndx);
-                       shndx = elfcpp::SHN_XINDEX;
+                         dynsym_xindex->add(dynsym_index, sec_shndx);
+                       sec_shndx = elfcpp::SHN_XINDEX;
                      }
 
                    // In object files symbol values are section
@@ -2526,27 +2739,27 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
          break;
 
        case Symbol::IN_OUTPUT_DATA:
-         shndx = sym->output_data()->out_shndx();
-         if (shndx >= elfcpp::SHN_LORESERVE)
+         sec_shndx = sym->output_data()->out_shndx();
+         if (sec_shndx >= elfcpp::SHN_LORESERVE)
            {
              if (sym_index != -1U)
-               symtab_xindex->add(sym_index, shndx);
+               symtab_xindex->add(sym_index, sec_shndx);
              if (dynsym_index != -1U)
-               dynsym_xindex->add(dynsym_index, shndx);
-             shndx = elfcpp::SHN_XINDEX;
+               dynsym_xindex->add(dynsym_index, sec_shndx);
+             sec_shndx = elfcpp::SHN_XINDEX;
            }
          break;
 
        case Symbol::IN_OUTPUT_SEGMENT:
-         shndx = elfcpp::SHN_ABS;
+         sec_shndx = elfcpp::SHN_ABS;
          break;
 
        case Symbol::IS_CONSTANT:
-         shndx = elfcpp::SHN_ABS;
+         sec_shndx = elfcpp::SHN_ABS;
          break;
 
        case Symbol::IS_UNDEFINED:
-         shndx = elfcpp::SHN_UNDEF;
+         sec_shndx = elfcpp::SHN_UNDEF;
          break;
 
        default:
@@ -2558,7 +2771,7 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
          sym_index -= first_global_index;
          gold_assert(sym_index < output_count);
          unsigned char* ps = psyms + (sym_index * sym_size);
-         this->sized_write_symbol<size, big_endian>(sym, sym_value, shndx,
+         this->sized_write_symbol<size, big_endian>(sym, sym_value, sec_shndx,
                                                     sympool, ps);
        }
 
@@ -2567,7 +2780,7 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
          dynsym_index -= first_dynamic_global_index;
          gold_assert(dynsym_index < dynamic_count);
          unsigned char* pd = dynamic_view + (dynsym_index * sym_size);
-         this->sized_write_symbol<size, big_endian>(sym, dynsym_value, shndx,
+         this->sized_write_symbol<size, big_endian>(sym, dynsym_value, sec_shndx,
                                                     dynpool, pd);
        }
     }
@@ -2584,26 +2797,31 @@ template<int size, bool big_endian>
 void
 Symbol_table::sized_write_symbol(
     Sized_symbol<size>* sym,
-    typename elfcpp::Elf_types<size>::Elf_Addr value,
-    unsigned int shndx,
+    typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+    unsigned int sec_shndx,
     const Stringpool* pool,
     unsigned char* p) const
 {
   elfcpp::Sym_write<size, big_endian> osym(p);
   osym.put_st_name(pool->get_offset(sym->name()));
-  osym.put_st_value(value);
+  osym.put_st_value(avalue);
   // Use a symbol size of zero for undefined symbols from shared libraries.
-  if (shndx == elfcpp::SHN_UNDEF && sym->is_from_dynobj())
+  if (sec_shndx == elfcpp::SHN_UNDEF && sym->is_from_dynobj())
     osym.put_st_size(0);
   else
     osym.put_st_size(sym->symsize());
+  elfcpp::STT type = sym->type();
+  // Turn IFUNC symbols from shared libraries into normal FUNC symbols.
+  if (type == elfcpp::STT_GNU_IFUNC
+      && sym->is_from_dynobj())
+    type = elfcpp::STT_FUNC;
   // A version script may have overridden the default binding.
   if (sym->is_forced_local())
-    osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, sym->type()));
+    osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, type));
   else
-    osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
+    osym.put_st_info(elfcpp::elf_st_info(sym->binding(), type));
   osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis()));
-  osym.put_st_shndx(shndx);
+  osym.put_st_shndx(sec_shndx);
 }
 
 // Check for unresolved symbols in shared libraries.  This is
@@ -2693,19 +2911,22 @@ Symbol_table::sized_write_section_symbol(const Output_section* os,
 
   elfcpp::Sym_write<size, big_endian> osym(pov);
   osym.put_st_name(0);
-  osym.put_st_value(os->address());
+  if (parameters->options().relocatable())
+    osym.put_st_value(0);
+  else
+    osym.put_st_value(os->address());
   osym.put_st_size(0);
   osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL,
                                       elfcpp::STT_SECTION));
   osym.put_st_other(elfcpp::elf_st_other(elfcpp::STV_DEFAULT, 0));
 
-  unsigned int shndx = os->out_shndx();
-  if (shndx >= elfcpp::SHN_LORESERVE)
+  unsigned int sec_shndx = os->out_shndx();
+  if (sec_shndx >= elfcpp::SHN_LORESERVE)
     {
-      symtab_xindex->add(os->symtab_index(), shndx);
-      shndx = elfcpp::SHN_XINDEX;
+      symtab_xindex->add(os->symtab_index(), sec_shndx);
+      sec_shndx = elfcpp::SHN_XINDEX;
     }
-  osym.put_st_shndx(shndx);
+  osym.put_st_shndx(sec_shndx);
 
   of->write_output_view(offset, sym_size, pov);
 }
@@ -2808,11 +3029,11 @@ Symbol_table::detect_odr_violations(const Task* task,
 // Add a new warning.
 
 void
-Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
+Warnings::add_warning(Symbol_table* symtab, const char* aname, Object* obj,
                      const std::string& warning)
 {
-  name = symtab->canonicalize_name(name);
-  this->warnings_[name].set(obj, warning);
+  aname = symtab->canonicalize_name(aname);
+  this->warnings_[aname].set(obj, warning);
 }
 
 // Look through the warnings and mark the symbols for which we should
@@ -3032,7 +3253,7 @@ void
 Symbol_table::define_with_copy_reloc<32>(
     Sized_symbol<32>* sym,
     Output_data* posd,
-    elfcpp::Elf_types<32>::Elf_Addr value);
+    elfcpp::Elf_types<32>::Elf_Addr avalue);
 #endif
 
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
@@ -3041,7 +3262,7 @@ void
 Symbol_table::define_with_copy_reloc<64>(
     Sized_symbol<64>* sym,
     Output_data* posd,
-    elfcpp::Elf_types<64>::Elf_Addr value);
+    elfcpp::Elf_types<64>::Elf_Addr avalue);
 #endif
 
 #ifdef HAVE_TARGET_32_LITTLE
This page took 0.057689 seconds and 4 git commands to generate.