[v2] gold: Properly remove the versioned symbol

Message ID 20240601213719.44776-1-hjl.tools@gmail.com
State New
Headers
Series [v2] gold: Properly remove the versioned symbol |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

H.J. Lu June 1, 2024, 9:37 p.m. UTC
  When the versioned symbol foo is removed from the shared library,  the
".symver foo,foo@VER" directive provides binary compatibility for foo@VER.
In this case, the unversioned symbol foo shouldn't provide the default
version for foo nor generate a multiple definition error.

	PR gold/31830
	* resolve.cc (Symbol_table::resolve): Move symbol version handling
	to ...
	* symtab.cc (Symbol_table::add_from_object): Here. If the hidden
	version from .symver is the same as the default version from the
	unversioned symbol, don't make the unversioned symbol the default
	versioned
	symbol.
	* testsuite/Makefile.am (check_SCRIPTS): Add ver_test_pr31830.sh.
	(check_DATA): ver_test_pr31830_a.syms and ver_test_pr31830_b.syms.
	(ver_test_pr31830_a.syms): New.
	(ver_test_pr31830_b.syms): Likewise.
	(ver_test_pr31830_a.so): Likewise.
	(ver_test_pr31830_b.so): Likewise.
	* testsuite/Makefile.in: Regenerated.
	* testsuite/ver_test_pr31830.script: New file.
	* testsuite/ver_test_pr31830.sh: Likewise.
	* testsuite/ver_test_pr3183_a.c: Likewise.
	* testsuite/ver_test_pr3183_b.c: Likewise.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 gold/resolve.cc                        | 14 ------
 gold/symtab.cc                         | 66 +++++++++++++++++++++-----
 gold/testsuite/Makefile.am             | 11 +++++
 gold/testsuite/Makefile.in             | 18 +++++++
 gold/testsuite/ver_test_pr31830.script |  6 +++
 gold/testsuite/ver_test_pr31830.sh     | 61 ++++++++++++++++++++++++
 gold/testsuite/ver_test_pr3183_a.c     |  2 +
 gold/testsuite/ver_test_pr3183_b.c     |  3 ++
 8 files changed, 156 insertions(+), 25 deletions(-)
 create mode 100644 gold/testsuite/ver_test_pr31830.script
 create mode 100755 gold/testsuite/ver_test_pr31830.sh
 create mode 100644 gold/testsuite/ver_test_pr3183_a.c
 create mode 100644 gold/testsuite/ver_test_pr3183_b.c
  

Patch

diff --git a/gold/resolve.cc b/gold/resolve.cc
index 777405dec1a..f05589551f4 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -250,20 +250,6 @@  Symbol_table::resolve(Sized_symbol<size>* to,
   bool to_is_ordinary;
   const unsigned int to_shndx = to->shndx(&to_is_ordinary);
 
-  // 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
-  // a linker script giving that symbol the same version.  We
-  // don't want to give a multiple-definition error for this
-  // harmless redefinition.
-  if (to->source() == Symbol::FROM_OBJECT
-      && to->object() == object
-      && to->is_defined()
-      && is_ordinary
-      && to_is_ordinary
-      && to_shndx == st_shndx
-      && to->value() == sym.get_st_value())
-    return;
-
   // Likewise for an absolute symbol defined twice with the same value.
   if (!is_ordinary
       && st_shndx == elfcpp::SHN_ABS
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 9a55e6ea511..24cb1f0272f 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -998,12 +998,54 @@  Symbol_table::add_from_object(Object* object,
       ret = this->get_sized_symbol<size>(ins.first->second);
       gold_assert(ret != NULL);
 
+      bool ret_is_ordinary;
+      const unsigned int ret_shndx = ret->shndx(&ret_is_ordinary);
+
       was_undefined_in_reg = ret->is_undefined() && ret->in_reg();
       // Commons from plugins are just placeholders.
       was_common = ret->is_common() && ret->object()->pluginobj() == NULL;
 
-      this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
-		    version, 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
+      // a linker script giving that symbol the same version.  We
+      // don't want to give a multiple-definition error for this
+      // harmless redefinition.
+      bool maybe_no_default_version = false;
+      if (ret->source() == Symbol::FROM_OBJECT
+	  && is_ordinary
+	  && ret_shndx == st_shndx)
+	{
+	  if (ret->object() == object)
+	    maybe_no_default_version = true;
+	  else if (version != NULL && version == ret->version())
+	    {
+	      // Don't give a multiple-definition error if the hidden
+	      // version from .symver is the same as the default version
+	      // from the unversioned symbol.
+	      if (is_default_version && !ret->is_default ())
+		{
+		  // Don't make the unversioned symbol the default
+		  // version.
+		  is_default_version = false;
+		  maybe_no_default_version = true;
+		}
+	      else if (!is_default_version && ret->is_default ())
+		{
+		  // Don't make the unversioned symbol the default version.
+		  ret->set_is_not_default();
+		  is_default_version = false;
+		  maybe_no_default_version = true;
+		}
+	    }
+	}
+
+      if (!(maybe_no_default_version
+	    && ret->is_defined()
+	    && ret_is_ordinary
+	    && ret->value() == sym.get_st_value()))
+	this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx,
+		      object, version, is_default_version);
+
       if (parameters->options().gc_sections())
         this->gc_mark_dyn_syms(ret);
 
@@ -1012,13 +1054,7 @@  Symbol_table::add_from_object(Object* object,
 						       insdefault.first);
       else
 	{
-	  bool dummy;
-	  if (version != NULL
-	      && ret->source() == Symbol::FROM_OBJECT
-	      && ret->object() == object
-	      && is_ordinary
-	      && ret->shndx(&dummy) == st_shndx
-	      && ret->is_default())
+	  if (version != NULL && maybe_no_default_version)
 	    {
 	      // We have seen NAME/VERSION already, and marked it as the
 	      // default version, but now we see a definition for
@@ -1032,9 +1068,17 @@  Symbol_table::add_from_object(Object* object,
 	      // In any other case, the two symbols should have generated
 	      // a multiple definition error.
 	      // (See PR gold/18703.)
-	      ret->set_is_not_default();
+	      // If the hidden version from .symver is the same as the
+	      // default version from the unversioned symbol, don't make
+	      // the unversioned symbol the default versioned symbol.
 	      const Stringpool::Key vnull_key = 0;
-	      this->table_.erase(std::make_pair(name_key, vnull_key));
+	      if (!ret->is_default())
+		this->table_.erase(std::make_pair(name_key, vnull_key));
+	      else if (ret->object() == object)
+		{
+		  ret->set_is_not_default();
+		  this->table_.erase(std::make_pair(name_key, vnull_key));
+		}
 	    }
 	}
     }
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 6e9af67b22d..5797874e98d 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -2040,6 +2040,17 @@  ver_test_pr23409_1.so: gcctestdir/ld ver_test_1.o $(srcdir)/ver_test_pr23409_1.s
 ver_test_pr23409_2.so: gcctestdir/ld ver_test_1.o $(srcdir)/ver_test_pr23409_2.script
 	gcctestdir/ld -shared -o $@ ver_test_1.o --version-script $(srcdir)/ver_test_pr23409_2.script
 
+check_SCRIPTS += ver_test_pr31830.sh
+check_DATA += ver_test_pr31830_a.syms ver_test_pr31830_b.syms
+ver_test_pr31830_a.syms: ver_test_pr31830_a.so
+	$(TEST_READELF) --dyn-syms -W $< >$@
+ver_test_pr31830_b.syms: ver_test_pr31830_b.so
+	$(TEST_READELF) --dyn-syms -W $< >$@
+ver_test_pr31830_a.so: gcctestdir/ld ver_test_pr3183_a.o ver_test_pr3183_b.o $(srcdir)/ver_test_pr31830.script
+	gcctestdir/ld -shared -o $@ ver_test_pr3183_a.o ver_test_pr3183_b.o --version-script $(srcdir)/ver_test_pr31830.script
+ver_test_pr31830_b.so: gcctestdir/ld ver_test_pr3183_a.o ver_test_pr3183_b.o $(srcdir)/ver_test_pr31830.script
+	gcctestdir/ld -shared -o $@ ver_test_pr3183_b.o ver_test_pr3183_a.o --version-script $(srcdir)/ver_test_pr31830.script
+
 check_SCRIPTS += weak_as_needed.sh
 check_DATA += weak_as_needed.stdout
 weak_as_needed.stdout: weak_as_needed_a.so
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index db299dd97f6..4e0bc83e7eb 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -487,6 +487,7 @@  check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_10.sh ver_test_13.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_14.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_pr23409.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_pr31830.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	weak_as_needed.sh relro_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_matching_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_3.sh \
@@ -544,6 +545,8 @@  check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_13.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_14.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_pr23409.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_pr31830_a.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_pr31830_b.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	weak_as_needed.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	protected_3.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	relro_test.stdout \
@@ -5978,6 +5981,13 @@  ver_test_pr23409.sh.log: ver_test_pr23409.sh
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+ver_test_pr31830.sh.log: ver_test_pr31830.sh
+	@p='ver_test_pr31830.sh'; \
+	b='ver_test_pr31830.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 weak_as_needed.sh.log: weak_as_needed.sh
 	@p='weak_as_needed.sh'; \
 	b='weak_as_needed.sh'; \
@@ -9031,6 +9041,14 @@  uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	gcctestdir/ld -shared -o $@ ver_test_1.o ver_test_pr23409_2.so --version-script $(srcdir)/ver_test_pr23409_1.script
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_pr23409_2.so: gcctestdir/ld ver_test_1.o $(srcdir)/ver_test_pr23409_2.script
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	gcctestdir/ld -shared -o $@ ver_test_1.o --version-script $(srcdir)/ver_test_pr23409_2.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_pr31830_a.syms: ver_test_pr31830_a.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_READELF) --dyn-syms -W $< >$@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_pr31830_b.syms: ver_test_pr31830_b.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_READELF) --dyn-syms -W $< >$@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_pr31830_a.so: gcctestdir/ld ver_test_pr3183_a.o ver_test_pr3183_b.o $(srcdir)/ver_test_pr31830.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	gcctestdir/ld -shared -o $@ ver_test_pr3183_a.o ver_test_pr3183_b.o --version-script $(srcdir)/ver_test_pr31830.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ver_test_pr31830_b.so: gcctestdir/ld ver_test_pr3183_a.o ver_test_pr3183_b.o $(srcdir)/ver_test_pr31830.script
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	gcctestdir/ld -shared -o $@ ver_test_pr3183_b.o ver_test_pr3183_a.o --version-script $(srcdir)/ver_test_pr31830.script
 @GCC_TRUE@@NATIVE_LINKER_TRUE@weak_as_needed.stdout: weak_as_needed_a.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_READELF) -dW --dyn-syms $< >$@
 @GCC_TRUE@@NATIVE_LINKER_TRUE@weak_as_needed_a.so: gcctestdir/ld weak_as_needed_a.o weak_as_needed_b.so weak_as_needed_c.so
diff --git a/gold/testsuite/ver_test_pr31830.script b/gold/testsuite/ver_test_pr31830.script
new file mode 100644
index 00000000000..0dcc47f4f5c
--- /dev/null
+++ b/gold/testsuite/ver_test_pr31830.script
@@ -0,0 +1,6 @@ 
+GLIBC_2.2.5 {
+  global:
+    foo;
+  local:
+    *;
+};
diff --git a/gold/testsuite/ver_test_pr31830.sh b/gold/testsuite/ver_test_pr31830.sh
new file mode 100755
index 00000000000..2a3c0347461
--- /dev/null
+++ b/gold/testsuite/ver_test_pr31830.sh
@@ -0,0 +1,61 @@ 
+#!/bin/sh
+
+# ver_test_pr31830.sh -- a test case for version scripts
+
+# Copyright (C) 2024 Free Software Foundation, Inc.
+
+# 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 linker-generated symbols (e.g., _end)
+# get correct version information even in the presence of
+# a shared library that provides those symbols with different
+# versions.
+
+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_pr31830_a.syms "foo@GLIBC_2.2.5$"
+check ver_test_pr31830_b.syms "foo@GLIBC_2.2.5$"
+
+check_missing ver_test_pr31830_a.syms "foo@@GLIBC_2.2.5$"
+check_missing ver_test_pr31830_b.syms "foo@@GLIBC_2.2.5$"
+
+exit 0
diff --git a/gold/testsuite/ver_test_pr3183_a.c b/gold/testsuite/ver_test_pr3183_a.c
new file mode 100644
index 00000000000..bb57059bf7e
--- /dev/null
+++ b/gold/testsuite/ver_test_pr3183_a.c
@@ -0,0 +1,2 @@ 
+extern void foo(void);
+void foo(void) {}
diff --git a/gold/testsuite/ver_test_pr3183_b.c b/gold/testsuite/ver_test_pr3183_b.c
new file mode 100644
index 00000000000..aba07cc6305
--- /dev/null
+++ b/gold/testsuite/ver_test_pr3183_b.c
@@ -0,0 +1,3 @@ 
+extern void __collector_foo_2_2(void);
+__attribute__((__symver__("foo@GLIBC_2.2.5")))
+void __collector_foo_2_2(void) {}