Make soft-fp symbols into compat symbols for powerpc*-*-linux*.
authorJoseph Myers <joseph@codesourcery.com>
Thu, 30 Oct 2014 17:28:30 +0000 (17:28 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Thu, 30 Oct 2014 17:28:30 +0000 (17:28 +0000)
Continuing preparations for implementing
TARGET_ATOMIC_ASSIGN_EXPAND_FENV for powerpc*-*-linux* soft-float and
e500, this patch makes soft-fp symbols used for those targets into
compat symbols when building with glibc >= 2.19, so that they are only
in shared libgcc for existing binaries requiring them, not in static
libgcc and not available for new links using shared libgcc.  Instead,
new links will get the symbols from libc, which has exported all of
them since 2.19.  (Actually all the symbols were exported from glibc
since 2.4, but some of them were exported by glibc as compat symbols
only - because of a confusion between deliberately present soft-fp
symbols and old accidental reexports of libgcc functions from glibc
2.0 - until 2.19.)

This allows user floating-point arithmetic to interoperate properly
with the state handled by <fenv.h> functions, whether software state
(for soft-float; TLS variables that don't form a public part of
glibc's ABI, so can only be accessed directly by functions within
glibc) or hardware state (for e500 - the copies of the soft-fp
functions in glibc being built to interoperate with the hardware state
whereas those in libgcc aren't).  Previously only glibc's own
functions, and those operations done in hardware on e500, properly
worked with that state, not direct floating-point arithmetic
operations that were implemented in software.

The intended next step is the actual TARGET_ATOMIC_ASSIGN_EXPAND_FENV
implementation.

The test of glibc >= 2.19 uses the same --with-glibc-version configure
option as in the gcc/ directory (but differently implemented; in gcc/
the fallback is to examine headers to find the version, while in
libgcc/ we can use compile for the target and so use AC_COMPUTE_INT).
The TARGET_ATOMIC_ASSIGN_EXPAND_FENV implementation will also only do
anything for glibc >= 2.19, as it will depend on generating calls to
functions __atomic_feholdexcept __atomic_feclearexcept
__atomic_feupdateenv that were added in 2.19 for that purpose (even
for e500, inline code is not readily possible because of the need to
make prctl syscalls from the implementation of these functions).

In order to make symbols compat symbols, the soft-fp files need
wrapping with generated wrappers including asm .symver directives,
which need to name the symbol version in question.  This is extracted
by an awk script from an intermediate stage of generating the .map
file for linking libgcc (that .map itself depends on the objects that
go into the library, so can't be used for this purpose as that would
mean a circular dependency); the extraction is not fully general
regarding the features available in .map generation, but suffices for
the present purpose.

It would make sense for hardfp.c symbols to be compat symbols as well
(in the cases where hardfp.c gets used, the functions in question
should not be used for new links), but this isn't required for the
present purpose, which is only concerned with ensuring that where
functions that should be affected by rounding modes or exceptions get
used, those functions are actually affected by those rounding modes or
exceptions.

Tested with no regressions with cross to powerpc-linux-gnu
(soft-float); c11-atomic-exec-5.c moves from UNSUPPORTED to FAIL, as
expected, now that floating-point arithmetic in user programs uses the
same state as <fenv.h> functions, so the fenv_exceptions test passes,
but TARGET_ATOMIC_ASSIGN_EXPAND_FENV isn't yet implemented.  (For
e500, c11-atomic-exec-5.c was already FAILing, as enough operations
worked with the hardware state for the fenv_exceptions effective
target test to pass.)  Also verified that the exported symbols and
versions are unchanged, with the expected symbols becoming compat
symbols at the same versions, and that with --with-glibc-version=2.18
the symbols remain normal rather than compat symbols.

* Makefile.in (libgcc.map.in): New target.
(libgcc.map): Use libgcc.map.in.
* config/t-softfp (softfp_compat): New variable to be set by
users.
[$(softfp_compat) = y] (softfp_map_dep, softfp_set_symver): New
variables.
[$(softfp_compat) = y] (softfp_file_list): Use files in the build
directory.
[$(softfp_compat) = y] ($(softfp_file_list)): Generate wrappers
that use compat symbols and disable all code unless [SHARED].
* config/t-softfp-compat: New file.
* find-symver.awk: New file.
* configure.ac (--with-glibc-version): New configure option.
(ppc_fp_compat): New variable set for powerpc*-*-linux*.
* configure: Regenerate.
* config.host (powerpc*-*-linux*): Use ${ppc_fp_compat} for
soft-float and e500.

From-SVN: r216942

libgcc/ChangeLog
libgcc/Makefile.in
libgcc/config.host
libgcc/config/t-softfp
libgcc/config/t-softfp-compat [new file with mode: 0644]
libgcc/configure
libgcc/configure.ac
libgcc/find-symver.awk [new file with mode: 0644]

index eb834601ace3f531176407f0081aa976999e787a..073ed11d3216c87eb568d230a3719482b7b53302 100644 (file)
@@ -1,3 +1,23 @@
+2014-10-30  Joseph Myers  <joseph@codesourcery.com>
+
+       * Makefile.in (libgcc.map.in): New target.
+       (libgcc.map): Use libgcc.map.in.
+       * config/t-softfp (softfp_compat): New variable to be set by
+       users.
+       [$(softfp_compat) = y] (softfp_map_dep, softfp_set_symver): New
+       variables.
+       [$(softfp_compat) = y] (softfp_file_list): Use files in the build
+       directory.
+       [$(softfp_compat) = y] ($(softfp_file_list)): Generate wrappers
+       that use compat symbols and disable all code unless [SHARED].
+       * config/t-softfp-compat: New file.
+       * find-symver.awk: New file.
+       * configure.ac (--with-glibc-version): New configure option.
+       (ppc_fp_compat): New variable set for powerpc*-*-linux*.
+       * configure: Regenerate.
+       * config.host (powerpc*-*-linux*): Use ${ppc_fp_compat} for
+       soft-float and e500.
+
 2014-10-29  Joseph Myers  <joseph@codesourcery.com>
 
        * config/t-hardfp (hardfp_exclusions): Document new variable for
index 4008a859349ffdd35239acc851a0363a694aee3a..357e15c37614ce7a5dad44aaaeba9fc652314320 100644 (file)
@@ -922,12 +922,16 @@ ifeq ($(enable_shared),yes)
 
 # Map-file generation.
 ifneq ($(SHLIB_MKMAP),)
-libgcc.map: $(SHLIB_MKMAP) $(SHLIB_MAPFILES) $(libgcc-s-objects)
-       { $(NM) $(SHLIB_NM_FLAGS) $(libgcc-s-objects); echo %%; \
-         cat $(SHLIB_MAPFILES) \
+libgcc.map.in: $(SHLIB_MAPFILES)
+       { cat $(SHLIB_MAPFILES) \
            | sed -e '/^[       ]*#/d' \
                  -e 's/^%\(if\|else\|elif\|endif\|define\)/#\1/' \
            | $(gcc_compile_bare) -E -xassembler-with-cpp -; \
+       } > tmp-$@
+       mv tmp-$@ $@
+libgcc.map: $(SHLIB_MKMAP) libgcc.map.in $(libgcc-s-objects)
+       { $(NM) $(SHLIB_NM_FLAGS) $(libgcc-s-objects); echo %%; \
+         cat libgcc.map.in; \
        } | $(AWK) -f $(SHLIB_MKMAP) $(SHLIB_MKMAP_OPTS) > tmp-$@
        mv tmp-$@ $@
 libgcc_s$(SHLIB_EXT): libgcc.map
index 6d0fccdab2d84a66a9e73560d0a43a62bf514489..f3cc276558302a9ea9d15ca61f702cfd9b87b388 100644 (file)
@@ -998,13 +998,13 @@ powerpc*-*-linux*)
                tmake_file="${tmake_file} t-hardfp-sfdf t-hardfp"
                ;;
        soft)
-               tmake_file="${tmake_file} t-softfp-sfdf t-softfp"
+               tmake_file="${tmake_file} t-softfp-sfdf ${ppc_fp_compat} t-softfp"
                ;;
        e500v1)
-               tmake_file="${tmake_file} rs6000/t-e500v1-fp t-softfp t-hardfp"
+               tmake_file="${tmake_file} rs6000/t-e500v1-fp ${ppc_fp_compat} t-softfp t-hardfp"
                ;;
        e500v2)
-               tmake_file="${tmake_file} t-hardfp-sfdf rs6000/t-e500v2-fp t-softfp t-hardfp"
+               tmake_file="${tmake_file} t-hardfp-sfdf rs6000/t-e500v2-fp ${ppc_fp_compat} t-softfp t-hardfp"
                ;;
        *)
                echo "Unknown ppc_fp_type $ppc_fp_type" 1>&2
index 43e0b4d578db96df3acb78c83e788fd7602ff40e..e9fece7583d22f54b83aee3b5adc8d9a374126c2 100644 (file)
 # the above settings, also define softfp_extras as a list of those
 # functions, e.g. unorddf2.
 #
+# If the functions should only be built as compat symbols for shared
+# libgcc, not available for new links, also define:
+#
+# softfp_compat := y
+#
 # If the libgcc2.c functions should not be replaced, also define:
 #
 # softfp_exclude_libgcc2 := y
@@ -52,7 +57,8 @@
 # softfp_wrap_end: text to put at the end of wrapper source files,
 #                  e.g. '#endif'
 #
-# This is another temporary measure.
+# This is another temporary measure, and cannot be used together with
+# softfp_compat.
 
 softfp_float_funcs = add$(m)3 div$(m)3 eq$(m)2 ge$(m)2 le$(m)2 mul$(m)3 \
   neg$(m)2 sub$(m)3 unord$(m)2
@@ -77,16 +83,36 @@ softfp_func_list := $(filter-out floatdidf floatdisf fixunsdfsi fixunssfsi \
   floatundidf floatundisf floatundixf floatunditf,$(softfp_func_list))
 endif
 
-ifeq ($(softfp_wrap_start),)
-softfp_file_list := \
-  $(addsuffix .c,$(addprefix $(srcdir)/soft-fp/,$(softfp_func_list)))
+ifeq ($(softfp_compat),y)
+softfp_file_list := $(addsuffix .c,$(softfp_func_list))
+
+ifeq ($(enable_shared),yes)
+softfp_map_dep := libgcc.map.in
 else
+softfp_map_dep :=
+endif
+softfp_set_symver = echo "asm (\".symver $(1),$(1)@`$(AWK) -f $(srcdir)/find-symver.awk -v symbol=$(1) libgcc.map.in`\");" >> $@
+$(softfp_file_list): $(softfp_map_dep)
+       echo '#ifdef SHARED' > $@
+       echo '#include "soft-fp/$@"' >> $@
+ifeq ($(enable_shared),yes)
+       $(call softfp_set_symver,__$(*F))
+       if grep strong_alias $(srcdir)/soft-fp/$@ > /dev/null; then \
+         alias=`grep strong_alias $(srcdir)/soft-fp/$@ | sed -e 's/.*, *//' -e 's/).*//'`; \
+         $(call softfp_set_symver,$$alias); \
+       fi
+endif
+       echo '#endif' >> $@
+else ifneq ($(softfp_wrap_start),)
 softfp_file_list := $(addsuffix .c,$(softfp_func_list))
 
 $(softfp_file_list):
        echo $(softfp_wrap_start) > $@
        echo '#include "soft-fp/$@"' >> $@
        echo $(softfp_wrap_end) >> $@
+else
+softfp_file_list := \
+  $(addsuffix .c,$(addprefix $(srcdir)/soft-fp/,$(softfp_func_list)))
 endif
 
 # Disable missing prototype and type limit warnings.  The prototypes
diff --git a/libgcc/config/t-softfp-compat b/libgcc/config/t-softfp-compat
new file mode 100644 (file)
index 0000000..2afc948
--- /dev/null
@@ -0,0 +1 @@
+softfp_compat := y
index 7a154db9de9bc59f7966b4e7ffad16973df2ade6..3f53aafacaa574dfe0eb43a19b9ed58101c7edea 100644 (file)
@@ -666,6 +666,7 @@ enable_decimal_float
 with_system_libunwind
 enable_sjlj_exceptions
 enable_explicit_exception_frame_registration
+with_glibc_version
 enable_tls
 '
       ac_precious_vars='build_alias
@@ -1318,6 +1319,8 @@ Optional Packages:
   --with-slibdir=DIR      shared libraries in DIR LIBDIR
   --with-build-libsubdir=DIR  Directory where to find libraries for build system
   --with-system-libunwind use installed libunwind
+  --with-glibc-version=M.N
+                          assume GCC used with glibc version M.N or later
 
 Some influential environment variables:
   CC          C compiler command
@@ -4376,6 +4379,38 @@ fi
 $as_echo "$libgcc_cv_mips_hard_float" >&6; }
 esac
 
+# Determine the version of glibc, if any, used on the target.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for target glibc version" >&5
+$as_echo_n "checking for target glibc version... " >&6; }
+
+# Check whether --with-glibc-version was given.
+if test "${with_glibc_version+set}" = set; then :
+  withval=$with_glibc_version;
+if echo "$with_glibc_version" | grep '^[0-9][0-9]*\.[0-9][0-9]*$'; then
+  glibc_version_major=`echo "$with_glibc_version" | sed -e 's/\..*//'`
+  glibc_version_minor=`echo "$with_glibc_version" | sed -e 's/.*\.//'`
+else
+  as_fn_error "option --with-glibc-version requires a version number M.N" "$LINENO" 5
+fi
+else
+
+if ac_fn_c_compute_int "$LINENO" "__GLIBC__" "glibc_version_major"        "#include <features.h>"; then :
+
+else
+  glibc_version_major=0
+fi
+
+if ac_fn_c_compute_int "$LINENO" "__GLIBC_MINOR__" "glibc_version_minor"        "#include <features.h>"; then :
+
+else
+  glibc_version_minor=0
+fi
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibc_version_major.$glibc_version_minor" >&5
+$as_echo "$glibc_version_major.$glibc_version_minor" >&6; }
+
 # Determine floating-point type for powerpc*-*-linux*.
 # Single-precision-only FPRs are not a supported configuration for
 # this target, so are not allowed for in this test.
@@ -4396,6 +4431,20 @@ ppc_fp_type=hard
 EOF
 eval `${CC-cc} -E conftest.c | grep ppc_fp_type=`
 rm -f conftest.c
+# glibc 2.19 and later provide all the soft-fp functions, with proper
+# interactions with <fenv.h> exception and rounding mode handling, so
+# make libgcc's versions into compat symbols if a recent enough glibc
+# version is being used.
+ppc_fp_compat=
+case ${ppc_fp_type} in
+soft|e500v1|e500v2)
+  if test $glibc_version_major -gt 2 \
+    || ( test $glibc_version_major -eq 2 \
+        && test $glibc_version_minor -ge 19 ); then
+    ppc_fp_compat="t-softfp-compat"
+  fi
+  ;;
+esac
 ;;
 esac
 
index 710f15a827967528c4910d9dfa5a1f8e1faa2fc8..79d0ea43493edc612bfb3eaebab2da52e2623cf4 100644 (file)
@@ -320,6 +320,25 @@ mips*-*-*)
     [libgcc_cv_mips_hard_float=no])])
 esac
 
+# Determine the version of glibc, if any, used on the target.
+AC_MSG_CHECKING([for target glibc version])
+AC_ARG_WITH([glibc-version],
+  [AS_HELP_STRING([--with-glibc-version=M.N],
+    [assume GCC used with glibc version M.N or later])], [
+if [echo "$with_glibc_version" | grep '^[0-9][0-9]*\.[0-9][0-9]*$']; then
+  glibc_version_major=`echo "$with_glibc_version" | sed -e 's/\..*//'`
+  glibc_version_minor=`echo "$with_glibc_version" | sed -e 's/.*\.//'`
+else
+  AC_MSG_ERROR([option --with-glibc-version requires a version number M.N])
+fi], [
+AC_COMPUTE_INT([glibc_version_major], [__GLIBC__],
+                                     [#include <features.h>],
+                                     [glibc_version_major=0])
+AC_COMPUTE_INT([glibc_version_minor], [__GLIBC_MINOR__],
+                                     [#include <features.h>],
+                                     [glibc_version_minor=0])])
+AC_MSG_RESULT([$glibc_version_major.$glibc_version_minor])
+
 # Determine floating-point type for powerpc*-*-linux*.
 # Single-precision-only FPRs are not a supported configuration for
 # this target, so are not allowed for in this test.
@@ -340,6 +359,20 @@ ppc_fp_type=hard
 EOF
 eval `${CC-cc} -E conftest.c | grep ppc_fp_type=`
 rm -f conftest.c
+# glibc 2.19 and later provide all the soft-fp functions, with proper
+# interactions with <fenv.h> exception and rounding mode handling, so
+# make libgcc's versions into compat symbols if a recent enough glibc
+# version is being used.
+ppc_fp_compat=
+case ${ppc_fp_type} in
+soft|e500v1|e500v2)
+  if test $glibc_version_major -gt 2 \
+    || ( test $glibc_version_major -eq 2 \
+        && test $glibc_version_minor -ge 19 ); then
+    ppc_fp_compat="t-softfp-compat"
+  fi
+  ;;
+esac
 ;;
 esac
 
diff --git a/libgcc/find-symver.awk b/libgcc/find-symver.awk
new file mode 100644 (file)
index 0000000..adf5ba7
--- /dev/null
@@ -0,0 +1,28 @@
+# Extract the version of a single symbol from the version map.
+# Copyright (C) 2014 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC 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, or (at your option) any later
+# version.
+#
+# GCC 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+/^[A-Z]/ {
+  version = $1;
+  next;
+}
+
+$1 == symbol {
+  print version
+  exit
+}