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);
{
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())
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
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();
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;
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:
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;
}
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
- const char* version);
+ const char* version,
+ bool is_default_version);
template
void
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)
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
- const char* version);
+ const char* version,
+ bool is_default_version);
template
void
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)
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())
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
{
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;
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;
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
// 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
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
@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 \
@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 \
@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
@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
--- /dev/null
+__asm__ (".symver foo, foo@VER_0");
+
+int foo(void);
+
+int foo(void) {
+ return 0;
+}
--- /dev/null
+VER_0 {
+ global:
+ foo;
+};
--- /dev/null
+#!/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
#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"
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"