public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [gold commit] Fix problem where version script causes predefined hidden symbol to be defined twice
@ 2016-12-22  1:25 Cary Coutant
  0 siblings, 0 replies; only message in thread
From: Cary Coutant @ 2016-12-22  1:25 UTC (permalink / raw)
  To: Binutils

[-- Attachment #1: Type: text/plain, Size: 1031 bytes --]

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.

-cary


2016-12-21  Cary Coutant  <ccoutant@gmail.com>

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.

[-- Attachment #2: local-version.patch --]
[-- Type: application/octet-stream, Size: 10004 bytes --]

Fix problem where version script causes predefined hidden symbol to be defined twice.

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.


2016-12-21  Cary Coutant  <ccoutant@gmail.com>

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.

diff --git a/gold/symtab.cc b/gold/symtab.cc
index 35989f0..d97fbdd 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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
diff --git a/gold/symtab.h b/gold/symtab.h
index b26b4e0..d0be59f 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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>
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 7d91575..fbdc147 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -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
diff --git a/gold/testsuite/ver_test_8.sh b/gold/testsuite/ver_test_8.sh
new file mode 100755
index 0000000..4f46e3c
--- /dev/null
+++ b/gold/testsuite/ver_test_8.sh
@@ -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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-12-22  1:25 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-22  1:25 [gold commit] Fix problem where version script causes predefined hidden symbol to be defined twice Cary Coutant

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).