diff options
Diffstat (limited to 'gold/symtab.cc')
-rw-r--r-- | gold/symtab.cc | 76 |
1 files changed, 65 insertions, 11 deletions
diff --git a/gold/symtab.cc b/gold/symtab.cc index 9a55e6e..5857dd7 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -998,12 +998,64 @@ Symbol_table::add_from_object(Object* object, ret = this->get_sized_symbol<size>(ins.first->second); gold_assert(ret != NULL); + bool ret_is_ordinary; + const unsigned int ret_shndx = ret->shndx(&ret_is_ordinary); + 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); + // It's possible for a symbol to be defined in an object file + // using .symver to give it a version, and for there to also be + // a linker script giving that symbol the same version. We + // don't want to give a multiple-definition error for this + // harmless redefinition. + bool check_version = false; + bool erase_default_version = false; + bool no_default_version = false; + if (ret->source() == Symbol::FROM_OBJECT + && is_ordinary + && ret_shndx == st_shndx) + { + if (ret->object() == object) + check_version = true; + + if (version != NULL && version == ret->version()) + { + // Don't give a multiple-definition error if the hidden + // version from .symver is the same as the default version + // from the unversioned symbol. + if (is_default_version && !ret->is_default ()) + { + no_default_version = true; + if (insdefault.second) + { + // Don't make the unversioned symbol the default + // version. + is_default_version = false; + erase_default_version = true; + check_version = true; + } + } + else if (!is_default_version && ret->is_default ()) + { + // Don't make the unversioned symbol the default + // version. + ret->set_is_not_default(); + no_default_version = true; + check_version = true; + } + } + } + + if (!(check_version + && ret->is_defined() + && ret_is_ordinary + && (no_default_version + || ret->value() == sym.get_st_value()))) + 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); @@ -1012,13 +1064,7 @@ Symbol_table::add_from_object(Object* object, insdefault.first); else { - bool dummy; - if (version != NULL - && ret->source() == Symbol::FROM_OBJECT - && ret->object() == object - && is_ordinary - && ret->shndx(&dummy) == st_shndx - && ret->is_default()) + if (version != NULL && check_version) { // We have seen NAME/VERSION already, and marked it as the // default version, but now we see a definition for @@ -1032,9 +1078,17 @@ Symbol_table::add_from_object(Object* object, // In any other case, the two symbols should have generated // a multiple definition error. // (See PR gold/18703.) - ret->set_is_not_default(); + // If the hidden version from .symver is the same as the + // default version from the unversioned symbol, don't make + // the unversioned symbol the default versioned symbol. const Stringpool::Key vnull_key = 0; - this->table_.erase(std::make_pair(name_key, vnull_key)); + if (erase_default_version) + this->table_.erase(std::make_pair(name_key, vnull_key)); + else if (ret->object() == object) + { + ret->set_is_not_default(); + this->table_.erase(std::make_pair(name_key, vnull_key)); + } } } } |