aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-09-07 21:21:41 +0000
committerIan Lance Taylor <iant@google.com>2006-09-07 21:21:41 +0000
commit1564db8db6620560889dd5baeae801623c00a595 (patch)
tree0d169f6071a1a4307765bd42f6d8576ce52d6e15 /gold
parent466bbf939d6756d579cb499f19654ac39b923d05 (diff)
downloadgdb-1564db8db6620560889dd5baeae801623c00a595.zip
gdb-1564db8db6620560889dd5baeae801623c00a595.tar.gz
gdb-1564db8db6620560889dd5baeae801623c00a595.tar.bz2
More symbol resolution code.
Diffstat (limited to 'gold')
-rw-r--r--gold/po/gold.pot10
-rw-r--r--gold/resolve.cc152
-rw-r--r--gold/symtab.cc51
-rw-r--r--gold/symtab.h123
4 files changed, 274 insertions, 62 deletions
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index 35860a5..5d13088 100644
--- a/gold/po/gold.pot
+++ b/gold/po/gold.pot
@@ -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 ""
diff --git a/gold/resolve.cc b/gold/resolve.cc
index 8c7d828..4a9b355 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -10,13 +10,43 @@
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);
diff --git a/gold/symtab.cc b/gold/symtab.cc
index a410db3..8cf7789 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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)
{
diff --git a/gold/symtab.h b/gold/symtab.h
index c085dd9..a90ba5d 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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)