aboutsummaryrefslogtreecommitdiff
path: root/gold/symtab.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/symtab.cc')
-rw-r--r--gold/symtab.cc76
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));
+ }
}
}
}