aboutsummaryrefslogtreecommitdiff
path: root/gold/resolve.cc
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@gmail.com>2015-07-27 15:09:08 -0700
committerCary Coutant <ccoutant@gmail.com>2015-08-18 19:24:41 -0700
commitb45e00b3ed40589af75b8a36a67905ae265a20f8 (patch)
treeb9b7e0b810d2cc3327cb743f14f3241e173b0d5c /gold/resolve.cc
parente49433d22dae92a56ae15a8b5742cbf1f31d5fd1 (diff)
downloadgdb-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/resolve.cc')
-rw-r--r--gold/resolve.cc33
1 files changed, 24 insertions, 9 deletions
diff --git a/gold/resolve.cc b/gold/resolve.cc
index 22d1e78..2dcf7b5 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -243,7 +243,8 @@ Symbol_table::resolve(Sized_symbol<size>* to,
const elfcpp::Sym<size, big_endian>& sym,
unsigned int st_shndx, bool is_ordinary,
unsigned int orig_st_shndx,
- Object* object, const char* version)
+ Object* object, const char* version,
+ bool 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
@@ -380,7 +381,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
typename Sized_symbol<size>::Size_type tosize = to->symsize();
if (Symbol_table::should_override(to, frombits, fromtype, OBJECT,
object, &adjust_common_sizes,
- &adjust_dyndef))
+ &adjust_dyndef, is_default_version))
{
elfcpp::STB tobinding = to->binding();
typename Sized_symbol<size>::Value_type tovalue = to->value();
@@ -449,7 +450,7 @@ bool
Symbol_table::should_override(const Symbol* to, unsigned int frombits,
elfcpp::STT fromtype, Defined defined,
Object* object, bool* adjust_common_sizes,
- bool* adjust_dyndef)
+ bool* adjust_dyndef, bool is_default_version)
{
*adjust_common_sizes = false;
*adjust_dyndef = false;
@@ -596,9 +597,19 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits,
case DEF * 16 + DYN_DEF:
case WEAK_DEF * 16 + DYN_DEF:
+ // Ignore a dynamic definition if we already have a definition.
+ return false;
+
case DYN_DEF * 16 + DYN_DEF:
case DYN_WEAK_DEF * 16 + DYN_DEF:
- // Ignore a dynamic definition if we already have a definition.
+ // Ignore a dynamic definition if we already have a definition,
+ // unless the existing definition is an unversioned definition
+ // in the same dynamic object, and the new definition is a
+ // default version.
+ if (to->object() == object
+ && to->version() == NULL
+ && is_default_version)
+ return true;
return false;
case UNDEF * 16 + DYN_DEF:
@@ -919,7 +930,7 @@ Symbol_table::should_override_with_special(const Symbol* to,
unsigned int frombits = global_flag | regular_flag | def_flag;
bool ret = Symbol_table::should_override(to, frombits, fromtype, defined,
NULL, &adjust_common_sizes,
- &adjust_dyn_def);
+ &adjust_dyn_def, false);
gold_assert(!adjust_common_sizes && !adjust_dyn_def);
return ret;
}
@@ -1051,7 +1062,8 @@ Symbol_table::resolve<32, false>(
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
- const char* version);
+ const char* version,
+ bool is_default_version);
template
void
@@ -1062,7 +1074,8 @@ Symbol_table::resolve<32, true>(
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
- const char* version);
+ const char* version,
+ bool is_default_version);
#endif
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
@@ -1075,7 +1088,8 @@ Symbol_table::resolve<64, false>(
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
- const char* version);
+ const char* version,
+ bool is_default_version);
template
void
@@ -1086,7 +1100,8 @@ Symbol_table::resolve<64, true>(
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
- const char* version);
+ const char* version,
+ bool is_default_version);
#endif
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)