From 1564db8db6620560889dd5baeae801623c00a595 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 7 Sep 2006 21:21:41 +0000 Subject: [PATCH] More symbol resolution code. --- elfcpp/elfcpp.h | 57 +++++++++++++++++++++ gold/po/gold.pot | 10 ++-- gold/resolve.cc | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++----- gold/symtab.cc | 51 +++++++++++-------- gold/symtab.h | 123 ++++++++++++++++++++++++++++++++++++-------- 5 files changed, 331 insertions(+), 62 deletions(-) diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h index 9af0b8d..4f2a4ab 100644 --- a/elfcpp/elfcpp.h +++ b/elfcpp/elfcpp.h @@ -437,6 +437,13 @@ elf_st_nonvis(unsigned char other) return static_cast(other >> 2); } +inline unsigned char +elf_st_other(STV vis, unsigned char nonvis) +{ + return ((nonvis << 2) + + (static_cast(vis) & 3)); +} + } // End namespace elfcpp. // Include internal details after defining the types. @@ -641,6 +648,56 @@ class Sym const internal::Sym_data* p_; }; +// Writer class for an ELF symbol table entry. + +template +class Sym_write +{ + public: + Sym_write(unsigned char* p) + : p_(reinterpret_cast*>(p)) + { } + + void + put_st_name(Elf_Word v) + { this->p_->st_name = internal::convert_word(v); } + + void + put_st_value(typename Elf_types::Elf_Addr v) + { this->p_->st_value = internal::convert_addr(v); } + + void + put_st_size(typename Elf_types::Elf_WXword v) + { this->p_->st_size = internal::convert_wxword(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(v); } + + Sym + sym() + { return Sym(reinterpret_cast(this->p_)); } + + private: + internal::Sym_data* p_; +}; + } // End namespace elfcpp. #endif // !defined(ELFPCP_H) 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 \n" "Language-Team: LANGUAGE \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 +void +Symbol::override_base(const elfcpp::Sym& 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 +template +void +Sized_symbol::override(const elfcpp::Sym& 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 void -Symbol_table::resolve(Symbol* to, +Symbol_table::resolve(Sized_symbol* to, const elfcpp::Sym& 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 @@ -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 void -Symbol_table::resolve(Symbol*, const Symbol*) +Symbol_table::resolve(Sized_symbol* to, const Sized_symbol* from) { + unsigned char buf[elfcpp::Elf_sizes::sym_size]; + elfcpp::Sym_write 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* object, // ins.first->second: the value (Symbol*). // ins.second: true if new entry was inserted, false if not. - Symbol* ret; + Sized_symbol* ret; if (!ins.second) { // We already have an entry for NAME/VERSION. - ret = ins.first->second; + ret = this->get_sized_symbol(ins.first->second); assert(ret != NULL); Symbol_table::resolve(ret, sym, object); @@ -182,7 +190,9 @@ Symbol_table::add_from_object(Sized_object* 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* sym2 = + this->get_sized_symbol(insdef.first->second); + Symbol_table::resolve(ret, sym2); this->make_forwarder(insdef.first->second, ret); insdef.first->second = ret; } @@ -196,18 +206,19 @@ Symbol_table::add_from_object(Sized_object* object, { // We already have an entry for NAME/NULL. Make // NAME/VERSION point to it. - ret = insdef.first->second; + ret = this->get_sized_symbol(insdef.first->second); Symbol_table::resolve(ret, sym, object); ins.first->second = ret; } else { - Sized_symbol* rs; Sized_target* target = object->sized_target(); - if (target->has_make_symbol()) + if (!target->has_make_symbol()) + ret = new Sized_symbol(); + 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* object, return NULL; } } - else - rs = new Sized_symbol(); - 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&); + // Override existing symbol. + template + void + override_base(const elfcpp::Sym&, 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 class Sized_symbol : public Symbol { public: + typedef typename elfcpp::Elf_types::Elf_Addr Value_type; + typedef typename elfcpp::Elf_types::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&); + // Override existing symbol. + template + void + override(const elfcpp::Sym&, 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::Elf_Addr value_; + Value_type value_; // Symbol size. - typename elfcpp::Elf_types::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 + Sized_symbol* + get_sized_symbol(Symbol*); + + template + const Sized_symbol* + 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 static void - resolve(Symbol* to, const elfcpp::Sym& sym, Object*); + resolve(Sized_symbol* to, + const elfcpp::Sym& sym, + Object*); + template static void - resolve(Symbol* to, const Symbol* from); + resolve(Sized_symbol* to, const Sized_symbol* from); typedef std::pair Symbol_table_key; @@ -233,6 +294,24 @@ class Symbol_table Unordered_map forwarders_; }; +// We inline get_sized_symbol for efficiency. + +template +Sized_symbol* +Symbol_table::get_sized_symbol(Symbol* sym) +{ + assert(size == this->get_size()); + return static_cast*>(sym); +} + +template +const Sized_symbol* +Symbol_table::get_sized_symbol(const Symbol* sym) +{ + assert(size == this->get_size()); + return static_cast*>(sym); +} + } // End namespace gold. #endif // !defined(GOLD_SYMTAB_H) -- 2.7.4