From 46fe162319cc0ad598f8aa74495ccde823349da2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 22 Oct 2007 23:08:22 +0000 Subject: [PATCH] Fix versions of copied symbols. --- gold/dynobj.cc | 43 +++++++++++++++++-------- gold/dynobj.h | 13 ++++++-- gold/i386.cc | 7 +---- gold/layout.cc | 14 +++++---- gold/layout.h | 2 ++ gold/resolve.cc | 16 ++++++++++ gold/symtab.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++++-- gold/symtab.h | 50 +++++++++++++++++++++-------- gold/x86_64.cc | 7 +---- 9 files changed, 187 insertions(+), 49 deletions(-) diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 2bf2373b846..499eda70da3 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -1190,11 +1190,28 @@ Versions::~Versions() delete *p; } +// Return the dynamic object which a symbol refers to. + +Dynobj* +Versions::get_dynobj_for_sym(const Symbol_table* symtab, + const Symbol* sym) const +{ + if (sym->is_copied_from_dynobj()) + return symtab->get_copy_source(sym); + else + { + Object* object = sym->object(); + gold_assert(object->is_dynamic()); + return static_cast(object); + } +} + // Record version information for a symbol going into the dynamic // symbol table. void Versions::record_version(const General_options* options, + const Symbol_table* symtab, Stringpool* dynpool, const Symbol* sym) { gold_assert(!this->is_finalized_); @@ -1203,7 +1220,7 @@ Versions::record_version(const General_options* options, Stringpool::Key version_key; const char* version = dynpool->add(sym->version(), false, &version_key); - if (!sym->is_from_dynobj()) + if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) { if (parameters->output_is_shared()) this->add_def(options, sym, version, version_key); @@ -1211,11 +1228,7 @@ Versions::record_version(const General_options* options, else { // This is a version reference. - - Object* object = sym->object(); - gold_assert(object->is_dynamic()); - Dynobj* dynobj = static_cast(object); - + Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym); this->add_need(dynpool, dynobj->soname(), version, version_key); } } @@ -1375,14 +1388,15 @@ Versions::finalize(const Target* target, Symbol_table* symtab, // pointers. unsigned int -Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const +Versions::version_index(const Symbol_table* symtab, const Stringpool* dynpool, + const Symbol* sym) const { Stringpool::Key version_key; const char* version = dynpool->find(sym->version(), &version_key); gold_assert(version != NULL); Key k; - if (!sym->is_from_dynobj()) + if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) { if (!parameters->output_is_shared()) return elfcpp::VER_NDX_GLOBAL; @@ -1390,9 +1404,7 @@ Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const } else { - Object* object = sym->object(); - gold_assert(object->is_dynamic()); - Dynobj* dynobj = static_cast(object); + Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym); Stringpool::Key filename_key; const char* filename = dynpool->find(dynobj->soname(), &filename_key); @@ -1412,7 +1424,8 @@ Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const template void -Versions::symbol_section_contents(const Stringpool* dynpool, +Versions::symbol_section_contents(const Symbol_table* symtab, + const Stringpool* dynpool, unsigned int local_symcount, const std::vector& syms, unsigned char** pp, @@ -1437,7 +1450,7 @@ Versions::symbol_section_contents(const Stringpool* dynpool, if (version == NULL) version_index = elfcpp::VER_NDX_GLOBAL; else - version_index = this->version_index(dynpool, *p); + version_index = this->version_index(symtab, dynpool, *p); elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2, version_index); } @@ -1561,6 +1574,7 @@ class Sized_dynobj<64, true>; template void Versions::symbol_section_contents<32, false>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, @@ -1573,6 +1587,7 @@ Versions::symbol_section_contents<32, false>( template void Versions::symbol_section_contents<32, true>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, @@ -1585,6 +1600,7 @@ Versions::symbol_section_contents<32, true>( template void Versions::symbol_section_contents<64, false>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, @@ -1597,6 +1613,7 @@ Versions::symbol_section_contents<64, false>( template void Versions::symbol_section_contents<64, true>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, diff --git a/gold/dynobj.h b/gold/dynobj.h index e6b0a526b01..78caaf9da30 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -411,7 +411,8 @@ class Versions // SYM is going into the dynamic symbol table and has a version. // Record the appropriate version information. void - record_version(const General_options*, Stringpool*, const Symbol* sym); + record_version(const General_options*, const Symbol_table* symtab, + Stringpool*, const Symbol* sym); // Set the version indexes. DYNSYM_INDEX is the index we should use // for the next dynamic symbol. We add new dynamic symbols to SYMS @@ -434,7 +435,8 @@ class Versions // version section (.gnu.version). template void - symbol_section_contents(const Stringpool*, unsigned int local_symcount, + symbol_section_contents(const Symbol_table*, const Stringpool*, + unsigned int local_symcount, const std::vector& syms, unsigned char**, unsigned int* ACCEPT_SIZE_ENDIAN) const; @@ -472,9 +474,14 @@ class Versions add_need(Stringpool*, const char* filename, const char* name, Stringpool::Key); + // Get the dynamic object to use for SYM. + Dynobj* + get_dynobj_for_sym(const Symbol_table*, const Symbol* sym) const; + // Return the version index to use for SYM. unsigned int - version_index(const Stringpool*, const Symbol* sym) const; + version_index(const Symbol_table*, const Stringpool*, + const Symbol* sym) const; // We keep a hash table mapping canonicalized name/version pairs to // a version base. diff --git a/gold/i386.cc b/gold/i386.cc index 4532bfd09cb..26888bfffb4 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -649,14 +649,9 @@ Target_i386::copy_reloc(const General_options* options, off_t offset = dynbss_size; dynbss->set_space_size(dynbss_size + symsize); - // Define the symbol in the .dynbss section. - symtab->define_in_output_data(this, ssym->name(), ssym->version(), - dynbss, offset, symsize, ssym->type(), - ssym->binding(), ssym->visibility(), - ssym->nonvis(), false, false); + symtab->define_with_copy_reloc(this, ssym, dynbss, offset); // Add the COPY reloc. - ssym->set_needs_dynsym_entry(); Reloc_section* rel_dyn = this->rel_dyn_section(layout); rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset); } diff --git a/gold/layout.cc b/gold/layout.cc index 727b335097e..ae2b23f6e96 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -578,7 +578,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // Create the version sections. We can't do this until the // dynamic string table is complete. - this->create_version_sections(&versions, local_dynamic_count, + this->create_version_sections(&versions, symtab, local_dynamic_count, dynamic_symbols, dynstr); } @@ -1214,6 +1214,7 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, void Layout::create_version_sections(const Versions* versions, + const Symbol_table* symtab, unsigned int local_symcount, const std::vector& dynamic_symbols, const Output_section* dynstr) @@ -1228,7 +1229,7 @@ Layout::create_version_sections(const Versions* versions, #ifdef HAVE_TARGET_32_BIG this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(32, true)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(32, true)); #else gold_unreachable(); @@ -1239,7 +1240,7 @@ Layout::create_version_sections(const Versions* versions, #ifdef HAVE_TARGET_32_LITTLE this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(32, false)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(32, false)); #else gold_unreachable(); @@ -1253,7 +1254,7 @@ Layout::create_version_sections(const Versions* versions, #ifdef HAVE_TARGET_64_BIG this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(64, true)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(64, true)); #else gold_unreachable(); @@ -1264,7 +1265,7 @@ Layout::create_version_sections(const Versions* versions, #ifdef HAVE_TARGET_64_LITTLE this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(64, false)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(64, false)); #else gold_unreachable(); @@ -1281,6 +1282,7 @@ template void Layout::sized_create_version_sections( const Versions* versions, + const Symbol_table* symtab, unsigned int local_symcount, const std::vector& dynamic_symbols, const Output_section* dynstr @@ -1294,7 +1296,7 @@ Layout::sized_create_version_sections( unsigned char* vbuf; unsigned int vsize; versions->symbol_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)( - &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize + symtab, &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize SELECT_SIZE_ENDIAN(size, big_endian)); Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2); diff --git a/gold/layout.h b/gold/layout.h index 441be944841..409290a6bbc 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -257,6 +257,7 @@ class Layout // Create the version sections. void create_version_sections(const Versions*, + const Symbol_table*, unsigned int local_symcount, const std::vector& dynamic_symbols, const Output_section* dynstr); @@ -264,6 +265,7 @@ class Layout template void sized_create_version_sections(const Versions* versions, + const Symbol_table*, unsigned int local_symcount, const std::vector& dynamic_symbols, const Output_section* dynstr diff --git a/gold/resolve.cc b/gold/resolve.cc index 8836a3afed7..7d141c02534 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -620,6 +620,8 @@ Symbol_table::should_override_with_special(const Symbol* to) void Symbol::override_base_with_special(const Symbol* from) { + gold_assert(this->name_ == from->name_ || this->has_alias()); + this->source_ = from->source_; switch (from->source_) { @@ -652,6 +654,20 @@ Symbol::override_base_with_special(const Symbol* from) // Special symbols are always considered to be regular symbols. this->in_reg_ = true; + + if (from->needs_dynsym_entry_) + this->needs_dynsym_entry_ = true; + if (from->needs_dynsym_value_) + this->needs_dynsym_value_ = true; + + // We shouldn't see these flags. If we do, we need to handle them + // somehow. + gold_assert(!from->is_target_special_ || this->is_target_special_); + gold_assert(!from->is_forwarder_); + gold_assert(!from->has_got_offset_); + gold_assert(!from->has_plt_offset_); + gold_assert(!from->has_warning_); + gold_assert(!from->is_copied_from_dynobj_); } // Override a symbol with a special symbol. diff --git a/gold/symtab.cc b/gold/symtab.cc index 3eee9be8545..1f120dd190d 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -66,6 +66,7 @@ Symbol::init_fields(const char* name, const char* version, this->has_got_offset_ = false; this->has_plt_offset_ = false; this->has_warning_ = false; + this->is_copied_from_dynobj_ = false; } // Initialize the fields in the base class Symbol for SYM in OBJECT. @@ -1223,6 +1224,70 @@ Symbol_table::define_symbols(const Layout* layout, const Target* target, } } +// Define CSYM using a COPY reloc. POSD is the Output_data where the +// symbol should be defined--typically a .dyn.bss section. VALUE is +// the offset within POSD. + +template +void +Symbol_table::define_with_copy_reloc(const Target* target, + Sized_symbol* csym, + Output_data* posd, uint64_t value) +{ + 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(object); + + // Our copied variable has to override any variable in a shared + // library. + elfcpp::STB binding = csym->binding(); + if (binding == elfcpp::STB_WEAK) + binding = elfcpp::STB_GLOBAL; + + this->define_in_output_data(target, csym->name(), csym->version(), + posd, value, csym->symsize(), + csym->type(), binding, + csym->visibility(), csym->nonvis(), + false, false); + + csym->set_is_copied_from_dynobj(); + csym->set_needs_dynsym_entry(); + + this->copied_symbol_dynobjs_[csym] = dynobj; + + // We have now defined all aliases, but we have not entered them all + // in the copied_symbol_dynobjs_ map. + if (csym->has_alias()) + { + Symbol* sym = csym; + while (true) + { + sym = this->weak_aliases_[sym]; + if (sym == csym) + break; + gold_assert(sym->output_data() == posd); + + sym->set_is_copied_from_dynobj(); + this->copied_symbol_dynobjs_[sym] = dynobj; + } + } +} + +// SYM is defined using a COPY reloc. Return the dynamic object where +// the original definition was found. + +Dynobj* +Symbol_table::get_copy_source(const Symbol* sym) const +{ + gold_assert(sym->is_copied_from_dynobj()); + Copied_symbol_dynobjs::const_iterator p = + this->copied_symbol_dynobjs_.find(sym); + gold_assert(p != this->copied_symbol_dynobjs_.end()); + return p->second; +} + // Set the dynamic symbol indexes. INDEX is the index of the first // global dynamic symbol. Pointers to the symbols are stored into the // vector SYMS. The names are added to DYNPOOL. This returns an @@ -1257,7 +1322,7 @@ Symbol_table::set_dynsym_indexes(const General_options* options, // Record any version information. if (sym->version() != NULL) - versions->record_version(options, dynpool, sym); + versions->record_version(options, this, dynpool, sym); } } @@ -1901,6 +1966,22 @@ Symbol_table::add_from_dynobj<64, true>( const std::vector* version_map); #endif +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) +template +void +Symbol_table::define_with_copy_reloc<32>(const Target* target, + Sized_symbol<32>* sym, + Output_data* posd, uint64_t value); +#endif + +#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) +template +void +Symbol_table::define_with_copy_reloc<64>(const Target* target, + Sized_symbol<64>* sym, + Output_data* posd, uint64_t value); +#endif + #ifdef HAVE_TARGET_32_LITTLE template void @@ -1933,5 +2014,4 @@ Warnings::issue_warning<64, true>(const Symbol* sym, size_t relnum, off_t reloffset) const; #endif - } // End namespace gold. diff --git a/gold/symtab.h b/gold/symtab.h index f7576b9fd82..49ceb7a0323 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -422,6 +422,17 @@ class Symbol set_has_warning() { this->has_warning_ = true; } + // Return whether this symbol is defined by a COPY reloc from a + // dynamic object. + bool + is_copied_from_dynobj() const + { return this->is_copied_from_dynobj_; } + + // Mark this symbol as defined by a COPY reloc. + void + set_is_copied_from_dynobj() + { this->is_copied_from_dynobj_ = true; } + protected: // Instances of this class should always be created at a specific // size. @@ -573,6 +584,9 @@ class Symbol bool needs_dynsym_value_ : 1; // True if there is a warning for this symbol. bool has_warning_ : 1; + // True if we are using a COPY reloc for this symbol, so that the + // real definition lives in a dynamic object. + bool is_copied_from_dynobj_ : 1; }; // The parts of a symbol which are size specific. Using a template @@ -870,6 +884,14 @@ class Symbol_table define_symbols(const Layout*, const Target*, int count, const Define_symbol_in_segment*); + // Define SYM using a COPY reloc. POSD is the Output_data where the + // symbol should be defined--typically a .dyn.bss section. VALUE is + // the offset within POSD. + template + void + define_with_copy_reloc(const Target*, Sized_symbol* sym, + Output_data* posd, uint64_t value); + // Look up a symbol. Symbol* lookup(const char*, const char* version = NULL) const; @@ -915,6 +937,11 @@ class Symbol_table size_t relnum, off_t reloffset) const { this->warnings_.issue_warning(sym, relinfo, relnum, reloffset); } + // SYM is defined using a COPY reloc. Return the dynamic object + // where the original definition was found. + Dynobj* + get_copy_source(const Symbol* sym) const; + // Set the dynamic symbol indexes. INDEX is the index of the first // global dynamic symbol. Pointers to the symbols are stored into // the vector. The names are stored into the Stringpool. This @@ -1089,55 +1116,52 @@ class Symbol_table Symbol_table_eq> Symbol_table_type; // The type of the list of common symbols. - typedef std::vector Commons_type; + // A map from symbols with COPY relocs to the dynamic objects where + // they are defined. + typedef Unordered_map Copied_symbol_dynobjs; + // We increment this every time we see a new undefined symbol, for // use in archive groups. int saw_undefined_; - // The index of the first global symbol in the output file. unsigned int first_global_index_; - // The file offset within the output symtab section where we should // write the table. off_t offset_; - // The number of global symbols we want to write out. size_t output_count_; - // The file offset of the global dynamic symbols, or 0 if none. off_t dynamic_offset_; - // The index of the first global dynamic symbol. unsigned int first_dynamic_global_index_; - // The number of global dynamic symbols, or 0 if none. off_t dynamic_count_; - // The symbol hash table. Symbol_table_type table_; - // A pool of symbol names. This is used for all global symbols. // Entries in the hash table point into this pool. Stringpool namepool_; - // Forwarding symbols. Unordered_map forwarders_; - // Weak aliases. A symbol in this list points to the next alias. // The aliases point to each other in a circular list. Unordered_map weak_aliases_; - // We don't expect there to be very many common symbols, so we keep // a list of them. When we find a common symbol we add it to this // list. It is possible that by the time we process the list the // symbol is no longer a common symbol. It may also have become a // forwarder. Commons_type commons_; - // Manage symbol warnings. Warnings warnings_; + // When we emit a COPY reloc for a symbol, we define it in an + // Output_data. When it's time to emit version information for it, + // we need to know the dynamic object in which we found the original + // definition. This maps symbols with COPY relocs to the dynamic + // object where they were defined. + Copied_symbol_dynobjs copied_symbol_dynobjs_; }; // We inline get_sized_symbol for efficiency. diff --git a/gold/x86_64.cc b/gold/x86_64.cc index b6a8a4a2a77..0af7a16483c 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -621,14 +621,9 @@ Target_x86_64::copy_reloc(const General_options* options, off_t offset = dynbss_size; dynbss->set_space_size(dynbss_size + symsize); - // Define the symbol in the .dynbss section. - symtab->define_in_output_data(this, ssym->name(), ssym->version(), - dynbss, offset, symsize, ssym->type(), - ssym->binding(), ssym->visibility(), - ssym->nonvis(), false, false); + symtab->define_with_copy_reloc(this, ssym, dynbss, offset); // Add the COPY reloc. - ssym->set_needs_dynsym_entry(); Reloc_section* rela_dyn = this->rela_dyn_section(layout); rela_dyn->add_global(ssym, elfcpp::R_X86_64_COPY, dynbss, offset, 0); } -- 2.30.2