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