Add _finite symbol aliases for better glibc compatibility

The glibc math.h header can redirect math symbols (e.g. with the
-ffinite-math-only cflag) to _finite symbols which have the same
semantics as the original ones except they may omit some error checks.

With these aliases libmathlib can be a drop in replacement for glibc
libm at link time.  It's not a full replacement, but it can interpose
glibc libm calls using LD_PRELOAD in case of an already dynamic linked
binary or using -lmathlib before -lm at link time.  This hopefully will
make it easy to try libmathlib with a glibc based toolchain.

Unfortunately with static linking the glibc _finite symbol definitions
may conflict with the libmathlib definitions if other glibc internal
symbols are used from the same object file where the _finite symbol is
defined.  To work this around add glibc internal symbols as hidden
aliases so the conflicting glibc object files don't get linked.
This is a bit fragile since glibc can change its internal symbols and
how they are used, but it only affects static linking, which always
has this problem when symbols are interposed.
diff --git a/math/exp.c b/math/exp.c
index 664b2a9..d747308 100644
--- a/math/exp.c
+++ b/math/exp.c
@@ -164,3 +164,8 @@
 {
   return exp_inline (x, xtail, 1);
 }
+#if USE_GLIBC_ABI
+strong_alias (exp, __exp_finite)
+hidden_alias (exp, __ieee754_exp)
+hidden_alias (__exp_dd, __exp1)
+#endif
diff --git a/math/exp2.c b/math/exp2.c
index 0241ed2..39133c1 100644
--- a/math/exp2.c
+++ b/math/exp2.c
@@ -134,3 +134,7 @@
   scale = asdouble (sbits);
   return scale + scale * tmp;
 }
+#if USE_GLIBC_ABI
+strong_alias (exp2, __exp2_finite)
+hidden_alias (exp2, __ieee754_exp2)
+#endif
diff --git a/math/exp2f.c b/math/exp2f.c
index d05288d..b9570ba 100644
--- a/math/exp2f.c
+++ b/math/exp2f.c
@@ -86,3 +86,7 @@
   y = y * s;
   return (float) y;
 }
+#if USE_GLIBC_ABI
+strong_alias (exp2f, __exp2f_finite)
+hidden_alias (exp2f, __ieee754_exp2f)
+#endif
diff --git a/math/expf.c b/math/expf.c
index dcea503..61ed55a 100644
--- a/math/expf.c
+++ b/math/expf.c
@@ -101,4 +101,8 @@
   y = y * s;
   return (float) y;
 }
+#if USE_GLIBC_ABI
+strong_alias (expf, __expf_finite)
+hidden_alias (expf, __ieee754_expf)
+#endif
 #endif
diff --git a/math/log.c b/math/log.c
index b803b30..e021f3f 100644
--- a/math/log.c
+++ b/math/log.c
@@ -160,3 +160,7 @@
 #endif
   return y;
 }
+#if USE_GLIBC_ABI
+strong_alias (log, __log_finite)
+hidden_alias (log, __ieee754_log)
+#endif
diff --git a/math/log2.c b/math/log2.c
index bc4b8f8..ebe207a 100644
--- a/math/log2.c
+++ b/math/log2.c
@@ -142,3 +142,7 @@
 #endif
   return y;
 }
+#if USE_GLIBC_ABI
+strong_alias (log2, __log2_finite)
+hidden_alias (log2, __ieee754_log2)
+#endif
diff --git a/math/log2f.c b/math/log2f.c
index 6598000..f615b5f 100644
--- a/math/log2f.c
+++ b/math/log2f.c
@@ -86,3 +86,7 @@
   y = y * r2 + p;
   return (float) y;
 }
+#if USE_GLIBC_ABI
+strong_alias (log2f, __log2f_finite)
+hidden_alias (log2f, __ieee754_log2f)
+#endif
diff --git a/math/logf.c b/math/logf.c
index d591410..e9e642f 100644
--- a/math/logf.c
+++ b/math/logf.c
@@ -89,4 +89,8 @@
   y = y * r2 + (y0 + r);
   return (float) y;
 }
+#if USE_GLIBC_ABI
+strong_alias (logf, __logf_finite)
+hidden_alias (logf, __ieee754_logf)
+#endif
 #endif
diff --git a/math/math_config.h b/math/math_config.h
index c878c24..5e27958 100644
--- a/math/math_config.h
+++ b/math/math_config.h
@@ -188,11 +188,26 @@
   return x;
 }
 
+/* Provide *_finite symbols and some of the glibc hidden symbols
+   so libmathlib can be used with binaries compiled against glibc
+   to interpose math functions with both static and dynamic linking.  */
+#ifndef USE_GLIBC_ABI
+# if __GNUC__
+#   define USE_GLIBC_ABI 1
+# else
+#   define USE_GLIBC_ABI 0
+# endif
+#endif
+
 #ifdef __GNUC__
 # define HIDDEN __attribute__ ((__visibility__ ("hidden")))
 # define NOINLINE __attribute__ ((noinline))
 # define likely(x) __builtin_expect (!!(x), 1)
 # define unlikely(x) __builtin_expect (x, 0)
+# define strong_alias(f, a) \
+  extern __typeof (f) a __attribute__ ((alias (#f)));
+# define hidden_alias(f, a) \
+  extern __typeof (f) a __attribute__ ((alias (#f), visibility ("hidden")));
 #else
 # define HIDDEN
 # define NOINLINE
diff --git a/math/pow.c b/math/pow.c
index 3d92784..1164ce1 100644
--- a/math/pow.c
+++ b/math/pow.c
@@ -369,3 +369,7 @@
 #endif
   return exp_inline (ehi, elo, sign_bias);
 }
+#if USE_GLIBC_ABI
+strong_alias (pow, __pow_finite)
+hidden_alias (pow, __ieee754_pow)
+#endif
diff --git a/math/powf.c b/math/powf.c
index 9af554a..4fdb8ef 100644
--- a/math/powf.c
+++ b/math/powf.c
@@ -226,4 +226,8 @@
     }
   return (float) exp2_inline (ylogx, sign_bias);
 }
+#if USE_GLIBC_ABI
+strong_alias (powf, __powf_finite)
+hidden_alias (powf, __ieee754_powf)
+#endif
 #endif