diff --git a/.travis.yml b/.travis.yml index 5dcd81a2..41a52d19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ addons: packages: - autoconf - automake + - clang - gawk + - gcc-10 - lcov - libtool - - llvm + - llvm-dev - pkg-config - python3-venv - valgrind @@ -84,6 +86,20 @@ matrix: env: - CONF="--enable-obsolete-api --enable-hashes=all" - SANITIZER=1 + - name: "Linux, GCC, all hashes, obsolete API, LTO, ASan+UBSan" + compiler: gcc + os: linux + env: + - CONF="--enable-obsolete-api --enable-hashes=all" + - LTO=1 + - SANITIZER=1 + - name: "Linux, Clang, all hashes, obsolete API, LTO, ASan+UBSan" + compiler: clang + os: linux + env: + - CONF="--enable-obsolete-api --enable-hashes=all" + - LTO=1 + - SANITIZER=1 - name: "Linux, GCC, all hashes, static lib" compiler: gcc os: linux diff --git a/.travis_script.sh b/.travis_script.sh index d3af788c..146a8045 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -133,6 +133,29 @@ if [[ "$SANITIZER" == "1" ]]; then export CXXFLAGS="$CXXFLAGS -fsanitize=undefined,address" fi +if [[ "$LTO" == "1" ]]; then + if [[ "$CC" == "gcc" ]]; then + export CC="gcc-10" + export CPP="cpp-10" + export CXX="g++-10" + export AR="gcc-ar-10" + export NM="gcc-nm-10" + export RANLIB="gcc-ranlib-10" + export CFLAGS="$CFLAGS -flto=auto -ffat-lto-objects" + export CXXFLAGS="$CXXFLAGS -flto=auto -ffat-lto-objects" + fi + if [[ "$CC" == "clang" ]]; then + export CC="/usr/bin/clang" + export CPP="/usr/bin/clang-cpp-10" + export CXX="/usr/bin/clang++" + export AR="/usr/bin/llvm-ar" + export NM="/usr/bin/llvm-nm" + export RANLIB="/usr/bin/llvm-ranlib" + export CFLAGS="$CFLAGS -flto" + export CXXFLAGS="$CXXFLAGS -flto" + fi +fi + pushd build log_time preparation diff --git a/NEWS b/NEWS index 67b1aa2b..34839efe 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,11 @@ Version 4.4.17 newline '\n' character, since all parameters of the user data must be on the same line within the Unix shadow file. +* Building with link-time optimization (-flto) enabled is now + possible with either GCC 10 or LLVM/Clang 10 (issue #24). + See the 'Portability Notes' section of the README.md file for + detailed instructions and possible caveats. + Version 4.4.16 * Add support for the e2k architecture. diff --git a/README.md b/README.md index d0197a01..c0a40a63 100644 --- a/README.md +++ b/README.md @@ -93,13 +93,29 @@ not always be able to retrieve cryptographically-sound random numbers from the operating system; if you call these functions with a null pointer for the “rbytes” argument, be prepared for them to fail. -As of mid-2018, GCC and LLVM don’t support link-time optimization of -libraries that use symbol versioning. If you build libxcrypt with -either of these compilers, do not use `-flto`. See [GCC bug 48200][1] -for specifics; the problem is very similar for LLVM. Because this is, -at its root, a set of missing compiler features, we expect link-time -optimization won’t work in other C compilers either, but we haven’t -tested it ourselves. +As of August 2020, link-time optimization (`-flto`) of libraries that use +symbol versioning is initially supported by GCC 10 and LLVM/Clang 10, if +their compiler specific toolchain is used during compilation. + +For GCC the needed tools are called with: +``` +./configure CC="gcc" AR="gcc-ar" NM="gcc-nm" RANLIB="gcc-ranlib" \ +CFLAGS="-O2 -flto -g" ... +``` +and for LLVM/Clang those tools are called with: +``` +./configure CC="clang" AR="llvm-ar" NM="llvm-nm" RANLIB="llvm-ranlib" \ +CFLAGS="-O2 -flto -g" ... +``` + +To build static libraries, that can be linked against non-LTO objects +one may also want to add `-ffat-lto-objects` to the CFLAGS. + +If you build libxcrypt with earlier versions of these compilers, do not +use `-flto`. See [GCC bug 48200][1] for specifics; the problem is very +similar for LLVM. Because this is, at its root, a set of missing compiler +features, we expect link-time optimization won’t work in other C compilers +either, but we haven’t tested it ourselves. [1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200 diff --git a/lib/crypt-port.h b/lib/crypt-port.h index bec36aca..bbbe92dd 100644 --- a/lib/crypt-port.h +++ b/lib/crypt-port.h @@ -50,6 +50,20 @@ #include #endif +/* The prototype of the crypt() function possibly defined in + needs to be renamed as it might be incompatible with our declaration. + Defining this macro *AFTER* the crypt-symbol-vers header, which also + defines the same macro for symbol-versioning purposes, was included, + would lead to a clashing redefinition of this macro, and thus cause + our symbol-versioning would not work properly. */ +#ifdef HAVE_UNISTD_H +#define crypt unistd_crypt_is_incompatible +#define crypt_r unistd_crypt_r_is_incompatible +#include +#undef crypt +#undef crypt_r +#endif + #ifndef HAVE_SYS_CDEFS_THROW #define __THROW /* nothing */ #endif @@ -179,11 +193,29 @@ _crypt_strcpy_or_abort (void *, const size_t, const void *); # define _strong_alias(name, aliasname) \ extern __typeof (name) aliasname __THROW __attribute__ ((alias (#name))) +/* Starting with GCC 10, we can use the symver attribute, which also works + with link-time optimization enabled. */ +# if __GNUC__ >= 10 + +/* Set the symbol version for EXTNAME, which uses INTNAME as its + implementation. */ +# define symver_set(extstr, intname, version, mode) \ + extern __typeof (intname) intname __THROW \ + __attribute__((symver (extstr mode #version))) + +/* Referencing specific _compatibility_ symbols still needs inline asm. */ +# define _symver_ref(extstr, intname, version) \ + __asm__ (".symver " #intname "," extstr "@" #version) + +# else + /* Set the symbol version for EXTNAME, which uses INTNAME as its implementation. */ # define symver_set(extstr, intname, version, mode) \ __asm__ (".symver " #intname "," extstr mode #version) +# endif + #else # error "Don't know how to do symbol versioning with this compiler" #endif @@ -239,9 +271,14 @@ _crypt_strcpy_or_abort (void *, const size_t, const void *); /* Tests may need to _refer_ to compatibility symbols, but should never need to _define_ them. */ - #define symver_ref(extstr, intname, version) \ + _symver_ref(extstr, intname, version) + +/* Generic way for referencing specific _compatibility_ symbols. */ +#ifndef _symver_ref +#define _symver_ref(extstr, intname, version) \ symver_set(extstr, intname, version, "@") +#endif /* Define configuration macros used during compile-time by the GOST R 34.11-2012 "Streebog" hash function. */ diff --git a/lib/randombytes.c b/lib/randombytes.c index 2c80bc7d..f7af93d4 100644 --- a/lib/randombytes.c +++ b/lib/randombytes.c @@ -31,9 +31,6 @@ #ifdef HAVE_SYS_STAT_H #include #endif -#ifdef HAVE_UNISTD_H -#include -#endif /* If we have O_CLOEXEC, we use it, but if we don't, we don't worry about it. */ diff --git a/libxcrypt.spec.rpkg b/libxcrypt.spec.rpkg index 12e24426..e8ecf883 100644 --- a/libxcrypt.spec.rpkg +++ b/libxcrypt.spec.rpkg @@ -151,11 +151,6 @@ fi \ %global _ld_strict_symbol_defs 1 -# The library uses symbol versioning in way -# that is not compatible with LTO currently. -%undefine _lto_cflags - - Name: {{{ git_name }}} Version: {{{ git_real_version }}} Release: 0.{{{ git_real_release }}}%{?dist} diff --git a/test/badsalt.c b/test/badsalt.c index 803b5758..2eecc19c 100644 --- a/test/badsalt.c +++ b/test/badsalt.c @@ -17,12 +17,10 @@ . */ #include "crypt-port.h" -#include #include #include #include #include -#include static const char phrase[] = "values of β will give rise to dom!"; diff --git a/test/crypt-badargs.c b/test/crypt-badargs.c index 59c6690a..ae690320 100644 --- a/test/crypt-badargs.c +++ b/test/crypt-badargs.c @@ -15,7 +15,6 @@ #include #include #include -#include /* The behavior tested below should be consistent for all hashing methods. */ diff --git a/test/getrandom-fallbacks.c b/test/getrandom-fallbacks.c index 9f93cbad..8469a2ec 100644 --- a/test/getrandom-fallbacks.c +++ b/test/getrandom-fallbacks.c @@ -23,9 +23,6 @@ #ifdef HAVE_SYS_STAT_H #include #endif -#ifdef HAVE_UNISTD_H -#include -#endif /* If arc4random_buf is available, all of the fallback logic is compiled out and this test is unnecessary. If ld --wrap is not available this diff --git a/test/getrandom-interface.c b/test/getrandom-interface.c index 82be78af..e0336872 100644 --- a/test/getrandom-interface.c +++ b/test/getrandom-interface.c @@ -15,7 +15,6 @@ #include #include #include -#include static bool error_occurred; diff --git a/test/short-outbuf.c b/test/short-outbuf.c index 9418c2a7..be274311 100644 --- a/test/short-outbuf.c +++ b/test/short-outbuf.c @@ -17,7 +17,6 @@ */ #include "crypt-port.h" -#include #include #include #include