More symbol resolution code.
authorIan Lance Taylor <iant@google.com>
Thu, 7 Sep 2006 21:21:41 +0000 (21:21 +0000)
committerIan Lance Taylor <iant@google.com>
Thu, 7 Sep 2006 21:21:41 +0000 (21:21 +0000)
elfcpp/elfcpp.h
gold/po/gold.pot
gold/resolve.cc
gold/symtab.cc
gold/symtab.h

index 9af0b8d4de437669ee2361e02791fe4e92e94228..4f2a4abcba93d3c1f839da7b2353c1972bdeeb6c 100644 (file)
@@ -437,6 +437,13 @@ elf_st_nonvis(unsigned char other)
   return static_cast<STV>(other >> 2);
 }
 
+inline unsigned char
+elf_st_other(STV vis, unsigned char nonvis)
+{
+  return ((nonvis << 2)
+         + (static_cast<unsigned char>(vis) & 3));
+}
+
 } // End namespace elfcpp.
 
 // Include internal details after defining the types.
@@ -641,6 +648,56 @@ class Sym
   const internal::Sym_data<size>* p_;
 };
 
+// Writer class for an ELF symbol table entry.
+
+template<int size, bool big_endian>
+class Sym_write
+{
+ public:
+  Sym_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Sym_data<size>*>(p))
+  { }
+
+  void
+  put_st_name(Elf_Word v)
+  { this->p_->st_name = internal::convert_word<big_endian>(v); }
+
+  void
+  put_st_value(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->st_value = internal::convert_addr<size, big_endian>(v); }
+
+  void
+  put_st_size(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->st_size = internal::convert_wxword<size, big_endian>(v); }
+
+  void
+  put_st_info(unsigned char v)
+  { this->p_->st_info = v; }
+
+  void
+  put_st_info(STB bind, STT type)
+  { this->p_->st_info = elf_st_info(bind, type); }
+
+  void
+  put_st_other(unsigned char v)
+  { this->p_->st_other = v; }
+
+  void
+  put_st_other(STV vis, unsigned char nonvis)
+  { this->p_->st_other = elf_st_other(vis, nonvis); }
+
+  void
+  put_st_shndx(Elf_Half v)
+  { this->p_->st_shndx = internal::convert_half<big_endian>(v); }
+
+  Sym<size, big_endian>
+  sym()
+  { return Sym<size, big_endian>(reinterpret_cast<unsigned char*>(this->p_)); }
+
+ private:
+  internal::Sym_data<size>* p_;
+};
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFPCP_H)
index 35860a5f731630c0912078bc5bce178960a38f00..5d13088b132c9405288535e73f4299cacff71eb6 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-08-18 15:26-0700\n"
+"POT-Creation-Date: 2006-09-07 14:17-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -220,22 +220,22 @@ msgstr ""
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: resolve.cc:103
+#: resolve.cc:135
 #, c-format
 msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
 msgstr ""
 
-#: resolve.cc:109
+#: resolve.cc:141
 #, c-format
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
 
-#: symtab.cc:262
+#: symtab.cc:271
 #, c-format
 msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
 msgstr ""
 
-#: symtab.cc:275
+#: symtab.cc:284
 #, c-format
 msgid "%s: %s: bad symbol name offset %u at %lu\n"
 msgstr ""
index 8c7d828d82e2f9da8e03f6750a0ffcbb5cf3c251..4a9b35567f749051a55c4d1a49b9212ee968df8a 100644 (file)
 namespace gold
 {
 
+// Symbol methods used in this file.
+
+// Override the fields in Symbol.
+
+template<int size, bool big_endian>
+void
+Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
+                     Object* object)
+{
+  this->object_ = object;
+  this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
+  this->type_ = sym.get_st_type();
+  this->binding_ = sym.get_st_bind();
+  this->visibility_ = sym.get_st_visibility();
+  this->other_ = sym.get_st_nonvis();
+}
+
+// Override the fields in Sized_symbol.
+
+template<int size>
+template<bool big_endian>
+void
+Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
+                            Object* object)
+{
+  this->override_base(sym, object);
+  this->value_ = sym.get_st_value();
+  this->size_ = sym.get_st_size();
+}
+
 // Resolve a symbol.  This is called the second and subsequent times
 // we see a symbol.  TO is the pre-existing symbol.  SYM is the new
 // symbol, seen in OBJECT.
 
 template<int size, bool big_endian>
 void
-Symbol_table::resolve(Symbol* to,
+Symbol_table::resolve(Sized_symbol<size>* to,
                      const elfcpp::Sym<size, big_endian>& sym,
                      Object* object)
 {
@@ -84,6 +114,8 @@ Symbol_table::resolve(Symbol* to,
       break;
 
     default:
+      if (to->type() == elfcpp::STT_COMMON)
+       tobits |= (2 << 2);
       break;
     }
 
@@ -113,7 +145,12 @@ Symbol_table::resolve(Symbol* to,
     }
 
   if (object->is_dynamic())
-    frombits |= (1 << 1);
+    {
+      frombits |= (1 << 1);
+
+      // Record that we've seen this symbol in a dynamic object.
+      to->set_in_dyn();
+    }
 
   switch (sym.get_st_shndx())
     {
@@ -126,9 +163,13 @@ Symbol_table::resolve(Symbol* to,
       break;
 
     default:
+      if (sym.get_st_type() == elfcpp::STT_COMMON)
+       frombits |= (2 << 2);
       break;
     }
 
+  // FIXME: Warn if either but not both of TO and SYM are STT_TLS.
+
   // We use a giant switch table for symbol resolution.  This code is
   // unwieldy, but: 1) it is efficient; 2) we definitely handle all
   // cases; 3) it is easy to change the handling of a particular case.
@@ -147,64 +188,124 @@ Symbol_table::resolve(Symbol* to,
       return;
 
     case WEAK_DEF * 16 + DEF:
-      // In the original SVR4 linker, a weak definition followed by a
-      // regular definition was treated as a multiple definition
-      // error.  In the Solaris linker and the GNU linker, a weak
-      // definition followed by a regular definition causes the
-      // regular definition to be ignored.  We are currently
-      // compatible with the GNU linker.  In the future we should add
-      // a target specific option to change this.  FIXME.
+      // We've seen a weak definition, and now we see a strong
+      // definition.  In the original SVR4 linker, this was treated as
+      // a multiple definition error.  In the Solaris linker and the
+      // GNU linker, a weak definition followed by a regular
+      // definition causes the weak definition to be overridden.  We
+      // are currently compatible with the GNU linker.  In the future
+      // we should add a target specific option to change this.
+      // FIXME.
+      to->override(sym, object);
       return;
 
     case DYN_DEF * 16 + DEF:
     case DYN_WEAK_DEF * 16 + DEF:
+      // We've seen a definition in a dynamic object, and now we see a
+      // definition in a regular object.  The definition in the
+      // regular object overrides the definition in the dynamic
+      // object.
+      to->override(sym, object);
+      return;
+
     case UNDEF * 16 + DEF:
     case WEAK_UNDEF * 16 + DEF:
     case DYN_UNDEF * 16 + DEF:
     case DYN_WEAK_UNDEF * 16 + DEF:
+      // We've seen an undefined reference, and now we see a
+      // definition.  We use the definition.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + DEF:
     case WEAK_COMMON * 16 + DEF:
     case DYN_COMMON * 16 + DEF:
     case DYN_WEAK_COMMON * 16 + DEF:
+      // We've seen a common symbol and now we see a definition.  The
+      // definition overrides.  FIXME: We should optionally issue a
+      // warning.
+      to->override(sym, object);
+      return;
 
     case DEF * 16 + WEAK_DEF:
     case WEAK_DEF * 16 + WEAK_DEF:
+      // We've seen a definition and now we see a weak definition.  We
+      // ignore the new weak definition.
+      return;
+
     case DYN_DEF * 16 + WEAK_DEF:
     case DYN_WEAK_DEF * 16 + WEAK_DEF:
+      // We've seen a dynamic definition and now we see a regular weak
+      // definition.  The regular weak definition overrides.
+      to->override(sym, object);
+      return;
+
     case UNDEF * 16 + WEAK_DEF:
     case WEAK_UNDEF * 16 + WEAK_DEF:
     case DYN_UNDEF * 16 + WEAK_DEF:
     case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
+      // A weak definition of a currently undefined symbol.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + WEAK_DEF:
     case WEAK_COMMON * 16 + WEAK_DEF:
+      // A weak definition does not override a common definition.
+      return;
+
     case DYN_COMMON * 16 + WEAK_DEF:
     case DYN_WEAK_COMMON * 16 + WEAK_DEF:
+      // A weak definition does override a definition in a dynamic
+      // object.  FIXME: We should optionally issue a warning.
+      to->override(sym, object);
+      return;
 
     case DEF * 16 + DYN_DEF:
     case WEAK_DEF * 16 + DYN_DEF:
     case DYN_DEF * 16 + DYN_DEF:
     case DYN_WEAK_DEF * 16 + DYN_DEF:
+      // Ignore a dynamic definition if we already have a definition.
+      return;
+
     case UNDEF * 16 + DYN_DEF:
     case WEAK_UNDEF * 16 + DYN_DEF:
     case DYN_UNDEF * 16 + DYN_DEF:
     case DYN_WEAK_UNDEF * 16 + DYN_DEF:
+      // Use a dynamic definition if we have a reference.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + DYN_DEF:
     case WEAK_COMMON * 16 + DYN_DEF:
     case DYN_COMMON * 16 + DYN_DEF:
     case DYN_WEAK_COMMON * 16 + DYN_DEF:
+      // Ignore a dynamic definition if we already have a common
+      // definition.
+      return;
 
     case DEF * 16 + DYN_WEAK_DEF:
     case WEAK_DEF * 16 + DYN_WEAK_DEF:
     case DYN_DEF * 16 + DYN_WEAK_DEF:
     case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
+      // Ignore a weak dynamic definition if we already have a
+      // definition.
+      return;
+
     case UNDEF * 16 + DYN_WEAK_DEF:
     case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
     case DYN_UNDEF * 16 + DYN_WEAK_DEF:
     case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+      // Use a weak dynamic definition if we have a reference.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + DYN_WEAK_DEF:
     case WEAK_COMMON * 16 + DYN_WEAK_DEF:
     case DYN_COMMON * 16 + DYN_WEAK_DEF:
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
+      // Ignore a weak dynamic definition if we already have a common
+      // definition.
+      return;
 
     case DEF * 16 + UNDEF:
     case WEAK_DEF * 16 + UNDEF:
@@ -218,6 +319,8 @@ Symbol_table::resolve(Symbol* to,
     case WEAK_COMMON * 16 + UNDEF:
     case DYN_COMMON * 16 + UNDEF:
     case DYN_WEAK_COMMON * 16 + UNDEF:
+      // A new undefined reference tells us nothing.
+      return;
 
     case DEF * 16 + WEAK_UNDEF:
     case WEAK_DEF * 16 + WEAK_UNDEF:
@@ -231,6 +334,8 @@ Symbol_table::resolve(Symbol* to,
     case WEAK_COMMON * 16 + WEAK_UNDEF:
     case DYN_COMMON * 16 + WEAK_UNDEF:
     case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
+      // A new weak undefined reference tells us nothing.
+      return;
 
     case DEF * 16 + DYN_UNDEF:
     case WEAK_DEF * 16 + DYN_UNDEF:
@@ -244,6 +349,8 @@ Symbol_table::resolve(Symbol* to,
     case WEAK_COMMON * 16 + DYN_UNDEF:
     case DYN_COMMON * 16 + DYN_UNDEF:
     case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
+      // A new dynamic undefined reference tells us nothing.
+      return;
 
     case DEF * 16 + DYN_WEAK_UNDEF:
     case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
@@ -257,15 +364,29 @@ Symbol_table::resolve(Symbol* to,
     case WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
     case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+      // A new weak dynamic undefined reference tells us nothing.
+      return;
 
     case DEF * 16 + COMMON:
+      // A common symbol does not override a definition.
+      return;
+
     case WEAK_DEF * 16 + COMMON:
     case DYN_DEF * 16 + COMMON:
     case DYN_WEAK_DEF * 16 + COMMON:
+      // A common symbol does override a weak definition or a dynamic
+      // definition.
+      to->override(sym, object);
+      return;
+
     case UNDEF * 16 + COMMON:
     case WEAK_UNDEF * 16 + COMMON:
     case DYN_UNDEF * 16 + COMMON:
     case DYN_WEAK_UNDEF * 16 + COMMON:
+      // A common symbol is a definition for a reference.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + COMMON:
     case WEAK_COMMON * 16 + COMMON:
     case DYN_COMMON * 16 + COMMON:
@@ -309,8 +430,11 @@ Symbol_table::resolve(Symbol* to,
     case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
     case DYN_COMMON * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
-
+      abort();
       break;
+
+    default:
+      abort();
     }
 }
 
@@ -321,28 +445,28 @@ Symbol_table::resolve(Symbol* to,
 template
 void
 Symbol_table::resolve<32, true>(
-    Symbol* to,
+    Sized_symbol<32>* to,
     const elfcpp::Sym<32, true>& sym,
     Object* object);
 
 template
 void
 Symbol_table::resolve<32, false>(
-    Symbol* to,
+    Sized_symbol<32>* to,
     const elfcpp::Sym<32, false>& sym,
     Object* object);
 
 template
 void
 Symbol_table::resolve<64, true>(
-    Symbol* to,
+    Sized_symbol<64>* to,
     const elfcpp::Sym<64, true>& sym,
     Object* object);
 
 template
 void
 Symbol_table::resolve<64, false>(
-    Symbol* to,
+    Sized_symbol<64>* to,
     const elfcpp::Sym<64, false>& sym,
     Object* object);
 
index a410db3171ca805ba98b2bda3b1f30722f6af466..8cf7789b82fd7feb19548865e0d5059dcfb062c0 100644 (file)
@@ -15,10 +15,6 @@ namespace gold
 
 // Class Symbol.
 
-Symbol::~Symbol()
-{
-}
-
 // Initialize the fields in the base class Symbol.
 
 template<int size, bool big_endian>
@@ -34,9 +30,10 @@ Symbol::init_base(const char* name, const char* version, Object* object,
   this->binding_ = sym.get_st_bind();
   this->visibility_ = sym.get_st_visibility();
   this->other_ = sym.get_st_nonvis();
-  this->special_ = false;
-  this->def_ = false;
-  this->forwarder_ = false;
+  this->is_special_ = false;
+  this->is_def_ = false;
+  this->is_forwarder_ = false;
+  this->in_dyn_ = object->is_dynamic();
 }
 
 // Initialize the fields in Sized_symbol.
@@ -107,11 +104,22 @@ Symbol_table::resolve_forwards(Symbol* from) const
 // Resolve a Symbol with another Symbol.  This is only used in the
 // unusual case where there are references to both an unversioned
 // symbol and a symbol with a version, and we then discover that that
-// version is the default version.
+// version is the default version.  Because this is unusual, we do
+// this the slow way, by converting back to an ELF symbol.
 
+template<int size, bool big_endian>
 void
-Symbol_table::resolve(Symbol*, const Symbol*)
+Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from)
 {
+  unsigned char buf[elfcpp::Elf_sizes<size>::sym_size];
+  elfcpp::Sym_write<size, big_endian> esym(buf);
+  // We don't bother to set the st_name field.
+  esym.put_st_value(from->value());
+  esym.put_st_size(from->symsize());
+  esym.put_st_info(from->binding(), from->type());
+  esym.put_st_other(from->visibility(), from->other());
+  esym.put_st_shndx(from->shnum());
+  Symbol_table::resolve(to, esym.sym(), from->object());
 }
 
 // Add one symbol from OBJECT to the symbol table.  NAME is symbol
@@ -162,11 +170,11 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
   // ins.first->second: the value (Symbol*).
   // ins.second: true if new entry was inserted, false if not.
 
-  Symbol* ret;
+  Sized_symbol<size>* ret;
   if (!ins.second)
     {
       // We already have an entry for NAME/VERSION.
-      ret = ins.first->second;
+      ret = this->get_sized_symbol<size>(ins.first->second);
       assert(ret != NULL);
       Symbol_table::resolve(ret, sym, object);
 
@@ -182,7 +190,9 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
            {
              // This is the unfortunate case where we already have
              // entries for both NAME/VERSION and NAME/NULL.
-             Symbol_table::resolve(ret, insdef.first->second);
+             const Sized_symbol<size>* 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;
            }
@@ -196,18 +206,19 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
        {
          // We already have an entry for NAME/NULL.  Make
          // NAME/VERSION point to it.
-         ret = insdef.first->second;
+         ret = this->get_sized_symbol<size>(insdef.first->second);
          Symbol_table::resolve(ret, sym, object);
          ins.first->second = ret;
        }
       else
        {
-         Sized_symbol<size>* rs;
          Sized_target<size, big_endian>* target = object->sized_target();
-         if (target->has_make_symbol())
+         if (!target->has_make_symbol())
+           ret = new Sized_symbol<size>();
+         else
            {
-             rs = target->make_symbol();
-             if (rs == NULL)
+             ret = target->make_symbol();
+             if (ret == NULL)
                {
                  // This means that we don't want a symbol table
                  // entry after all.
@@ -222,11 +233,9 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
                  return NULL;
                }
            }
-         else
-           rs = new Sized_symbol<size>();
-         rs->init(name, version, object, sym);
 
-         ret = rs;
+         ret->init(name, version, object, sym);
+
          ins.first->second = ret;
          if (def)
            {
index c085dd9c7dd35821f0f23a63893846b6e8e58e84..a90ba5db8abfebc81fba5a8fe7fcf87b33765fb8 100644 (file)
@@ -32,8 +32,6 @@ class Sized_target;
 class Symbol
 {
  public:
-  virtual ~Symbol();
-
   // Return the symbol name.
   const char*
   name() const
@@ -45,18 +43,6 @@ class Symbol
   version() const
   { return this->version_; }
 
-  // Return whether this symbol is a forwarder.  This will never be
-  // true of a symbol found in the hash table, but may be true of
-  // symbol pointers attached to object files.
-  bool
-  is_forwarder() const
-  { return this->forwarder_; }
-
-  // Mark this symbol as a forwarder.
-  void
-  set_forwarder()
-  { this->forwarder_ = true; }
-
   // Return the object with which this symbol is associated.
   Object*
   object() const
@@ -67,11 +53,48 @@ class Symbol
   binding() const
   { return this->binding_; }
 
+  // Return the symbol type.
+  elfcpp::STT
+  type() const
+  { return this->type_; }
+
+  // Return the symbol visibility.
+  elfcpp::STV
+  visibility() const
+  { return this->visibility_; }
+
+  // Return the non-visibility part of the st_other field.
+  unsigned char
+  other() const
+  { return this->other_; }
+
   // Return the section index.
   unsigned int
   shnum() const
   { return this->shnum_; }
 
+  // Return whether this symbol is a forwarder.  This will never be
+  // true of a symbol found in the hash table, but may be true of
+  // symbol pointers attached to object files.
+  bool
+  is_forwarder() const
+  { return this->is_forwarder_; }
+
+  // Mark this symbol as a forwarder.
+  void
+  set_forwarder()
+  { this->is_forwarder_ = true; }
+
+  // Return whether this symbol was seen in a dynamic object.
+  bool
+  in_dyn() const
+  { return this->in_dyn_; }
+
+  // Mark this symbol as seen in a dynamic object.
+  void
+  set_in_dyn()
+  { this->in_dyn_ = true; }
+
  protected:
   // Instances of this class should always be created at a specific
   // size.
@@ -84,6 +107,11 @@ class Symbol
   init_base(const char *name, const char* version, Object* object,
            const elfcpp::Sym<size, big_endian>&);
 
+  // Override existing symbol.
+  template<int size, bool big_endian>
+  void
+  override_base(const elfcpp::Sym<size, big_endian>&, Object* object);
+
  private:
   Symbol(const Symbol&);
   Symbol& operator=(const Symbol&);
@@ -107,9 +135,9 @@ class Symbol
   unsigned int other_ : 6;
   // True if this symbol always requires special target-specific
   // handling.
-  bool special_ : 1;
+  bool is_special_ : 1;
   // True if this is the default version of the symbol.
-  bool def_ : 1;
+  bool is_def_ : 1;
   // True if this symbol really forwards to another symbol.  This is
   // used when we discover after the fact that two different entries
   // in the hash table really refer to the same symbol.  This will
@@ -117,7 +145,9 @@ class Symbol
   // for a symbol found in the list of symbols attached to an Object.
   // It forwards to the symbol found in the forwarders_ map of
   // Symbol_table.
-  bool forwarder_ : 1;
+  bool is_forwarder_ : 1;
+  // True if we've seen this symbol in a dynamic object.
+  bool in_dyn_ : 1;
 };
 
 // The parts of a symbol which are size specific.  Using a template
@@ -127,6 +157,9 @@ template<int size>
 class Sized_symbol : public Symbol
 {
  public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Value_type;
+  typedef typename elfcpp::Elf_types<size>::Elf_WXword Size_type;
+
   Sized_symbol()
   { }
 
@@ -136,14 +169,30 @@ class Sized_symbol : public Symbol
   init(const char *name, const char* version, Object* object,
        const elfcpp::Sym<size, big_endian>&);
 
+  // Override existing symbol.
+  template<bool big_endian>
+  void
+  override(const elfcpp::Sym<size, big_endian>&, Object* object);
+
+  // Return the symbol's value.
+  Value_type
+  value() const
+  { return this->value_; }
+
+  // Return the symbol's size (we can't call this 'size' because that
+  // is a template parameter).
+  Size_type
+  symsize() const
+  { return this->size_; }
+
  private:
   Sized_symbol(const Sized_symbol&);
   Sized_symbol& operator=(const Sized_symbol&);
 
   // Symbol value.
-  typename elfcpp::Elf_types<size>::Elf_Addr value_;
+  Value_type value_;
   // Symbol size.
-  typename elfcpp::Elf_types<size>::Elf_WXword size_;
+  Size_type size_;
 };
 
 // The main linker symbol table.
@@ -153,7 +202,7 @@ class Symbol_table
  public:
   Symbol_table();
 
-  virtual ~Symbol_table();
+  ~Symbol_table();
 
   // Add COUNT external symbols from OBJECT to the symbol table.  SYMS
   // is the symbols, SYM_NAMES is their names, SYM_NAME_SIZE is the
@@ -175,6 +224,15 @@ class Symbol_table
   get_size() const
   { return this->size_; }
 
+  // Return the sized version of a symbol in this table.
+  template<int size>
+  Sized_symbol<size>*
+  get_sized_symbol(Symbol*);
+
+  template<int size>
+  const Sized_symbol<size>*
+  get_sized_symbol(const Symbol*);
+
  private:
   Symbol_table(const Symbol_table&);
   Symbol_table& operator=(const Symbol_table&);
@@ -198,10 +256,13 @@ class Symbol_table
   // Resolve symbols.
   template<int size, bool big_endian>
   static void
-  resolve(Symbol* to, const elfcpp::Sym<size, big_endian>& sym, Object*);
+  resolve(Sized_symbol<size>* to,
+         const elfcpp::Sym<size, big_endian>& sym,
+         Object*);
 
+  template<int size, bool big_endian>
   static void
-  resolve(Symbol* to, const Symbol* from);
+  resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from);
 
   typedef std::pair<const char*, const char*> Symbol_table_key;
 
@@ -233,6 +294,24 @@ class Symbol_table
   Unordered_map<Symbol*, Symbol*> forwarders_;
 };
 
+// We inline get_sized_symbol for efficiency.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::get_sized_symbol(Symbol* sym)
+{
+  assert(size == this->get_size());
+  return static_cast<Sized_symbol<size>*>(sym);
+}
+
+template<int size>
+const Sized_symbol<size>*
+Symbol_table::get_sized_symbol(const Symbol* sym)
+{
+  assert(size == this->get_size());
+  return static_cast<const Sized_symbol<size>*>(sym);
+}
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_SYMTAB_H)