X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Fsymtab.cc;h=56d1e42b8b0b5eaaeef1f592f9d20d0b393bd84d;hb=cb24623460fe3e68794b79b79b0dbd5e62598d85;hp=a7edbb1f352fd228579536354be0e86b8cd0ec17;hpb=b60ecbc6ddeaf7af8f2515841b58035f0d4d2db7;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/symtab.cc b/gold/symtab.cc index a7edbb1f35..56d1e42b8b 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1,6 +1,6 @@ // symtab.cc -- the gold symbol table -// Copyright (C) 2006-2016 Free Software Foundation, Inc. +// Copyright (C) 2006-2019 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -47,8 +47,8 @@ namespace gold // Class Symbol. -// Initialize fields in Symbol. This initializes everything except u_ -// and source_. +// Initialize fields in Symbol. This initializes everything except +// u1_, u2_ and source_. void Symbol::init_fields(const char* name, const char* version, @@ -80,6 +80,8 @@ Symbol::init_fields(const char* name, const char* version, this->undef_binding_set_ = false; this->undef_binding_weak_ = false; this->is_predefined_ = false; + this->is_protected_ = false; + this->non_zero_localentry_ = false; } // Return the demangled version of the symbol's name, but only @@ -118,8 +120,8 @@ Symbol::init_base_object(const char* name, const char* version, Object* object, { this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(), sym.get_st_visibility(), sym.get_st_nonvis()); - this->u_.from_object.object = object; - this->u_.from_object.shndx = st_shndx; + this->u1_.object = object; + this->u2_.shndx = st_shndx; this->is_ordinary_shndx_ = is_ordinary; this->source_ = FROM_OBJECT; this->in_reg_ = !object->is_dynamic(); @@ -138,8 +140,8 @@ Symbol::init_base_output_data(const char* name, const char* version, bool is_predefined) { this->init_fields(name, version, type, binding, visibility, nonvis); - this->u_.in_output_data.output_data = od; - this->u_.in_output_data.offset_is_from_end = offset_is_from_end; + this->u1_.output_data = od; + this->u2_.offset_is_from_end = offset_is_from_end; this->source_ = IN_OUTPUT_DATA; this->in_reg_ = true; this->in_real_elf_ = true; @@ -158,8 +160,8 @@ Symbol::init_base_output_segment(const char* name, const char* version, bool is_predefined) { this->init_fields(name, version, type, binding, visibility, nonvis); - this->u_.in_output_segment.output_segment = os; - this->u_.in_output_segment.offset_base = offset_base; + this->u1_.output_segment = os; + this->u2_.offset_base = offset_base; this->source_ = IN_OUTPUT_SEGMENT; this->in_reg_ = true; this->in_real_elf_ = true; @@ -204,8 +206,8 @@ Symbol::allocate_base_common(Output_data* od) { gold_assert(this->is_common()); this->source_ = IN_OUTPUT_DATA; - this->u_.in_output_data.output_data = od; - this->u_.in_output_data.offset_is_from_end = false; + this->u1_.output_data = od; + this->u2_.offset_is_from_end = false; } // Initialize the fields in Sized_symbol for SYM in OBJECT. @@ -486,19 +488,19 @@ Symbol::output_section() const { case FROM_OBJECT: { - unsigned int shndx = this->u_.from_object.shndx; + unsigned int shndx = this->u2_.shndx; if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_) { - gold_assert(!this->u_.from_object.object->is_dynamic()); - gold_assert(this->u_.from_object.object->pluginobj() == NULL); - Relobj* relobj = static_cast(this->u_.from_object.object); + gold_assert(!this->u1_.object->is_dynamic()); + gold_assert(this->u1_.object->pluginobj() == NULL); + Relobj* relobj = static_cast(this->u1_.object); return relobj->output_section(shndx); } return NULL; } case IN_OUTPUT_DATA: - return this->u_.in_output_data.output_data->output_section(); + return this->u1_.output_data->output_section(); case IN_OUTPUT_SEGMENT: case IS_CONSTANT: @@ -525,8 +527,8 @@ Symbol::set_output_section(Output_section* os) break; case IS_CONSTANT: this->source_ = IN_OUTPUT_DATA; - this->u_.in_output_data.output_data = os; - this->u_.in_output_data.offset_is_from_end = false; + this->u1_.output_data = os; + this->u2_.offset_is_from_end = false; break; case IN_OUTPUT_SEGMENT: case IS_UNDEFINED: @@ -544,8 +546,8 @@ Symbol::set_output_segment(Output_segment* os, Segment_offset_base base) { gold_assert(this->is_predefined_); this->source_ = IN_OUTPUT_SEGMENT; - this->u_.in_output_segment.output_segment = os; - this->u_.in_output_segment.offset_base = base; + this->u1_.output_segment = os; + this->u2_.offset_base = base; } // Set the symbol to undefined. This is used for pre-defined @@ -881,6 +883,7 @@ Symbol_table::define_default_version(Sized_symbol* sym, ; else if (pdef->second->is_from_dynobj() && sym->is_from_dynobj() + && pdef->second->is_defined() && pdef->second->object() != sym->object()) ; else @@ -986,8 +989,8 @@ Symbol_table::add_from_object(Object* object, // ins.first->second: the value (Symbol*). // ins.second: true if new entry was inserted, false if not. - Sized_symbol* ret; - bool was_undefined; + Sized_symbol* ret = NULL; + bool was_undefined_in_reg; bool was_common; if (!ins.second) { @@ -995,7 +998,7 @@ Symbol_table::add_from_object(Object* object, ret = this->get_sized_symbol(ins.first->second); gold_assert(ret != NULL); - was_undefined = ret->is_undefined(); + was_undefined_in_reg = ret->is_undefined() && ret->in_reg(); // Commons from plugins are just placeholders. was_common = ret->is_common() && ret->object()->pluginobj() == NULL; @@ -1046,19 +1049,44 @@ Symbol_table::add_from_object(Object* object, // it, then change it to NAME/VERSION. ret = this->get_sized_symbol(insdefault.first->second); - was_undefined = ret->is_undefined(); - // Commons from plugins are just placeholders. - was_common = ret->is_common() && ret->object()->pluginobj() == NULL; - - this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object, - version, is_default_version); - if (parameters->options().gc_sections()) - this->gc_mark_dyn_syms(ret); - ins.first->second = ret; + // If the existing symbol already has a version, + // don't override it with the new symbol. + // This should only happen when the new symbol + // is from a shared library. + if (ret->version() != NULL) + { + if (!object->is_dynamic()) + { + gold_warning(_("%s: conflicting default version definition" + " for %s@@%s"), + object->name().c_str(), name, version); + if (ret->source() == Symbol::FROM_OBJECT) + gold_info(_("%s: %s: previous definition of %s@@%s here"), + program_name, + ret->object()->name().c_str(), + name, ret->version()); + } + ret = NULL; + is_default_version = false; + } + else + { + was_undefined_in_reg = ret->is_undefined() && ret->in_reg(); + // Commons from plugins are just placeholders. + was_common = (ret->is_common() + && ret->object()->pluginobj() == NULL); + + this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, + object, version, is_default_version); + if (parameters->options().gc_sections()) + this->gc_mark_dyn_syms(ret); + ins.first->second = ret; + } } - else + + if (ret == NULL) { - was_undefined = false; + was_undefined_in_reg = false; was_common = false; Sized_target* target = @@ -1102,9 +1130,10 @@ Symbol_table::add_from_object(Object* object, ret->set_is_default(); } - // Record every time we see a new undefined symbol, to speed up - // archive groups. - if (!was_undefined && ret->is_undefined()) + // Record every time we see a new undefined symbol, to speed up archive + // groups. We only care about symbols undefined in regular objects here + // because undefined symbols only in dynamic objects should't trigger rescans. + if (!was_undefined_in_reg && ret->is_undefined() && ret->in_reg()) { ++this->saw_undefined_; if (parameters->options().has_plugins()) @@ -1182,7 +1211,9 @@ Symbol_table::add_from_relobj( const char* name = sym_names + st_name; if (!parameters->options().relocatable() - && strcmp (name, "__gnu_lto_slim") == 0) + && name[0] == '_' + && name[1] == '_' + && strcmp (name + (name[2] == '_'), "__gnu_lto_slim") == 0) gold_info(_("%s: plugin needed to handle lto object"), relobj->name().c_str()); @@ -1324,6 +1355,9 @@ Symbol_table::add_from_relobj( res = this->add_from_object(relobj, name, name_key, ver, ver_key, is_default_version, *psym, st_shndx, is_ordinary, orig_st_shndx); + + if (res == NULL) + continue; if (is_forced_local) this->force_local(res); @@ -1405,6 +1439,9 @@ Symbol_table::add_from_pluginobj( is_default_version, *sym, st_shndx, is_ordinary, st_shndx); + if (res == NULL) + return NULL; + if (is_forced_local) this->force_local(res); @@ -1601,6 +1638,9 @@ Symbol_table::add_from_dynobj( } } + if (res == NULL) + continue; + // Note that it is possible that RES was overridden by an // earlier object, in which case it can't be aliased here. if (st_shndx != elfcpp::SHN_UNDEF @@ -1610,6 +1650,13 @@ Symbol_table::add_from_dynobj( && res->object() == dynobj) object_symbols.push_back(res); + // If the symbol has protected visibility in the dynobj, + // mark it as such if it was not overridden. + if (res->source() == Symbol::FROM_OBJECT + && res->object() == dynobj + && sym.get_st_visibility() == elfcpp::STV_PROTECTED) + res->set_is_protected(); + if (sympointers != NULL) (*sympointers)[i] = res; } @@ -1632,7 +1679,6 @@ Symbol_table::add_from_incrobj( Stringpool::Key ver_key = 0; bool is_default_version = false; - bool is_forced_local = false; Stringpool::Key name_key; name = this->namepool_.add(name, true, &name_key); @@ -1642,9 +1688,6 @@ Symbol_table::add_from_incrobj( is_default_version, *sym, st_shndx, is_ordinary, st_shndx); - if (is_forced_local) - this->force_local(res); - return res; } @@ -1744,8 +1787,9 @@ template Sized_symbol* Symbol_table::define_special_symbol(const char** pname, const char** pversion, bool only_if_ref, + elfcpp::STV visibility, Sized_symbol** poldsym, - bool* resolve_oldsym) + bool* resolve_oldsym, bool is_forced_local) { *resolve_oldsym = false; *poldsym = NULL; @@ -1754,7 +1798,7 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion, // the version script. std::string v; bool is_default_version = false; - if (*pversion == NULL) + if (!is_forced_local && *pversion == NULL) { bool is_global; if (this->version_script_.get_symbol_version(*pname, &v, &is_global)) @@ -1782,8 +1826,21 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion, oldsym = this->lookup(*pname, *pversion); if (oldsym == NULL && is_default_version) oldsym = this->lookup(*pname, NULL); - if (oldsym == NULL || !oldsym->is_undefined()) + if (oldsym == NULL) return NULL; + if (!oldsym->is_undefined()) + { + // Skip if the old definition is from a regular object. + if (!oldsym->is_from_dynobj()) + return NULL; + + // If the symbol has hidden or internal visibility, ignore + // definition and reference from a dynamic object. + if ((visibility == elfcpp::STV_HIDDEN + || visibility == elfcpp::STV_INTERNAL) + && !oldsym->in_reg()) + return NULL; + } *pname = oldsym->name(); if (is_default_version) @@ -1841,10 +1898,13 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion, add_to_table = true; add_loc = ins.first; - if (is_default_version && !insdefault.second) + if (is_default_version + && !insdefault.second + && insdefault.first->second->version() == NULL) { // We are adding NAME/VERSION, and it is the default - // version. We already have an entry for NAME/NULL. + // version. We already have an entry for NAME/NULL + // that does not already have a version. oldsym = insdefault.first->second; *resolve_oldsym = true; } @@ -1952,13 +2012,17 @@ Symbol_table::do_define_in_output_data( Sized_symbol* sym; Sized_symbol* oldsym; bool resolve_oldsym; + const bool is_forced_local = binding == elfcpp::STB_LOCAL; if (parameters->target().is_big_endian()) { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) sym = this->define_special_symbol(&name, &version, - only_if_ref, &oldsym, - &resolve_oldsym); + only_if_ref, + visibility, + &oldsym, + &resolve_oldsym, + is_forced_local); #else gold_unreachable(); #endif @@ -1967,8 +2031,11 @@ Symbol_table::do_define_in_output_data( { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) sym = this->define_special_symbol(&name, &version, - only_if_ref, &oldsym, - &resolve_oldsym); + only_if_ref, + visibility, + &oldsym, + &resolve_oldsym, + is_forced_local); #else gold_unreachable(); #endif @@ -1983,8 +2050,7 @@ Symbol_table::do_define_in_output_data( if (oldsym == NULL) { - if (binding == elfcpp::STB_LOCAL - || this->version_script_.symbol_is_local(name)) + if (is_forced_local || this->version_script_.symbol_is_local(name)) this->force_local(sym); else if (version != NULL) sym->set_is_default(); @@ -1999,8 +2065,7 @@ Symbol_table::do_define_in_output_data( else { if (defined == PREDEFINED - && (binding == elfcpp::STB_LOCAL - || this->version_script_.symbol_is_local(name))) + && (is_forced_local || this->version_script_.symbol_is_local(name))) this->force_local(oldsym); delete sym; return oldsym; @@ -2070,13 +2135,17 @@ Symbol_table::do_define_in_output_segment( Sized_symbol* sym; Sized_symbol* oldsym; bool resolve_oldsym; + const bool is_forced_local = binding == elfcpp::STB_LOCAL; if (parameters->target().is_big_endian()) { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) sym = this->define_special_symbol(&name, &version, - only_if_ref, &oldsym, - &resolve_oldsym); + only_if_ref, + visibility, + &oldsym, + &resolve_oldsym, + is_forced_local); #else gold_unreachable(); #endif @@ -2085,8 +2154,11 @@ Symbol_table::do_define_in_output_segment( { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) sym = this->define_special_symbol(&name, &version, - only_if_ref, &oldsym, - &resolve_oldsym); + only_if_ref, + visibility, + &oldsym, + &resolve_oldsym, + is_forced_local); #else gold_unreachable(); #endif @@ -2101,8 +2173,7 @@ Symbol_table::do_define_in_output_segment( if (oldsym == NULL) { - if (binding == elfcpp::STB_LOCAL - || this->version_script_.symbol_is_local(name)) + if (is_forced_local || this->version_script_.symbol_is_local(name)) this->force_local(sym); else if (version != NULL) sym->set_is_default(); @@ -2116,8 +2187,7 @@ Symbol_table::do_define_in_output_segment( return sym; else { - if (binding == elfcpp::STB_LOCAL - || this->version_script_.symbol_is_local(name)) + if (is_forced_local || this->version_script_.symbol_is_local(name)) this->force_local(oldsym); delete sym; return oldsym; @@ -2186,13 +2256,17 @@ Symbol_table::do_define_as_constant( Sized_symbol* sym; Sized_symbol* oldsym; bool resolve_oldsym; + const bool is_forced_local = binding == elfcpp::STB_LOCAL; if (parameters->target().is_big_endian()) { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) sym = this->define_special_symbol(&name, &version, - only_if_ref, &oldsym, - &resolve_oldsym); + only_if_ref, + visibility, + &oldsym, + &resolve_oldsym, + is_forced_local); #else gold_unreachable(); #endif @@ -2201,8 +2275,11 @@ Symbol_table::do_define_as_constant( { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) sym = this->define_special_symbol(&name, &version, - only_if_ref, &oldsym, - &resolve_oldsym); + only_if_ref, + visibility, + &oldsym, + &resolve_oldsym, + is_forced_local); #else gold_unreachable(); #endif @@ -2221,8 +2298,7 @@ Symbol_table::do_define_as_constant( if ((version == NULL || name != version || value != 0) - && (binding == elfcpp::STB_LOCAL - || this->version_script_.symbol_is_local(name))) + && (is_forced_local || this->version_script_.symbol_is_local(name))) this->force_local(sym); else if (version != NULL && (name != version || value != 0)) @@ -2238,8 +2314,7 @@ Symbol_table::do_define_as_constant( return sym; else { - if (binding == elfcpp::STB_LOCAL - || this->version_script_.symbol_is_local(name)) + if (is_forced_local || this->version_script_.symbol_is_local(name)) this->force_local(oldsym); delete sym; return oldsym; @@ -2429,8 +2504,11 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name) { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) sym = this->define_special_symbol(&name, &version, - false, &oldsym, - &resolve_oldsym); + false, + elfcpp::STV_DEFAULT, + &oldsym, + &resolve_oldsym, + false); #else gold_unreachable(); #endif @@ -2439,8 +2517,11 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) sym = this->define_special_symbol(&name, &version, - false, &oldsym, - &resolve_oldsym); + false, + elfcpp::STV_DEFAULT, + &oldsym, + &resolve_oldsym, + false); #else gold_unreachable(); #endif @@ -2454,17 +2535,39 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name) } // 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 -// updated dynamic symbol index. +// global dynamic symbol. Pointers to the global symbols are stored +// into the vector SYMS. The names are added to DYNPOOL. +// This returns an updated dynamic symbol index. unsigned int Symbol_table::set_dynsym_indexes(unsigned int index, + unsigned int* pforced_local_count, std::vector* syms, Stringpool* dynpool, Versions* versions) { - std::vector as_needed_sym; + // First process all the symbols which have been forced to be local, + // as they must appear before all global symbols. + unsigned int forced_local_count = 0; + for (Forced_locals::iterator p = this->forced_locals_.begin(); + p != this->forced_locals_.end(); + ++p) + { + Symbol* sym = *p; + gold_assert(sym->is_forced_local()); + if (sym->has_dynsym_index()) + continue; + if (!sym->should_add_dynsym_entry(this)) + sym->set_dynsym_index(-1U); + else + { + sym->set_dynsym_index(index); + ++index; + ++forced_local_count; + dynpool->add(sym->name(), false, NULL); + } + } + *pforced_local_count = forced_local_count; // Allow a target to set dynsym indexes. if (parameters->target().has_custom_set_dynsym_indexes()) @@ -2475,6 +2578,8 @@ Symbol_table::set_dynsym_indexes(unsigned int index, ++p) { Symbol* sym = p->second; + if (sym->is_forced_local()) + continue; if (!sym->should_add_dynsym_entry(this)) sym->set_dynsym_index(-1U); else @@ -2491,6 +2596,9 @@ Symbol_table::set_dynsym_indexes(unsigned int index, { Symbol* sym = p->second; + if (sym->is_forced_local()) + continue; + // Note that SYM may already have a dynamic symbol index, since // some symbols appear more than once in the symbol table, with // and without a version. @@ -2504,15 +2612,6 @@ Symbol_table::set_dynsym_indexes(unsigned int index, syms->push_back(sym); dynpool->add(sym->name(), false, NULL); - // If the symbol is defined in a dynamic object and is - // referenced strongly in a regular object, then mark the - // dynamic object as needed. This is used to implement - // --as-needed. - if (sym->is_from_dynobj() - && sym->in_reg() - && !sym->is_undef_binding_weak()) - sym->object()->set_is_needed(); - // Record any version information, except those from // as-needed libraries not seen to be needed. Note that the // is_needed state for such libraries can change in this loop. @@ -2523,24 +2622,19 @@ Symbol_table::set_dynsym_indexes(unsigned int index, || sym->object()->is_needed()) versions->record_version(this, dynpool, sym); else - as_needed_sym.push_back(sym); + { + if (parameters->options().warn_drop_version()) + gold_warning(_("discarding version information for " + "%s@%s, defined in unused shared library %s " + "(linked with --as-needed)"), + sym->name(), sym->version(), + sym->object()->name().c_str()); + sym->clear_version(); + } } } } - // Process version information for symbols from as-needed libraries. - for (std::vector::iterator p = as_needed_sym.begin(); - p != as_needed_sym.end(); - ++p) - { - Symbol* sym = *p; - - if (sym->object()->is_needed()) - versions->record_version(this, dynpool, sym); - else - sym->clear_version(); - } - // Finish up the versions. In some cases this may add new dynamic // symbols. index = versions->finalize(this, index, syms); @@ -2562,7 +2656,12 @@ Symbol_table::set_dynsym_indexes(unsigned int index, // Set the final values for all the symbols. The index of the first // global symbol in the output file is *PLOCAL_SYMCOUNT. Record the // file offset OFF. Add their names to POOL. Return the new file -// offset. Update *PLOCAL_SYMCOUNT if necessary. +// offset. Update *PLOCAL_SYMCOUNT if necessary. DYNOFF and +// DYN_GLOBAL_INDEX refer to the start of the symbols that will be +// written from the global symbol table in Symtab::write_globals(), +// which will include forced-local symbols. DYN_GLOBAL_INDEX is +// not necessarily the same as the sh_info field for the .dynsym +// section, which will point to the first real global symbol. off_t Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index, @@ -3097,12 +3196,23 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, // In object files symbol values are section // relative. if (parameters->options().relocatable()) - sym_value -= od->address(); + { + Output_section* os = od->output_section(); + gold_assert(os != NULL); + sym_value -= os->address(); + } } break; case Symbol::IN_OUTPUT_SEGMENT: - shndx = elfcpp::SHN_ABS; + { + Output_segment* oseg = sym->output_segment(); + Output_section* osect = oseg->first_section(); + if (osect == NULL) + shndx = elfcpp::SHN_ABS; + else + shndx = osect->out_shndx(); + } break; case Symbol::IS_CONSTANT: