From ffc6b678b9d12a8f963ab362b952fd6b7e6c4ec7 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 9 Apr 2014 22:40:33 -0400 Subject: [PATCH 1/4] build: add glibc/libstdc++ back-compat stubs glibc/libstdc++ have added new symbols in later releases. When running a new binary against an older glibc, the run-time linker is unable to resolve the new symbols and the binary refuses to run. This can be fixed by adding our own versions of those functions, so that the build-time linker does not emit undefined symbols for them. This enables our binary releases to work on older Linux distros, while not incurring the downsides of a fully static binary. --- src/compat/glibc_compat.cpp | 19 +++++++++ src/compat/glibcxx_compat.cpp | 80 +++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/compat/glibc_compat.cpp create mode 100644 src/compat/glibcxx_compat.cpp diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp new file mode 100644 index 000000000..5b73e6051 --- /dev/null +++ b/src/compat/glibc_compat.cpp @@ -0,0 +1,19 @@ +#include "bitcoin-config.h" +#include +#include + +// Prior to GLIBC_2.14, memcpy was aliased to memmove. +extern "C" void* memmove(void* a, const void* b, size_t c); +extern "C" void* memcpy(void* a, const void* b, size_t c) +{ + return memmove(a, b, c); +} + +extern "C" void __chk_fail (void) __attribute__((__noreturn__)); +extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a) +{ + if (a >= FD_SETSIZE) + __chk_fail (); + return a / __NFDBITS; +} +extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn"))); diff --git a/src/compat/glibcxx_compat.cpp b/src/compat/glibcxx_compat.cpp new file mode 100644 index 000000000..6e04f6745 --- /dev/null +++ b/src/compat/glibcxx_compat.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +#ifndef _GLIBCXX_USE_NOEXCEPT + #define _GLIBCXX_USE_NOEXCEPT throw() +#endif + +namespace std { + +const char* bad_exception::what() const throw() +{ + return "std::bad_exception"; +} + +const char* bad_cast::what() const throw() +{ + return "std::bad_cast"; +} + +const char* bad_alloc::what() const throw() +{ + return "std::bad_alloc"; +} + +namespace __detail +{ +struct _List_node_base +{ + void _M_hook(std::__detail::_List_node_base* const __position) throw () __attribute__((used)) + { + _M_next = __position; + _M_prev = __position->_M_prev; + __position->_M_prev->_M_next = this; + __position->_M_prev = this; + } + void _M_unhook() __attribute__((used)) + { + _List_node_base* const __next_node = _M_next; + _List_node_base* const __prev_node = _M_prev; + __prev_node->_M_next = __next_node; + __next_node->_M_prev = __prev_node; + } + _List_node_base* _M_next; + _List_node_base* _M_prev; +}; +} // namespace detail + +template ostream& ostream::_M_insert(bool); +template ostream& ostream::_M_insert(long); +template ostream& ostream::_M_insert(double); +template ostream& ostream::_M_insert(unsigned long); +template ostream& ostream::_M_insert(const void*); +template ostream& __ostream_insert(ostream&, const char*, streamsize); +template istream& istream::_M_extract(long&); +template istream& istream::_M_extract(unsigned short&); + +out_of_range::~out_of_range() _GLIBCXX_USE_NOEXCEPT { } + +// Used with permission. +// See: https://github.com/madlib/madlib/commit/c3db418c0d34d6813608f2137fef1012ce03043d + +void +ctype::_M_widen_init() const { + char __tmp[sizeof(_M_widen)]; + for (unsigned __i = 0; __i < sizeof(_M_widen); ++__i) + __tmp[__i] = __i; + do_widen(__tmp, __tmp + sizeof(__tmp), _M_widen); + + _M_widen_ok = 1; + // Set _M_widen_ok to 2 if memcpy can't be used. + for (unsigned __i = 0; __i < sizeof(_M_widen); ++__i) + if (__tmp[__i] != _M_widen[__i]) { + _M_widen_ok = 2; + break; + } +} + +}// namespace std From d5aab704908d6bea48bd7e7b36a3a49ece7d5c5f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 27 Mar 2014 19:58:41 -0400 Subject: [PATCH 2/4] build: add an option for enabling glibc back-compat Using "./configure --enable-glibc-back-compat" will attempt to be compatible with a target running glibc abi 2.9 and libstdc++ abi 3.4. --- configure.ac | 22 ++++++++++++++++++++++ src/Makefile.am | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/configure.ac b/configure.ac index 45cd023bb..3e508571e 100644 --- a/configure.ac +++ b/configure.ac @@ -108,6 +108,12 @@ AC_ARG_ENABLE([lcov], [use_lcov=yes], [use_lcov=no]) +AC_ARG_ENABLE([glibc-back-compat], + [AS_HELP_STRING([--enable-glibc-back-compat], + [enable backwards compatibility with glibc and libstdc++])], + [use_glibc_compat=$enableval], + [use_glibc_compat=no]) + AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) @@ -319,6 +325,21 @@ fi AX_CHECK_LINK_FLAG([[-Wl,--large-address-aware]], [LDFLAGS="$LDFLAGS -Wl,--large-address-aware"]) +if test x$use_glibc_compat != xno; then + + #__fdelt_chk's params and return type have changed from long unsigned int to long int. + # See which one is present here. + AC_MSG_CHECKING(__fdelt_chk type) + AC_TRY_COMPILE([#define __USE_FORTIFY_LEVEL 2 + #include + extern "C" long unsigned int __fdelt_warn(long unsigned int);],[], + [ fdelt_type="long unsigned int"], + [ fdelt_type="long int"]) + AC_MSG_RESULT($fdelt_type) + AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) + +fi + if test x$use_hardening != xno; then AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) AX_CHECK_COMPILE_FLAG([-fstack-protector-all],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"]) @@ -691,6 +712,7 @@ AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov == xyes]) AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno]) AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno]) +AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) diff --git a/src/Makefile.am b/src/Makefile.am index c725c4f1c..a19246a5c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -135,6 +135,11 @@ libbitcoin_common_a_SOURCES = \ version.cpp \ $(BITCOIN_CORE_H) +if GLIBC_BACK_COMPAT +libbitcoin_common_a_SOURCES += compat/glibc_compat.cpp +libbitcoin_common_a_SOURCES += compat/glibcxx_compat.cpp +endif + libbitcoin_cli_a_SOURCES = \ rpcclient.cpp \ $(BITCOIN_CORE_H) From 49a3352c1c05319c5fa22c4cb6819371d71de74d Mon Sep 17 00:00:00 2001 From: Warren Togami Date: Tue, 8 Apr 2014 18:20:44 -1000 Subject: [PATCH 3/4] gitian-linux: --enable-glibc-back-compat --- contrib/gitian-descriptors/gitian-linux.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 018b6fb26..1747f531e 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -41,7 +41,7 @@ script: | cd ../build function do_configure { - ./configure "$@" --enable-upnp-default --prefix=$STAGING --with-protoc-bindir=$STAGING/host/bin --with-boost=$STAGING --disable-maintainer-mode --disable-dependency-tracking PKG_CONFIG_PATH="$STAGING/lib/pkgconfig" CPPFLAGS="-I$STAGING/include ${OPTFLAGS}" LDFLAGS="-L$STAGING/lib ${OPTFLAGS}" CXXFLAGS="-frandom-seed=bitcoin ${OPTFLAGS}" BOOST_CHRONO_EXTRALIBS="-lrt" + ./configure "$@" --enable-upnp-default --prefix=$STAGING --with-protoc-bindir=$STAGING/host/bin --with-boost=$STAGING --disable-maintainer-mode --disable-dependency-tracking PKG_CONFIG_PATH="$STAGING/lib/pkgconfig" CPPFLAGS="-I$STAGING/include ${OPTFLAGS}" LDFLAGS="-L$STAGING/lib ${OPTFLAGS}" CXXFLAGS="-frandom-seed=bitcoin ${OPTFLAGS}" BOOST_CHRONO_EXTRALIBS="-lrt" --enable-glibc-back-compat } # cd bitcoin @@ -60,19 +60,6 @@ script: | make $MAKEOPTS install-strip make $MAKEOPTS clean - # Build fully static versions of bitcoind and bitcoin-cli for older Linux distros - STATIC_BINDIR="$HOME/bindir.static" - mkdir -p $STATIC_BINDIR - # For 32-bit, -pie cannot be used with -static, as invalid executables are generated - # For 64-bit, -pie with -static causes a link error - # Disable hardening in configure and manually pass 'static-safe' hardening flags - OPTFLAGS='-O2 -static -Wstack-protector -fstack-protector-all -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wl,-z,now' - do_configure --bindir=$STATIC_BINDIR --disable-tests --enable-upnp-default --without-gui --disable-hardening - make $MAKEOPTS - make $MAKEOPTS install-strip - cp $STATIC_BINDIR/bitcoind $BINDIR/bitcoind.static - cp $STATIC_BINDIR/bitcoin-cli $BINDIR/bitcoin-cli.static - # sort distribution tar file and normalize user/group/mtime information for deterministic output mkdir -p $OUTDIR/src rm -rf $TEMPDIR From 05c20a553a12d03b1512a75973674c6d25534259 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 11 Apr 2014 18:51:49 -0400 Subject: [PATCH 4/4] build: add symbol for upcoming gcc 4.9's libstdc++ --- src/compat/glibcxx_compat.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compat/glibcxx_compat.cpp b/src/compat/glibcxx_compat.cpp index 6e04f6745..e91376f81 100644 --- a/src/compat/glibcxx_compat.cpp +++ b/src/compat/glibcxx_compat.cpp @@ -77,4 +77,11 @@ ctype::_M_widen_init() const { } } +void __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__)); +void __throw_out_of_range_fmt(const char* err, ...) +{ + // Safe and over-simplified version. Ignore the format and print it as-is. + __throw_out_of_range(err); +} + }// namespace std