about summary refs log tree commit diff
path: root/include
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2021-03-25 11:05:37 +0100
committerFlorian Weimer <fweimer@redhat.com>2021-03-25 12:33:02 +0100
commit0923f74adaa2827264a0d7cbe51ba287fc0f0c16 (patch)
tree06778dcf88a5b0ac149f3c23d5cb85de4a2f78b7 /include
parent6d8fcee694b9581630a7f27fcbf0009fc44d7baa (diff)
downloadglibc-0923f74adaa2827264a0d7cbe51ba287fc0f0c16.tar.gz
glibc-0923f74adaa2827264a0d7cbe51ba287fc0f0c16.tar.xz
glibc-0923f74adaa2827264a0d7cbe51ba287fc0f0c16.zip
Support for multiple versions in versioned_symbol, compat_symbol
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>
Diffstat (limited to 'include')
-rw-r--r--include/libc-symbols.h5
-rw-r--r--include/shlib-compat.h82
2 files changed, 42 insertions, 45 deletions
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) \