]> sourceware.org Git - glibc.git/commitdiff
Support for multiple versions in versioned_symbol, compat_symbol
authorFlorian Weimer <fweimer@redhat.com>
Thu, 25 Mar 2021 10:05:37 +0000 (11:05 +0100)
committerFlorian Weimer <fweimer@redhat.com>
Thu, 25 Mar 2021 11:33:02 +0000 (12:33 +0100)
This essentially folds compat_symbol_unique functionality into
compat_symbol.

This change eliminates the need for intermediate aliases for defining
multiple symbol versions, for both compat_symbol and versioned_symbol.
Some binutils versions do not suport multiple versions per symbol on
some targets, so aliases are automatically introduced, similar to what
compat_symbol_unique did.  To reduce symbol table sizes, a configure
check is added to avoid these aliases if they are not needed.

The new mechanism works with data symbols as well as function symbols,
due to the way an assembler-level redirect is used.  It is not
compatible with weak symbols for old binutils versions, which is why
the definition of __malloc_initialize_hook had to be changed.  This
is not a loss of functionality because weak symbols do not matter
to dynamic linking.

The placeholder symbol needs repeating in nptl/libpthread-compat.c
now that compat_symbol is used, but that seems more obvious than
introducing yet another macro.

A subtle difference was that compat_symbol_unique made the symbol
global automatically.  compat_symbol does not do this, so static
had to be removed from the definition of
__libpthread_version_placeholder.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
14 files changed:
config.h.in
configure
configure.ac
include/libc-symbols.h
include/shlib-compat.h
malloc/malloc.c
nptl/libpthread-compat.c
sysdeps/generic/libc-symver.h
sysdeps/ia64/libc-symver.h [new file with mode: 0644]
time/clock_getcpuclockid.c
time/clock_getres.c
time/clock_gettime.c
time/clock_nanosleep.c
time/clock_settime.c

index f21bf04e4791e5dc8d1c680361d2899dba035751..ca1547ae67f1192fc5b7414f3712b3d703c6714e 100644 (file)
 /* 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
+
 /*
 \f */
 
index 5dc616a9deff41a52c652636c4367914bcb437b8..fcf43bf7dee0a86f497a160cdd09a009fa0029cb 100755 (executable)
--- 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 :
index 6a3a9ab6202d530dcb9fc9d7adf9a25eed144f55..fce967f2c2e98e700758b823ab74851feb1e1e42 100644 (file)
@@ -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
index ce5f75a1a2bd19edb1e26003553709659cc31f06..546fc26a7b8c4ef78429bc4f940b617e15a5ab71 100644 (file)
@@ -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.  */
index b874e2588f7cb6a2c3f79449491b17c5cc56b699..537851d7531864cda102337654a84b9e25503011 100644 (file)
    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) \
 # 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.  */
 
 /* 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) \
index 1f4bbd8edf8b97701b779f183475565c7d0a6762..530c792997b55bdc44b9b2c5a663641ab47b2ddf 100644 (file)
@@ -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
index 820dcd6a8ffbe3439d98708837c68a4b73a05354..da537af76ec74c6d0ad16fecea59d96906d8c24e 100644 (file)
 #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
index 11c77ae1cd47e98a5f9eda6e178d7746a456b3a6..69d147e2a8df3f08ad305200c460a608387631ad 100644 (file)
 #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 (file)
index 0000000..63a3e58
--- /dev/null
@@ -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 */
index c148d96c5c1ab3806126abff75c9d938e6222a7b..220e2eb0167106da4b7242ff6ad0558397e7786a 100644 (file)
@@ -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
index 4b31893849dfe822d681b47db4a6efccd6f2f333..9099b6267247f515a85070dbdef82a4dd8548e89 100644 (file)
@@ -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)
index fdeaaca3f8c8981d4069a00b00dbc39241bc5289..e8e129d2015d40f3a36aeb91c8a1ac748749b458 100644 (file)
@@ -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)
index 7ecb1cfcb87e71df23bebfe13e295ce15ee7cd42..57b3af2a70d52b53b00d18c4cea49ae4e93c2081 100644 (file)
@@ -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)
index 7676aaeb23b16f2424214b001d9be593bca2eb65..4df4ec56d181fbb229e134a9e3cca3456713c6aa 100644 (file)
@@ -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)
This page took 0.068081 seconds and 5 git commands to generate.