diff options
author | Cary Coutant <ccoutant@gmail.com> | 2015-07-27 15:09:08 -0700 |
---|---|---|
committer | Cary Coutant <ccoutant@gmail.com> | 2015-08-18 19:24:41 -0700 |
commit | b45e00b3ed40589af75b8a36a67905ae265a20f8 (patch) | |
tree | b9b7e0b810d2cc3327cb743f14f3241e173b0d5c /gold/symtab.cc | |
parent | e49433d22dae92a56ae15a8b5742cbf1f31d5fd1 (diff) | |
download | gdb-b45e00b3ed40589af75b8a36a67905ae265a20f8.zip gdb-b45e00b3ed40589af75b8a36a67905ae265a20f8.tar.gz gdb-b45e00b3ed40589af75b8a36a67905ae265a20f8.tar.bz2 |
Fix symbol versioning problems in PR 18703.
If a symbol is defined with ".symver foo,foo@VER", the assembler
creates two symbols in the object: one unversioned, and one with
the (non-default) version "VER". If foo is listed in a version
script, gold would then make the first of those symbols the
default version, and would ignore the second symbol as a
duplicate, without making it a non-default version. While this is
arguably reasonable behavior, it doesn't match Gnu ld behavior,
so this patch fixes that by allowing the second definition to
override the first by resetting the "default version" indication.
Several test cases from the Gnu ld testsuite also exposed another
related problem, where a symbol defined with ".symver foo,foo@",
placed into a shared library, is not handled properly by gold.
This patch also fixes that case, binding the symbol to the base
version.
gold/
PR gold/18703
* dynobj.cc (Versions::record_version): Handle symbol defined with
base version.
(Versions::symbol_section_contents): Likewise.
* symtab.h (Symbol::set_is_not_default): New class method.
(Symbol_table::resolve): Add is_default_version parameter.
(Symbol_table::should_override): Likewise.
* resolve.cc (Symbol_table::resolve): Add is_default_version parameter,
and pass to should_override. Adjust all callers and explicit
instantiations.
(Symbol_table::should_override): Add is_default_value parameter;
allow default version in a dynamic object to override existing
definition from same object.
* symtab.cc (Symbol_table::add_from_object): Handle case where same
symbol is defined as unversioned and non-default version in the same
object.
* testsuite/Makefile.am (ver_test_13): New test case.
* testsuite/Makefile.in: Regenerate.
* testsuite/ver_test_4.cc: Add test for symbol with base version.
* testsuite/ver_test_4.sh: Likewise.
* testsuite/ver_test_13.c: New source file.
* testsuite/ver_test_13.script: New version script.
* testsuite/ver_test_13.sh: New test case.
Diffstat (limited to 'gold/symtab.cc')
-rw-r--r-- | gold/symtab.cc | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/gold/symtab.cc b/gold/symtab.cc index 31ecc5c..7e30fbf 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -737,7 +737,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from) bool is_ordinary; unsigned int shndx = from->shndx(&is_ordinary); this->resolve(to, esym.sym(), shndx, is_ordinary, shndx, from->object(), - from->version()); + from->version(), true); if (from->in_reg()) to->set_in_reg(); if (from->in_dyn()) @@ -991,13 +991,38 @@ Symbol_table::add_from_object(Object* object, was_common = ret->is_common() && ret->object()->pluginobj() == NULL; this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object, - version); + version, is_default_version); if (parameters->options().gc_sections()) this->gc_mark_dyn_syms(ret); if (is_default_version) this->define_default_version<size, big_endian>(ret, insdefault.second, insdefault.first); + else if (version != NULL && ret->is_default()) + { + // We have seen NAME/VERSION already, and marked it as the + // default version, but now we see a definition for + // NAME/VERSION that is not the default version. This can + // happen when the assembler generates two symbols for + // a symbol as a result of a ".symver foo,foo@VER" + // directive. We see the first unversioned symbol and + // we may mark it as the default version (from a + // version script); then we see the second versioned + // symbol and we need to override the first. + // In any other case, the two symbols should have generated + // a multiple definition error. + // (See PR gold/18703.) + bool dummy; + if (ret->source() == Symbol::FROM_OBJECT + && ret->object() == object + && is_ordinary + && ret->shndx(&dummy) == st_shndx) + { + ret->set_is_not_default(); + const Stringpool::Key vnull_key = 0; + this->table_.erase(std::make_pair(name_key, vnull_key)); + } + } } else { @@ -1015,7 +1040,7 @@ Symbol_table::add_from_object(Object* object, was_common = ret->is_common() && ret->object()->pluginobj() == NULL; this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object, - version); + version, is_default_version); if (parameters->options().gc_sections()) this->gc_mark_dyn_syms(ret); ins.first->second = ret; |