diff options
author | Jia Tan <jiat0218@gmail.com> | 2023-11-21 20:56:55 +0800 |
---|---|---|
committer | Jia Tan <jiat0218@gmail.com> | 2023-11-30 20:04:42 +0800 |
commit | ffb456593d695d70052a2f71c7a2e6269217d194 (patch) | |
tree | a00443d5cc4f60e32adc601e13095afcde45c50a | |
parent | xz: Tweak a comment. (diff) | |
download | xz-ffb456593d695d70052a2f71c7a2e6269217d194.tar.xz |
Build: Change --enable-ifunc handling.
Some compilers support __attribute__((__ifunc__())) even though the
dynamic linker does not. The compiler is able to create the binary
but it will fail on startup. So it is not enough to just test if
the attribute is supported.
The default value for enable_ifunc is now auto, which will attempt
to compile a program using __attribute__((__ifunc__())). There are
additional checks in this program if glibc is being used or if it
is running on FreeBSD.
Setting --enable-ifunc will skip this test and always enable
__attribute__((__ifunc__())), even if is not supported.
-rw-r--r-- | configure.ac | 61 |
1 files changed, 44 insertions, 17 deletions
diff --git a/configure.ac b/configure.ac index 1fe61016..cdd72a9f 100644 --- a/configure.ac +++ b/configure.ac @@ -869,15 +869,37 @@ fi # implementations of the same function at runtime. This is slightly more # efficient than using __attribute__((__constructor__)) and setting # a function pointer. -AC_ARG_ENABLE([ifunc], [AS_HELP_STRING([--disable-ifunc], - [do not use __attribute__((__ifunc__()))])], - [], [enable_ifunc=yes]) - -if test "x$enable_ifunc" = xyes ; then +AC_ARG_ENABLE([ifunc], [AS_HELP_STRING([--enable-ifunc], + [Use __attribute__((__ifunc__())). Enabled by default on + GNU/Linux (glibc) and FreeBSD.])], + [], [enable_ifunc=auto]) + +# When enable_ifunc is 'auto', allow the use of __attribute__((__ifunc__())) +# if compiler support is detected and we are building for GNU/Linux (glibc) +# or FreeBSD. uClibc and musl don't support ifunc in their dynamic linkers +# but some compilers still accept the attribute when compiling for these +# C libraries, which results in broken binaries. That's why we need to +# check which libc is being used. +if test "x$enable_ifunc" = xauto ; then OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" AC_MSG_CHECKING([if __attribute__((__ifunc__())) can be used]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + /* + * Force a compilation error when not using glibc on Linux + * or if we are not using FreeBSD. uClibc will define + * __GLIBC__ but does not support ifunc, so we must have + * an extra check to disable with uClibc. + */ + #if defined(__linux__) + # include <features.h> + # if !defined(__GLIBC__) || defined(__UCLIBC__) + compile error + # endif + #elif !defined(__FreeBSD__) + compile error + #endif + static void func(void) { return; } static void (*resolve_func (void)) (void) { return func; } void func_ifunc (void) @@ -891,23 +913,28 @@ if test "x$enable_ifunc" = xyes ; then void make_clang_quiet(void); void make_clang_quiet(void) { resolve_func()(); } ]])], [ - AC_DEFINE([HAVE_FUNC_ATTRIBUTE_IFUNC], [1], + enable_ifunc=yes + ], [ + enable_ifunc=no + ]) + + AC_MSG_RESULT([$enable_ifunc]) + + CFLAGS="$OLD_CFLAGS" +fi + +if test "x$enable_ifunc" = xyes ; then + AC_DEFINE([HAVE_FUNC_ATTRIBUTE_IFUNC], [1], [Define to 1 if __attribute__((__ifunc__())) is supported for functions.]) - AC_MSG_RESULT([yes]) - # ifunc explicitly does not work with -fsanitize=address. - # If configured, it will result in a liblzma build that - # will fail when liblzma is loaded at runtime (when the - # ifunc resolver executes). - AS_CASE([$CFLAGS], [*-fsanitize=*], [AC_MSG_ERROR([ + # ifunc explicitly does not work with -fsanitize=address. + # If configured, it will result in a liblzma build that will fail + # when liblzma is loaded at runtime (when the ifunc resolver + # executes). + AS_CASE([$CFLAGS], [*-fsanitize=*], [AC_MSG_ERROR([ CFLAGS contains '-fsanitize=' which is incompatible with ifunc. Use --disable-ifunc when using '-fsanitize'.])]) - ], [ - AC_MSG_RESULT([no]) - ]) - - CFLAGS="$OLD_CFLAGS" fi |