about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--config.h.in4
-rwxr-xr-xconfigure28
-rw-r--r--configure.ac23
-rw-r--r--include/libc-symbols.h5
-rw-r--r--include/shlib-compat.h82
-rw-r--r--malloc/malloc.c2
-rw-r--r--nptl/libpthread-compat.c16
-rw-r--r--sysdeps/generic/libc-symver.h56
-rw-r--r--sysdeps/ia64/libc-symver.h33
-rw-r--r--time/clock_getcpuclockid.c3
-rw-r--r--time/clock_getres.c3
-rw-r--r--time/clock_gettime.c3
-rw-r--r--time/clock_nanosleep.c3
-rw-r--r--time/clock_settime.c3
14 files changed, 197 insertions, 67 deletions
diff --git a/config.h.in b/config.h.in
index f21bf04e47..ca1547ae67 100644
--- a/config.h.in
+++ b/config.h.in
@@ -190,6 +190,10 @@
 /* Define if the linker defines __ehdr_start.  */
 #undef HAVE_EHDR_START
 
+/* Define to 1 if the assembler needs intermediate aliases to define
+   multiple symbol versions for one symbol.  */
+#define SYMVER_NEEDS_ALIAS 0
+
 /*
  */
 
diff --git a/configure b/configure
index 5dc616a9de..fcf43bf7de 100755
--- a/configure
+++ b/configure
@@ -6590,6 +6590,34 @@ elif test "$libc_cv_ehdr_start" = broken; then
 $as_echo "$as_me: WARNING: linker is broken -- you should upgrade" >&2;}
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the assembler requires one version per symbol" >&5
+$as_echo_n "checking whether the assembler requires one version per symbol... " >&6; }
+if ${libc_cv_symver_needs_alias+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    cat > conftest.s <<EOF
+        .text
+testfunc:
+        .globl testfunc
+        .symver testfunc, testfunc1@VERSION1
+        .symver testfunc, testfunc1@VERSION2
+EOF
+  libc_cv_symver_needs_alias=no
+  if ${CC-cc} $ASFLAGS -c conftest.s 2>&5; then
+    libc_cv_symver_needs_alias=no
+  else
+    libc_cv_symver_needs_alias=yes
+  fi
+  rm conftest.*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_symver_needs_alias" >&5
+$as_echo "$libc_cv_symver_needs_alias" >&6; }
+if test "$libc_cv_symver_needs_alias" = yes; then
+  $as_echo "#define SYMVER_NEEDS_ALIAS 1" >>confdefs.h
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_trap with no external dependencies" >&5
 $as_echo_n "checking for __builtin_trap with no external dependencies... " >&6; }
 if ${libc_cv_builtin_trap+:} false; then :
diff --git a/configure.ac b/configure.ac
index 6a3a9ab620..fce967f2c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1673,6 +1673,29 @@ elif test "$libc_cv_ehdr_start" = broken; then
   AC_MSG_WARN([linker is broken -- you should upgrade])
 fi
 
+dnl Starting with binutils 2.35, GAS can attach multiple symbol versions
+dnl to one symbol (PR 23840).
+AC_CACHE_CHECK(whether the assembler requires one version per symbol,
+               libc_cv_symver_needs_alias, [dnl
+  cat > conftest.s <<EOF
+        .text
+testfunc:
+        .globl testfunc
+        .symver testfunc, testfunc1@VERSION1
+        .symver testfunc, testfunc1@VERSION2
+EOF
+  libc_cv_symver_needs_alias=no
+  if ${CC-cc} $ASFLAGS -c conftest.s 2>&AS_MESSAGE_LOG_FD; then
+    libc_cv_symver_needs_alias=no
+  else
+    libc_cv_symver_needs_alias=yes
+  fi
+  rm conftest.*
+])
+if test "$libc_cv_symver_needs_alias" = yes; then
+  AC_DEFINE(SYMVER_NEEDS_ALIAS)
+fi
+
 AC_CACHE_CHECK(for __builtin_trap with no external dependencies,
 	       libc_cv_builtin_trap, [dnl
 libc_cv_builtin_trap=no
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index ce5f75a1a2..546fc26a7b 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -404,12 +404,13 @@ for linking")
   symbol_version_reference(real, name, version)
 # define default_symbol_version(real, name, version) \
      _default_symbol_version(real, name, version)
+/* See <libc-symver.h>.  */
 # ifdef __ASSEMBLER__
 #  define _default_symbol_version(real, name, version) \
-     .symver real, name##@##@##version
+  _set_symbol_version (real, name@@version)
 # else
 #  define _default_symbol_version(real, name, version) \
-     __asm__ (".symver " #real "," #name "@@" #version)
+  _set_symbol_version (real, #name "@@" #version)
 # endif
 
 /* Evalutes to a string literal for VERSION in LIB.  */
diff --git a/include/shlib-compat.h b/include/shlib-compat.h
index b874e2588f..537851d753 100644
--- a/include/shlib-compat.h
+++ b/include/shlib-compat.h
@@ -62,6 +62,20 @@
    i.e. either GLIBC_2.1 or the "earliest version" specified in
    shlib-versions if that is newer.  */
 
+/* versioned_symbol (LIB, LOCAL, SYMBOL, VERSION) emits a definition
+   of SYMBOL with a default (@@) VERSION appropriate for LIB.  (The
+   actually emitted symbol version is adjusted according to the
+   baseline symbol version for LIB.)  The address of the symbol is
+   taken from LOCAL.  Properties of LOCAL are copied to the exported
+   symbol.  In particular, LOCAL itself should be global.  It is
+   unspecified whether SYMBOL@VERSION is associated with LOCAL, or if
+   an intermediate alias is created.  If LOCAL and SYMBOL are
+   distinct, and LOCAL is also intended for export, its version should
+   be specified explicitly with versioned_symbol, too.
+
+   If LOCAL is a data symbol and does not have a non-zero initializer,
+   it should be defined with __attribute__ ((nocommon)) for
+   compatibility with GCC versions that default to -fcommon.  */
 # define versioned_symbol(lib, local, symbol, version) \
   versioned_symbol_1 (lib, local, symbol, version)
 # define versioned_symbol_1(lib, local, symbol, version) \
@@ -69,44 +83,25 @@
 # define versioned_symbol_2(local, symbol, name) \
   default_symbol_version (local, symbol, name)
 
+/* compat_symbol is like versioned_symbol, but emits a compatibility
+   version (with @ instead of @@).  The same issue related to
+   intermediate aliases applies, so LOCAL should not be listed in the
+   Versions file, or otherwise it can be exported with an undesired
+   default symbol version.  */
 # define compat_symbol(lib, local, symbol, version) \
-  compat_symbol_reference (lib, local, symbol, version)
-
-/* This is similar to compat_symbol, but allows versioning the same symbol
-   to multiple version without having multiple symbol definitions.  For
-   instance:
-
-   #if (SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_2))
-   compat_symbol_unique (libc, old_foo, GLIBC_2_1_2)
-   #endif
-
-   #if (SHLIB_COMPAT (libpthread, GLIBC_2_2_6, GLIBC_2_3))
-   compat_symbol_unique (libc, old_foo, GLIBC_2_2_6)
-   #endif
-
-   Internally it creates a unique strong alias to the input symbol and
-   creates one compat_symbol on the alias.  Using the above example,
-   it is similar to:
-
-   #if (SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_2))
-   strong_alias (old_foo, old_foo__COUNTER__)
-   compat_symbol (libc, old_foo__COUNTER__, foo, GLIBC_2_2)
-   #endif.
-
-   With __COUNTER__ being a monotonic number generated by the compiler.  */
-
-# define __compat_symbol_unique_concat(x, y) x ## y
-# define _compat_symbol_unique_concat(x, y) \
-  __compat_symbol_unique_concat (x, y)
-# define _compat_symbol_unique_alias(name) \
-  _compat_symbol_unique_concat (name, __COUNTER__)
-# define _compat_symbol_unique(lib, orig_name, name, version) \
-  strong_alias (orig_name, name) \
-  compat_symbol (lib, name, orig_name, version)
-# define compat_symbol_unique(lib, name, version) \
-  _compat_symbol_unique (lib, name, _compat_symbol_unique_alias (name), \
-                         version)
-
+  compat_symbol_1 (lib, local, symbol, version)
+# define compat_symbol_1(lib, local, symbol, version) \
+  compat_symbol_2 (local, symbol, VERSION_##lib##_##version)
+/* See <libc-symver.h>.  */
+# ifdef __ASSEMBLER__
+#define compat_symbol_2(local, symbol, name) \
+  _set_symbol_version (local, symbol@name)
+# else
+#  define compat_symbol_2(local, symbol, name) \
+  compat_symbol_3 (local, symbol, name)
+#  define compat_symbol_3(local, symbol, name) \
+  _set_symbol_version (local, #symbol "@" #name)
+# endif
 #else
 
 /* Not compiling ELF shared libraries at all, so never any old versions.  */
@@ -118,16 +113,17 @@
 
 /* This should not appear outside `#if SHLIB_COMPAT (...)'.  */
 # define compat_symbol(lib, local, symbol, version) ...
-# define compat_symbol_unique(lib, name, version) ...
 
 #endif
 
 /* Use compat_symbol_reference for a reference *or* definition of a
-   specific version of a symbol.  Definitions are primarily used to
-   ensure tests reference the exact compat symbol required, or define an
-   interposing symbol of the right version e.g. __malloc_initialize_hook
-   in mcheck-init.c.  Use compat_symbol to define such a symbol within
-   the shared libraries that are built for users.  */
+   specific version of a symbol.  compat_symbol_reference does not
+   create intermediate aliases.  Definitions are primarily used to
+   ensure tests reference the exact compat symbol required, or define
+   an interposing symbol of the right version e.g.,
+   __malloc_initialize_hook in mcheck-init.c.  Use compat_symbol to
+   define such a symbol within the shared libraries that are built for
+   users.  */
 #define compat_symbol_reference(lib, local, symbol, version) \
   compat_symbol_reference_1 (lib, local, symbol, version)
 #define compat_symbol_reference_1(lib, local, symbol, version) \
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 1f4bbd8edf..530c792997 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1991,7 +1991,7 @@ static void *memalign_hook_ini (size_t alignment, size_t sz,
                                 const void *caller) __THROW;
 
 #if HAVE_MALLOC_INIT_HOOK
-void weak_variable (*__malloc_initialize_hook) (void) = NULL;
+void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
 compat_symbol (libc, __malloc_initialize_hook,
 	       __malloc_initialize_hook, GLIBC_2_0);
 #endif
diff --git a/nptl/libpthread-compat.c b/nptl/libpthread-compat.c
index 820dcd6a8f..da537af76e 100644
--- a/nptl/libpthread-compat.c
+++ b/nptl/libpthread-compat.c
@@ -20,10 +20,10 @@
 #include <shlib-compat.h>
 
 #ifdef SHARED
-static void
+void
 attribute_compat_text_section
 __attribute_used__
-__libpthread_version_placeholder (void)
+__libpthread_version_placeholder_1 (void)
 {
 }
 #endif
@@ -37,16 +37,16 @@ __libpthread_version_placeholder (void)
    there are plenty of other symbols which populate those later
    versions.  */
 #if (SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_2))
-compat_symbol_unique (libpthread,
-		      __libpthread_version_placeholder, GLIBC_2_1_2);
+compat_symbol (libpthread, __libpthread_version_placeholder_1,
+	       __libpthread_version_placeholder, GLIBC_2_1_2);
 #endif
 
 #if (SHLIB_COMPAT (libpthread, GLIBC_2_2_3, GLIBC_2_2_4))
-compat_symbol_unique (libpthread,
-		      __libpthread_version_placeholder, GLIBC_2_2_3);
+compat_symbol (libpthread, __libpthread_version_placeholder_1,
+	       __libpthread_version_placeholder, GLIBC_2_2_3);
 #endif
 
 #if (SHLIB_COMPAT (libpthread, GLIBC_2_2_6, GLIBC_2_3))
-compat_symbol_unique (libpthread,
-		      __libpthread_version_placeholder, GLIBC_2_2_6);
+compat_symbol (libpthread, __libpthread_version_placeholder_1,
+	       __libpthread_version_placeholder, GLIBC_2_2_6);
 #endif
diff --git a/sysdeps/generic/libc-symver.h b/sysdeps/generic/libc-symver.h
index 11c77ae1cd..69d147e2a8 100644
--- a/sysdeps/generic/libc-symver.h
+++ b/sysdeps/generic/libc-symver.h
@@ -22,17 +22,67 @@
 #ifndef _LIBC_SYMVER_H
 #define _LIBC_SYMVER_H 1
 
+#include <config.h>
+
 /* Use symbol_version_reference to specify the version a symbol
    reference should link to.  Use symbol_version or
    default_symbol_version for the definition of a versioned symbol.
    The difference is that the latter is a no-op in non-shared
-   builds.  */
+   builds.
+
+   _set_symbol_version is similar to symbol_version_reference, except
+   that this macro expects the name and symbol version as a single
+   string or token sequence, with an @ or @@ separator.  (A string is
+   used in C mode and a token sequence in assembler mode.)
+   _set_symbol_version only be used for definitions because it may
+   introduce an alias symbol that would not be globally unique for
+   mere references.  The _set_symbol_version macro is used to define
+   default_symbol_version and compat_symbol.  */
+
 #ifdef __ASSEMBLER__
 # define symbol_version_reference(real, name, version) \
      .symver real, name##@##version
-#else  /* !__ASSEMBLER__ */
+#else
 # define symbol_version_reference(real, name, version) \
   __asm__ (".symver " #real "," #name "@" #version)
-#endif
+#endif  /* !__ASSEMBLER__ */
+
+#if SYMVER_NEEDS_ALIAS
+/* If the assembler cannot support multiple versions for the same
+   symbol, introduce __SInnn_ aliases to which the symbol version is
+   attached.  */
+# define __symbol_version_unique_concat(x, y) __SI ## x ## _ ## y
+# define _symbol_version_unique_concat(x, y) \
+  __symbol_version_unique_concat (x, y)
+# define _symbol_version_unique_alias(name) \
+  _symbol_version_unique_concat (name, __COUNTER__)
+# ifdef __ASSEMBLER__
+#  define _set_symbol_version_2(real, alias, name_version) \
+  .globl alias ASM_LINE_SEP                                \
+  .equiv alias, real ASM_LINE_SEP                          \
+  .symver alias, name_version
+# else
+#  define _set_symbol_version_2(real, alias, name_version) \
+  __asm__ (".globl " #alias "\n\t"                         \
+           ".equiv " #alias ", " #real "\n\t"              \
+           ".symver " #alias "," name_version)
+# endif
+# define _set_symbol_version_1(real, alias, name_version) \
+  _set_symbol_version_2 (real, alias, name_version)
+/* REAL must be globally unique, so that the counter also produces
+   globally unique symbols.  */
+# define _set_symbol_version(real, name_version)                   \
+  _set_symbol_version_1 (real, _symbol_version_unique_alias (real), \
+                               name_version)
+# else  /* !SYMVER_NEEDS_ALIAS */
+# ifdef __ASSEMBLER__
+#  define _set_symbol_version(real, name_version) \
+  .symver real, name_version
+# else
+#  define _set_symbol_version(real, name_version) \
+  __asm__ (".symver " #real "," name_version)
+# endif
+#endif  /* !SYMVER_NEEDS_ALIAS */
+
 
 #endif /* _LIBC_SYMVER_H */
diff --git a/sysdeps/ia64/libc-symver.h b/sysdeps/ia64/libc-symver.h
new file mode 100644
index 0000000000..63a3e58dde
--- /dev/null
+++ b/sysdeps/ia64/libc-symver.h
@@ -0,0 +1,33 @@
+/* Symbol version management.  ia64 version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC_SYMVER_H
+
+#include <sysdeps/generic/libc-symver.h>
+
+/* ia64 recognizes loc1 as a register name.  Add the # suffix to all
+   symbol references.  */
+#if !defined (__ASSEMBLER__) && SYMVER_NEEDS_ALIAS
+#undef _set_symbol_version_2
+# define _set_symbol_version_2(real, alias, name_version) \
+  __asm__ (".globl " #alias "#\n\t"                         \
+           ".equiv " #alias ", " #real "#\n\t"              \
+           ".symver " #alias "#," name_version)
+#endif
+
+#endif /* _LIBC_SYMVER_H */
diff --git a/time/clock_getcpuclockid.c b/time/clock_getcpuclockid.c
index c148d96c5c..220e2eb016 100644
--- a/time/clock_getcpuclockid.c
+++ b/time/clock_getcpuclockid.c
@@ -42,6 +42,5 @@ versioned_symbol (libc, __clock_getcpuclockid, clock_getcpuclockid, GLIBC_2_17);
 /* clock_getcpuclockid moved to libc in version 2.17;
    old binaries may expect the symbol version it had in librt.  */
 #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
-strong_alias (__clock_getcpuclockid, __clock_getcpuclockid_2);
-compat_symbol (libc, __clock_getcpuclockid_2, clock_getcpuclockid, GLIBC_2_2);
+compat_symbol (libc, __clock_getcpuclockid, clock_getcpuclockid, GLIBC_2_2);
 #endif
diff --git a/time/clock_getres.c b/time/clock_getres.c
index 4b31893849..9099b62672 100644
--- a/time/clock_getres.c
+++ b/time/clock_getres.c
@@ -32,8 +32,7 @@ versioned_symbol (libc, __clock_getres, clock_getres, GLIBC_2_17);
 /* clock_getres moved to libc in version 2.17;
    old binaries may expect the symbol version it had in librt.  */
 #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
-strong_alias (__clock_getres, __clock_getres_2);
-compat_symbol (libc, __clock_getres_2, clock_getres, GLIBC_2_2);
+compat_symbol (libc, __clock_getres, clock_getres, GLIBC_2_2);
 #endif
 
 stub_warning (clock_getres)
diff --git a/time/clock_gettime.c b/time/clock_gettime.c
index fdeaaca3f8..e8e129d201 100644
--- a/time/clock_gettime.c
+++ b/time/clock_gettime.c
@@ -33,8 +33,7 @@ versioned_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_17);
 /* clock_gettime moved to libc in version 2.17;
    old binaries may expect the symbol version it had in librt.  */
 #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
-strong_alias (__clock_gettime, __clock_gettime_2);
-compat_symbol (libc, __clock_gettime_2, clock_gettime, GLIBC_2_2);
+compat_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_2);
 #endif
 
 stub_warning (clock_gettime)
diff --git a/time/clock_nanosleep.c b/time/clock_nanosleep.c
index 7ecb1cfcb8..57b3af2a70 100644
--- a/time/clock_nanosleep.c
+++ b/time/clock_nanosleep.c
@@ -38,8 +38,7 @@ versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17);
 /* clock_nanosleep moved to libc in version 2.17;
    old binaries may expect the symbol version it had in librt.  */
 #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
-strong_alias (__clock_nanosleep, __clock_nanosleep_2);
-compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2);
+compat_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_2);
 #endif
 
 stub_warning (clock_nanosleep)
diff --git a/time/clock_settime.c b/time/clock_settime.c
index 7676aaeb23..4df4ec56d1 100644
--- a/time/clock_settime.c
+++ b/time/clock_settime.c
@@ -33,8 +33,7 @@ versioned_symbol (libc, __clock_settime, clock_settime, GLIBC_2_17);
 /* clock_settime moved to libc in version 2.17;
    old binaries may expect the symbol version it had in librt.  */
 #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
-strong_alias (__clock_settime, __clock_settime_2);
-compat_symbol (libc, __clock_settime_2, clock_settime, GLIBC_2_2);
+compat_symbol (libc, __clock_settime, clock_settime, GLIBC_2_2);
 #endif
 
 stub_warning (clock_settime)