diff options
Diffstat (limited to 'gold/symtab.cc')
-rw-r--r-- | gold/symtab.cc | 213 |
1 files changed, 194 insertions, 19 deletions
diff --git a/gold/symtab.cc b/gold/symtab.cc index ac14c01..9279d26 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -8,6 +8,7 @@ #include <utility> #include "object.h" +#include "dynobj.h" #include "output.h" #include "target.h" #include "workqueue.h" @@ -194,6 +195,7 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1, void Symbol_table::make_forwarder(Symbol* from, Symbol* to) { + assert(from != to); assert(!from->is_forwarder() && !to->is_forwarder()); this->forwarders_[from] = to; from->set_forwarder(); @@ -334,7 +336,7 @@ Symbol_table::add_from_object(Object* object, // NAME/NULL point to NAME/VERSION. insdef.first->second = ret; } - else + else if (insdef.first->second != ret) { // This is the unfortunate case where we already have // entries for both NAME/VERSION and NAME/NULL. @@ -424,8 +426,8 @@ Symbol_table::add_from_object(Object* object, template<int size, bool big_endian> void -Symbol_table::add_from_object( - Relobj* object, +Symbol_table::add_from_relobj( + Sized_relobj<size, big_endian>* relobj, const unsigned char* syms, size_t count, const char* sym_names, @@ -436,10 +438,10 @@ Symbol_table::add_from_object( if (this->get_size() == 0) this->set_size(size); - if (size != this->get_size() || size != object->target()->get_size()) + if (size != this->get_size() || size != relobj->target()->get_size()) { fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"), - program_name, object->name().c_str()); + program_name, relobj->name().c_str()); gold_exit(false); } @@ -456,11 +458,13 @@ Symbol_table::add_from_object( { fprintf(stderr, _("%s: %s: bad global symbol name offset %u at %lu\n"), - program_name, object->name().c_str(), st_name, + program_name, relobj->name().c_str(), st_name, static_cast<unsigned long>(i)); gold_exit(false); } + const char* name = sym_names + st_name; + // A symbol defined in a section which we are not including must // be treated as an undefined symbol. unsigned char symbuf[sym_size]; @@ -468,7 +472,7 @@ Symbol_table::add_from_object( unsigned int st_shndx = psym->get_st_shndx(); if (st_shndx != elfcpp::SHN_UNDEF && st_shndx < elfcpp::SHN_LORESERVE - && !object->is_section_included(st_shndx)) + && !relobj->is_section_included(st_shndx)) { memcpy(symbuf, p, sym_size); elfcpp::Sym_write<size, big_endian> sw(symbuf); @@ -476,8 +480,6 @@ Symbol_table::add_from_object( psym = &sym2; } - const char* name = sym_names + st_name; - // 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. @@ -488,7 +490,7 @@ Symbol_table::add_from_object( { Stringpool::Key name_key; name = this->namepool_.add(name, &name_key); - res = this->add_from_object(object, name, name_key, NULL, 0, + res = this->add_from_object(relobj, name, name_key, NULL, 0, false, *psym); } else @@ -507,7 +509,7 @@ Symbol_table::add_from_object( Stringpool::Key ver_key; ver = this->namepool_.add(ver, &ver_key); - res = this->add_from_object(object, name, name_key, ver, ver_key, + res = this->add_from_object(relobj, name, name_key, ver, ver_key, def, *psym); } @@ -515,6 +517,131 @@ Symbol_table::add_from_object( } } +// Add all the symbols in a dynamic object to the hash table. + +template<int size, bool big_endian> +void +Symbol_table::add_from_dynobj( + Sized_dynobj<size, big_endian>* dynobj, + const unsigned char* syms, + size_t count, + const char* sym_names, + size_t sym_name_size, + const unsigned char* versym, + size_t versym_size, + const std::vector<const char*>* version_map) +{ + // We take the size from the first object we see. + if (this->get_size() == 0) + this->set_size(size); + + if (size != this->get_size() || size != dynobj->target()->get_size()) + { + fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"), + program_name, dynobj->name().c_str()); + gold_exit(false); + } + + if (versym != NULL && versym_size / 2 < count) + { + fprintf(stderr, _("%s: %s: too few symbol versions\n"), + program_name, dynobj->name().c_str()); + gold_exit(false); + } + + const int sym_size = elfcpp::Elf_sizes<size>::sym_size; + + const unsigned char* p = syms; + const unsigned char* vs = versym; + for (size_t i = 0; i < count; ++i, p += sym_size, vs += 2) + { + elfcpp::Sym<size, big_endian> sym(p); + + // Ignore symbols with local binding. + if (sym.get_st_bind() == elfcpp::STB_LOCAL) + continue; + + unsigned int st_name = sym.get_st_name(); + if (st_name >= sym_name_size) + { + fprintf(stderr, _("%s: %s: bad symbol name offset %u at %lu\n"), + program_name, dynobj->name().c_str(), st_name, + static_cast<unsigned long>(i)); + gold_exit(false); + } + + const char* name = sym_names + st_name; + + if (versym == NULL) + { + Stringpool::Key name_key; + name = this->namepool_.add(name, &name_key); + this->add_from_object(dynobj, name, name_key, NULL, 0, + false, sym); + continue; + } + + // Read the version information. + + unsigned int v = elfcpp::Swap<16, big_endian>::readval(vs); + + bool hidden = (v & elfcpp::VERSYM_HIDDEN) != 0; + v &= elfcpp::VERSYM_VERSION; + + if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)) + { + // This symbol should not be visible outside the object. + continue; + } + + // At this point we are definitely going to add this symbol. + Stringpool::Key name_key; + name = this->namepool_.add(name, &name_key); + + if (v == static_cast<unsigned int>(elfcpp::VER_NDX_GLOBAL)) + { + // This symbol does not have a version. + this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym); + continue; + } + + if (v >= version_map->size()) + { + fprintf(stderr, + _("%s: %s: versym for symbol %zu out of range: %u\n"), + program_name, dynobj->name().c_str(), i, v); + gold_exit(false); + } + + const char* version = (*version_map)[v]; + if (version == NULL) + { + fprintf(stderr, _("%s: %s: versym for symbol %zu has no name: %u\n"), + program_name, dynobj->name().c_str(), i, v); + gold_exit(false); + } + + Stringpool::Key version_key; + version = this->namepool_.add(version, &version_key); + + // If this is an absolute symbol, and the version name and + // symbol name are the same, then this is the version definition + // symbol. These symbols exist to support using -u to pull in + // particular versions. We do not want to record a version for + // them. + if (sym.get_st_shndx() == elfcpp::SHN_ABS && name_key == version_key) + { + this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym); + continue; + } + + const bool def = !hidden && sym.get_st_shndx() != elfcpp::SHN_UNDEF; + + this->add_from_object(dynobj, name, name_key, version, version_key, + def, sym); + } +} + // 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. @@ -1142,8 +1269,8 @@ Warnings::issue_warning(Symbol* sym, const std::string& location) const template void -Symbol_table::add_from_object<32, true>( - Relobj* object, +Symbol_table::add_from_relobj<32, true>( + Sized_relobj<32, true>* relobj, const unsigned char* syms, size_t count, const char* sym_names, @@ -1152,8 +1279,8 @@ Symbol_table::add_from_object<32, true>( template void -Symbol_table::add_from_object<32, false>( - Relobj* object, +Symbol_table::add_from_relobj<32, false>( + Sized_relobj<32, false>* relobj, const unsigned char* syms, size_t count, const char* sym_names, @@ -1162,8 +1289,8 @@ Symbol_table::add_from_object<32, false>( template void -Symbol_table::add_from_object<64, true>( - Relobj* object, +Symbol_table::add_from_relobj<64, true>( + Sized_relobj<64, true>* relobj, const unsigned char* syms, size_t count, const char* sym_names, @@ -1172,12 +1299,60 @@ Symbol_table::add_from_object<64, true>( template void -Symbol_table::add_from_object<64, false>( - Relobj* object, +Symbol_table::add_from_relobj<64, false>( + Sized_relobj<64, false>* relobj, const unsigned char* syms, size_t count, const char* sym_names, size_t sym_name_size, Symbol** sympointers); +template +void +Symbol_table::add_from_dynobj<32, true>( + Sized_dynobj<32, true>* dynobj, + const unsigned char* syms, + size_t count, + const char* sym_names, + size_t sym_name_size, + const unsigned char* versym, + size_t versym_size, + const std::vector<const char*>* version_map); + +template +void +Symbol_table::add_from_dynobj<32, false>( + Sized_dynobj<32, false>* dynobj, + const unsigned char* syms, + size_t count, + const char* sym_names, + size_t sym_name_size, + const unsigned char* versym, + size_t versym_size, + const std::vector<const char*>* version_map); + +template +void +Symbol_table::add_from_dynobj<64, true>( + Sized_dynobj<64, true>* dynobj, + const unsigned char* syms, + size_t count, + const char* sym_names, + size_t sym_name_size, + const unsigned char* versym, + size_t versym_size, + const std::vector<const char*>* version_map); + +template +void +Symbol_table::add_from_dynobj<64, false>( + Sized_dynobj<64, false>* dynobj, + const unsigned char* syms, + size_t count, + const char* sym_names, + size_t sym_name_size, + const unsigned char* versym, + size_t versym_size, + const std::vector<const char*>* version_map); + } // End namespace gold. |