Fix problem where version script causes predefined hidden symbol to be defined twice.
authorCary Coutant <ccoutant@gmail.com>
Thu, 22 Dec 2016 01:32:39 +0000 (17:32 -0800)
committerCary Coutant <ccoutant@gmail.com>
Fri, 23 Dec 2016 00:00:06 +0000 (16:00 -0800)
When creating a predefined hidden symbol like _GLOBAL_OFFSET_TABLE_, gold
was incorrectly letting a version script add a version to the symbol,
resulting in two copies of the symbol, both STB_LOCAL, but one of which
was grouped in the globals part of the symbol table.

gold/
* symtab.cc (Symbol_table::define_special_symbol): Add is_forced_local
parameter; if set, do not check version script.
(Symbol_table::do_define_in_output_data): Pass is_forced_local for
STB_LOCAL predefined symbols.
(Symbol_table::do_define_in_output_segment): Likewise.
(Symbol_table::do_define_in_output_segment): Likewise.
(Symbol_table::do_define_as_constant): Likewise.
* symtab.h (Symbol_table::define_special_symbol): Add is_forced_local
parameter. Adjust all callers.
* testsuite/Makefile.am (ver_test_8.sh): New test case.
* testsuite/Makefile.in: Regenerate.
* ver_test_8.sh: New test script.

gold/ChangeLog
gold/symtab.cc
gold/symtab.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/ver_test_8.sh [new file with mode: 0755]

index ba7454506c998e97d7ed36592b2e14fc84146a47..9ea609eeef774f87eb9786809629556fe79104ea 100644 (file)
@@ -1,3 +1,18 @@
+2016-12-21  Cary Coutant  <ccoutant@gmail.com>
+
+       * symtab.cc (Symbol_table::define_special_symbol): Add is_forced_local
+       parameter; if set, do not check version script.
+       (Symbol_table::do_define_in_output_data): Pass is_forced_local for
+       STB_LOCAL predefined symbols.
+       (Symbol_table::do_define_in_output_segment): Likewise.
+       (Symbol_table::do_define_in_output_segment): Likewise.
+       (Symbol_table::do_define_as_constant): Likewise.
+       * symtab.h (Symbol_table::define_special_symbol): Add is_forced_local
+       parameter. Adjust all callers.
+       * testsuite/Makefile.am (ver_test_8.sh): New test case.
+       * testsuite/Makefile.in: Regenerate.
+       * ver_test_8.sh: New test script.
+
 2016-12-21  Cary Coutant  <ccoutant@gmail.com>
 
        * output.cc (Output_segment::first_section): Return NULL if there are
index 35989f0e636c56c11ac1c468aee131d39425dc21..d97fbdd358679a1f6539c5dee105d52d58c2b79f 100644 (file)
@@ -1759,7 +1759,7 @@ Sized_symbol<size>*
 Symbol_table::define_special_symbol(const char** pname, const char** pversion,
                                    bool only_if_ref,
                                     Sized_symbol<size>** poldsym,
-                                   bool* resolve_oldsym)
+                                   bool* resolve_oldsym, bool is_forced_local)
 {
   *resolve_oldsym = false;
   *poldsym = NULL;
@@ -1768,7 +1768,7 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
   // the version script.
   std::string v;
   bool is_default_version = false;
-  if (*pversion == NULL)
+  if (!is_forced_local && *pversion == NULL)
     {
       bool is_global;
       if (this->version_script_.get_symbol_version(*pname, &v, &is_global))
@@ -1966,13 +1966,15 @@ Symbol_table::do_define_in_output_data(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
   bool resolve_oldsym;
+  const bool is_forced_local = binding == elfcpp::STB_LOCAL;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
                                                    only_if_ref, &oldsym,
-                                                   &resolve_oldsym);
+                                                   &resolve_oldsym,
+                                                   is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -1982,7 +1984,8 @@ Symbol_table::do_define_in_output_data(
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
                                                     only_if_ref, &oldsym,
-                                                    &resolve_oldsym);
+                                                    &resolve_oldsym,
+                                                    is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -1997,8 +2000,7 @@ Symbol_table::do_define_in_output_data(
 
   if (oldsym == NULL)
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(sym);
       else if (version != NULL)
        sym->set_is_default();
@@ -2013,8 +2015,7 @@ Symbol_table::do_define_in_output_data(
   else
     {
       if (defined == PREDEFINED
-         && (binding == elfcpp::STB_LOCAL
-             || this->version_script_.symbol_is_local(name)))
+         && (is_forced_local || this->version_script_.symbol_is_local(name)))
        this->force_local(oldsym);
       delete sym;
       return oldsym;
@@ -2084,13 +2085,15 @@ Symbol_table::do_define_in_output_segment(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
   bool resolve_oldsym;
+  const bool is_forced_local = binding == elfcpp::STB_LOCAL;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
                                                    only_if_ref, &oldsym,
-                                                   &resolve_oldsym);
+                                                   &resolve_oldsym,
+                                                   is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2100,7 +2103,8 @@ Symbol_table::do_define_in_output_segment(
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
                                                     only_if_ref, &oldsym,
-                                                    &resolve_oldsym);
+                                                    &resolve_oldsym,
+                                                    is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2115,8 +2119,7 @@ Symbol_table::do_define_in_output_segment(
 
   if (oldsym == NULL)
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(sym);
       else if (version != NULL)
        sym->set_is_default();
@@ -2130,8 +2133,7 @@ Symbol_table::do_define_in_output_segment(
     return sym;
   else
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(oldsym);
       delete sym;
       return oldsym;
@@ -2200,13 +2202,15 @@ Symbol_table::do_define_as_constant(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
   bool resolve_oldsym;
+  const bool is_forced_local = binding == elfcpp::STB_LOCAL;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
                                                    only_if_ref, &oldsym,
-                                                   &resolve_oldsym);
+                                                   &resolve_oldsym,
+                                                   is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2216,7 +2220,8 @@ Symbol_table::do_define_as_constant(
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
                                                     only_if_ref, &oldsym,
-                                                    &resolve_oldsym);
+                                                    &resolve_oldsym,
+                                                    is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2235,8 +2240,7 @@ Symbol_table::do_define_as_constant(
       if ((version == NULL
           || name != version
           || value != 0)
-         && (binding == elfcpp::STB_LOCAL
-             || this->version_script_.symbol_is_local(name)))
+         && (is_forced_local || this->version_script_.symbol_is_local(name)))
        this->force_local(sym);
       else if (version != NULL
               && (name != version || value != 0))
@@ -2252,8 +2256,7 @@ Symbol_table::do_define_as_constant(
     return sym;
   else
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(oldsym);
       delete sym;
       return oldsym;
@@ -2444,7 +2447,8 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name)
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
                                                    false, &oldsym,
-                                                   &resolve_oldsym);
+                                                   &resolve_oldsym,
+                                                   false);
 #else
       gold_unreachable();
 #endif
@@ -2454,7 +2458,8 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name)
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
                                                     false, &oldsym,
-                                                    &resolve_oldsym);
+                                                    &resolve_oldsym,
+                                                    false);
 #else
       gold_unreachable();
 #endif
index b26b4e04a6e4b4ab7dff20fcfe3a58c731958d2a..d0be59f7a34e6bb412a0d99a240a6769fb90ce26 100644 (file)
@@ -1790,7 +1790,7 @@ class Symbol_table
   Sized_symbol<size>*
   define_special_symbol(const char** pname, const char** pversion,
                        bool only_if_ref, Sized_symbol<size>** poldsym,
-                       bool* resolve_oldsym);
+                       bool* resolve_oldsym, bool is_forced_local);
 
   // Define a symbol in an Output_data, sized version.
   template<int size>
index 7d9157598864256c8f706df2a55c9f705a74aae1..fbdc147446e906bec6885f470bc61ad13a9faa32 100644 (file)
@@ -1739,6 +1739,11 @@ ver_test_8_1.so: two_file_test_1_pic.o two_file_test_1b_pic.o ver_test_8_2.so gc
 ver_test_8_2.so: two_file_test_2_pic.o $(srcdir)/ver_test_8.script gcctestdir/ld
        $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_8.script two_file_test_2_pic.o
 
+check_SCRIPTS += ver_test_8.sh
+check_DATA += ver_test_8_2.so.syms
+ver_test_8_2.so.syms: ver_test_8_2.so
+       $(TEST_READELF) -s $< >$@ 2>/dev/null
+
 check_PROGRAMS += ver_test_9
 ver_test_9_SOURCES = ver_test_main.cc
 ver_test_9_DEPENDENCIES = gcctestdir/ld ver_test_9.so
index a385ad49c5b7d3d8a4ac8425898f803a1f7ad529..d1ce1fb757d68ed6255b88b15e8e03b1ac9e01c7 100644 (file)
@@ -409,8 +409,9 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.sh pr18689.sh \
 @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@ ver_test_13.sh relro_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.sh ver_test_8.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_10.sh ver_test_13.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ 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 \
@@ -461,7 +462,9 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_ttext_2 \
 @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@ ver_test_7.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_8_2.so.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_10.syms \
 @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 \
@@ -5118,6 +5121,8 @@ ver_test_5.sh.log: ver_test_5.sh
        @p='ver_test_5.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 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_8.sh.log: ver_test_8.sh
+       @p='ver_test_8.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
@@ -6578,6 +6583,8 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o ver_test_8_2.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_2.so: two_file_test_2_pic.o $(srcdir)/ver_test_8.script gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_8.script two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_8_2.so.syms: ver_test_8_2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -s $< >$@ 2>/dev/null
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9.so: ver_test_9.o ver_test_4.so ver_test_5.so gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-R,. ver_test_9.o ver_test_5.so ver_test_4.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_9.o: ver_test_9.cc
diff --git a/gold/testsuite/ver_test_8.sh b/gold/testsuite/ver_test_8.sh
new file mode 100755 (executable)
index 0000000..4f46e3c
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# ver_test_8.sh -- check that __GLOBAL_OFFSET_TABLE__ is defined only once.
+
+# Copyright (C) 2016 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.
+
+count=`grep -c '_GLOBAL_OFFSET_TABLE_' ver_test_8_2.so.syms`
+
+if test "$count" -ne 1; then
+  echo "Found $count copies of '_GLOBAL_OFFSET_TABLE_' (should be only 1)"
+  exit 1
+fi
+
+exit 0