diff options
-rw-r--r-- | gold/dynobj.cc | 12 | ||||
-rw-r--r-- | gold/resolve.cc | 33 | ||||
-rw-r--r-- | gold/symtab.cc | 31 | ||||
-rw-r--r-- | gold/symtab.h | 10 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 9 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 12 | ||||
-rw-r--r-- | gold/testsuite/ver_test_13.c | 7 | ||||
-rw-r--r-- | gold/testsuite/ver_test_13.script | 4 | ||||
-rwxr-xr-x | gold/testsuite/ver_test_13.sh | 59 | ||||
-rw-r--r-- | gold/testsuite/ver_test_4.cc | 10 | ||||
-rwxr-xr-x | gold/testsuite/ver_test_4.sh | 5 |
11 files changed, 171 insertions, 21 deletions
diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 13e3f61..9ab6bf8 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -1499,6 +1499,10 @@ Versions::record_version(const Symbol_table* symtab, gold_assert(!this->is_finalized_); gold_assert(sym->version() != NULL); + // A symbol defined as "sym@" is bound to an unspecified base version. + if (sym->version()[0] == '\0') + return; + Stringpool::Key version_key; const char* version = dynpool->add(sym->version(), false, &version_key); @@ -1731,15 +1735,17 @@ Versions::symbol_section_contents(const Symbol_table* symtab, { unsigned int version_index; const char* version = (*p)->version(); - if (version != NULL) - version_index = this->version_index(symtab, dynpool, *p); - else + if (version == NULL) { if ((*p)->is_defined() && !(*p)->is_from_dynobj()) version_index = elfcpp::VER_NDX_GLOBAL; else version_index = elfcpp::VER_NDX_LOCAL; } + else if (version[0] == '\0') + version_index = elfcpp::VER_NDX_GLOBAL; + else + version_index = this->version_index(symtab, dynpool, *p); // If the symbol was defined as foo@V1 instead of foo@@V1, add // the hidden bit. if ((*p)->version() != NULL && !(*p)->is_default()) 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) 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; diff --git a/gold/symtab.h b/gold/symtab.h index 2c9aa32..1a1f1c7 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -140,6 +140,11 @@ class Symbol set_is_default() { this->is_def_ = true; } + // Set that this version is not the default for this symbol name. + void + set_is_not_default() + { this->is_def_ = false; } + // Return the symbol's name as name@version (or name@@version). std::string versioned_name() const; @@ -1706,7 +1711,8 @@ class Symbol_table const elfcpp::Sym<size, big_endian>& sym, unsigned int st_shndx, bool is_ordinary, unsigned int orig_st_shndx, - Object*, const char* version); + Object*, const char* version, + bool is_default_version); template<int size, bool big_endian> void @@ -1725,7 +1731,7 @@ class Symbol_table // resolve.cc. static bool should_override(const Symbol*, unsigned int, elfcpp::STT, Defined, - Object*, bool*, bool*); + Object*, bool*, bool*, bool); // Report a problem in symbol resolution. static void diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index ca07016..5ceaeef 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -1563,6 +1563,15 @@ ver_test_12_LDADD = ver_test_12.o ver_test_12.o: gcctestdir/ld ver_test_1.o ver_test_2.o ver_test_4.o gcctestdir/ld -r -o $@ ver_test_1.o ver_test_2.o ver_test_4.o +check_SCRIPTS += ver_test_13.sh +check_DATA += ver_test_13.syms +ver_test_13.syms: ver_test_13.so + $(TEST_READELF) -s $< >$@ 2>/dev/null +ver_test_13.so: gcctestdir/ld ver_test_13.o ver_test_13.script + $(LINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_13.script ver_test_13.o +ver_test_13.o: ver_test_13.c + $(COMPILE) -c -fpic -o $@ $< + check_PROGRAMS += protected_1 protected_1_SOURCES = \ protected_main_1.cc protected_main_2.cc protected_main_3.cc diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index d4cc5dc..9cabcd8 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -327,7 +327,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.sh ver_test_2.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_4.sh ver_test_5.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.sh ver_test_10.sh \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test.sh \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_13.sh relro_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.sh \ @@ -371,7 +371,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.syms ver_test_2.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_4.syms ver_test_5.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.syms ver_test_10.syms \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_3.err \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_13.syms protected_3.err \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ relro_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \ @@ -4432,6 +4432,8 @@ ver_test_7.sh.log: ver_test_7.sh @p='ver_test_7.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) ver_test_10.sh.log: ver_test_10.sh @p='ver_test_10.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +ver_test_13.sh.log: ver_test_13.sh + @p='ver_test_13.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) relro_test.sh.log: relro_test.sh @p='relro_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) ver_matching_test.sh.log: ver_matching_test.sh @@ -5747,6 +5749,12 @@ uninstall-am: @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^ @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_12.o: gcctestdir/ld ver_test_1.o ver_test_2.o ver_test_4.o @GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ ver_test_1.o ver_test_2.o ver_test_4.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_13.syms: ver_test_13.so +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null +@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_13.so: gcctestdir/ld ver_test_13.o ver_test_13.script +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_13.script ver_test_13.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_13.o: ver_test_13.c +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fpic -o $@ $< @GCC_TRUE@@NATIVE_LINKER_TRUE@protected_1.so: gcctestdir/ld protected_1_pic.o protected_2_pic.o protected_3_pic.o @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared protected_1_pic.o protected_2_pic.o protected_3_pic.o diff --git a/gold/testsuite/ver_test_13.c b/gold/testsuite/ver_test_13.c new file mode 100644 index 0000000..01f4ba7 --- /dev/null +++ b/gold/testsuite/ver_test_13.c @@ -0,0 +1,7 @@ +__asm__ (".symver foo, foo@VER_0"); + +int foo(void); + +int foo(void) { + return 0; +} diff --git a/gold/testsuite/ver_test_13.script b/gold/testsuite/ver_test_13.script new file mode 100644 index 0000000..f0205cf --- /dev/null +++ b/gold/testsuite/ver_test_13.script @@ -0,0 +1,4 @@ +VER_0 { + global: + foo; +}; diff --git a/gold/testsuite/ver_test_13.sh b/gold/testsuite/ver_test_13.sh new file mode 100755 index 0000000..b0435ff --- /dev/null +++ b/gold/testsuite/ver_test_13.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +# ver_test_13.sh -- a test case for version script matching + +# Copyright (C) 2015 Free Software Foundation, Inc. +# Written by Cary Coutant <ccoutant@gmail.com>. + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +# This test verifies that a symbol declared with .symver as a +# non-default version does not get overridden by the version +# script and declared as a default version. +# (See PR gold/18703.) + +check() +{ + if ! grep -q "$2" "$1" + then + echo "Did not find expected symbol in $1:" + echo " $2" + echo "" + echo "Actual output below:" + cat "$1" + exit 1 + fi +} + +check_missing() +{ + if grep -q "$2" "$1" + then + echo "Found unexpected symbol in $1:" + echo " $2" + echo "" + echo "Actual output below:" + cat "$1" + exit 1 + fi +} + +check ver_test_13.syms "foo@VER_0$" +check_missing ver_test_13.syms "foo@@VER_0" + +exit 0 diff --git a/gold/testsuite/ver_test_4.cc b/gold/testsuite/ver_test_4.cc index 7a5544e..2fdba21 100644 --- a/gold/testsuite/ver_test_4.cc +++ b/gold/testsuite/ver_test_4.cc @@ -22,6 +22,16 @@ #include "ver_test.h" +__asm__(".symver t1_2_orig,t1_2@"); + +extern "C" +int +t1_2_orig() +{ + TRACE + return 12; +} + __asm__(".symver t1_2_a,t1_2@@VER2"); extern "C" diff --git a/gold/testsuite/ver_test_4.sh b/gold/testsuite/ver_test_4.sh index 05305b1..bc67ef9 100755 --- a/gold/testsuite/ver_test_4.sh +++ b/gold/testsuite/ver_test_4.sh @@ -24,17 +24,18 @@ check() { - if ! grep -q "$2" "$1" + if ! sed '/\.symtab/q' "$1" | grep -q "$2" then echo "Did not find expected symbol in $1:" echo " $2" echo "" echo "Actual output below:" - cat "$1" + sed '/\.symtab/q' "$1" exit 1 fi } +check ver_test_4.syms "t1_2\$" check ver_test_4.syms "t1_2@@VER2" check ver_test_4.syms "t2_2@VER1" check ver_test_4.syms "t2_2@@VER2" |