From 615f5ab4c68623d45bab4477d9967d8582073f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= Date: Thu, 3 Aug 2017 17:40:09 +0200 Subject: [PATCH 2/2] WIP 2: Experimental fix for libqb logging not working with ld.bfd 2.29 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What's missing: * cross-testing programs vs. libqb prior/after this fix with ld.bfd 2.29 * program vs. library sanity attestation for good measure - code header-included in the program could/shall run-time one-off self-test the library code actually logs anything via custom callback log handler - library could/shall attest in qb_log_init that QB_ATTR_SECTION_START + STOP symbols belong to other address space than its own (dladdr?) Version 2: Simplify the compilation against libqb for its users that now no longer need to worry to use a new flag for compilation with the affected ld version, as semantically the same is already contained in libqb.so itself (it's now a linker script instead of a common symlink to the end versioned so file, which something known as an implicit linker script: https://sourceware.org/binutils/docs/ld/Implicit-Linker-Scripts.html). Deficiencies of version 2 (some carried over, apparently): - BUILT_SOURCES in lib/Makefile.am should be generalized over all dependent places: https://www.gnu.org/software/automake/manual/automake.html#Recording-Dependencies-manually - see What's missing above Deficiencies that are not solvable as long as we use the linker script to participate in restoring boundary section symbols being global again: - /usr/bin/ld: warning: ../lib/qblog_script.ld contains output sections; did you forget -T? References: http://oss.clusterlabs.org/pipermail/developers/2017-July/000503.html https://bugzilla.redhat.com/show_bug.cgi?id=1477354#c8 Signed-off-by: Jan Pokorný --- configure.ac | 59 ++++++++++++++++++++++++++++++++++++++++---------- examples/Makefile.am | 4 ++++ include/qb/Makefile.am | 3 ++- lib/Makefile.am | 28 ++++++++++++++++++++++++ lib/log.c | 7 ++++++ lib/qblog_script.ld.in | 15 +++++++++++++ tests/Makefile.am | 3 +++ 8 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 lib/qblog_script.ld.in diff --git a/configure.ac b/configure.ac index fd37466..ffb81d0 100644 --- a/configure.ac +++ b/configure.ac @@ -618,31 +618,68 @@ AC_SUBST(HAVE_SLOW_TESTS) # --- callsite sections --- if test "x${GCC}" = xyes; then + LDFLAGS_save="${LDFLAGS}" AC_MSG_CHECKING([whether GCC supports __attribute__((section()) + ld supports orphan sections]) if test "x${ac_cv_link_attribute_section}" = x ; then + LDFLAGS="${LDFLAGS_save} -shared -fPIC" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [[#include + extern int __start___verbose[], __stop___verbose[]; + int test(void) { + static int my_var __attribute__((section("__verbose"))) = 3; + if (__start___verbose == __stop___verbose) assert(0); + return *((int *) __start___verbose); + }]])], + [gcc_has_attribute_section=yes; cp "conftest${EXEEXT}" "lib_conftest.so"], + [gcc_has_attribute_section=no] + ) + LDFLAGS="${LDFLAGS_save}" + else + gcc_has_attribute_section=${ac_cv_link_attribute_section} + fi + AC_MSG_RESULT($gcc_has_attribute_section) + + # in the failing case (e.g. with ld from binutils 2.29), it's probable + # linking will fail readily (hidden symbol `__stop___verbose' in + # conftest is referenced by DSO), but keep the sensible test (in-binary + # symbol is expected to be propagated into the library, and draw the + # full circle back to binary through standard return value passing + # (-rpath passed because LD_LIBRARY_PATH exporting is unwieldy here) + if test "x${gcc_has_attribute_section}" = xyes; then + AC_MSG_CHECKING([whether linker emits global symbols for orphan sections]) + LDFLAGS="${LDFLAGS_save} -L. -l_conftest -Wl,-rpath=$(pwd)" AC_TRY_RUN( AC_LANG_PROGRAM( [[#include - extern void * __start___verbose, * __stop___verbose;]], + extern int __start___verbose[], __stop___verbose[]; + int test(void);]], [[static int my_var __attribute__((section("__verbose"))) = 5; if (__start___verbose == __stop___verbose) assert(0); - if (my_var == 5) return 0; - else return -1; + return !(my_var == test() /*5?*/); ]]), - [gcc_has_attribute_section=yes], - [gcc_has_attribute_section=no] + [gcc_has_attribute_section_visible=yes], + [gcc_has_attribute_section_visible=no] ) - else - gcc_has_attribute_section=${ac_cv_link_attribute_section} - fi + LDFLAGS="${LDFLAGS_save}" + AC_MSG_RESULT($gcc_has_attribute_section_visible) + rm -f "lib_conftest.so" - AC_MSG_RESULT($gcc_has_attribute_section) - if test $gcc_has_attribute_section = yes; then AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1, [Enabling code using __attribute__((section))]) - PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" + if test "x${gcc_has_attribute_section_visible}" = xyes; then + PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section" + else + AC_DEFINE([QB_NEED_ATTRIBUTE_SECTION_WORKAROUND], 1, + [Enabling code using __attribute__((section))]) + PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section-workaround" + fi fi fi +AM_CONDITIONAL(HAVE_GCC_ATTRIBUTE_SECTION, [test "x${gcc_has_attribute_section}" = xyes]) +AM_CONDITIONAL(NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND, + [test "x${gcc_has_attribute_section}" = xyes \ + && test "x${gcc_has_attribute_section_visible}" != xyes]) # --- ansi --- if test "x${enable_ansi}" = xyes && \ diff --git a/examples/Makefile.am b/examples/Makefile.am index 3637d30..b2264fd 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -23,6 +23,10 @@ CLEANFILES = noinst_PROGRAMS = mapnotify simplelog tcpclient tcpserver ipcclient ipcserver +if NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND +AM_LDFLAGS = $(top_builddir)/lib/qblog_script.ld +endif + mapnotify_SOURCES = mapnotify.c $(top_builddir)/include/qb/qbmap.h mapnotify_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include mapnotify_LDADD = $(top_builddir)/lib/libqb.la diff --git a/include/qb/Makefile.am b/include/qb/Makefile.am index 41d7e23..d09cca7 100644 --- a/include/qb/Makefile.am +++ b/include/qb/Makefile.am @@ -18,7 +18,8 @@ # along with libqb. If not, see . # -MAINTAINERCLEANFILES = Makefile.in +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = qblog.t instdir = $(includedir)/qb/ inst_HEADERS = qbhdb.h qblist.h qbdefs.h qbatomic.h \ qbloop.h qbrb.h qbutil.h qbarray.h \ diff --git a/lib/Makefile.am b/lib/Makefile.am index 0bebeb5..f85ba76 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -20,6 +20,7 @@ MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = qblog_script.ld noinst_HEADERS = ipc_int.h util_int.h ringbuffer_int.h loop_int.h \ log_int.h map_int.h rpl_sem.h loop_poll_int.h \ @@ -39,11 +40,15 @@ source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c \ log_syslog.c log_dcs.c log_format.c \ map.c skiplist.c hashtable.c trie.c +BUILT_SOURCES = $(top_builddir)/lib/qblog_script.ld libqb_la_SOURCES = $(source_to_lint) unix.c libqb_la_CFLAGS = $(PTHREAD_CFLAGS) libqb_la_LIBADD = $(LTLIBOBJS) $(dlopen_LIBS) $(PTHREAD_LIBS) $(socket_LIBS) AM_LDFLAGS = $(LDFLAGS_COPY:-Bsymbolic-functions=) +if NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND +AM_LDFLAGS += $(top_builddir)/lib/qblog_script.ld +endif if HAVE_SEM_TIMEDWAIT else @@ -60,6 +65,29 @@ else endif endif +%.ld: %.ld.in + $(CPP) -xc -I$(top_srcdir)/include -C -P $< \ + | sed -n "/$$(sed -n '/^[^#]/{s/[*\/]/\\\0/g;p;q}' $<)/{:r;p;n;br}" \ + > $@ + +# find the libqb.so symlink's target, if so, try to find out, iteratively, +# its gradually shorter forms that likewise symlinks the same target as the +# original libqb.so path, point to that file from the linker script using +# qblog_script.ld as a template, and stored in place of original libqb.so +# NOTE: readlink nor realpath are POSIX; not chained links ready +install-exec-hook: $(top_builddir)/lib/qblog_script.ld + target=$$(ls -l "$(DESTDIR)$(libdir)/libqb.so" || :); \ + target=$${target#* -> }; t1_bn=$$(basename "$${target}" || :); \ + while test -n "$${t1_bn}"; do t2_bn=$${t1_bn%.*[0-9]*}; \ + test "$${t2_bn}" != libqb.so || break; \ + test -L "$${t2_bn}" || { t1_bn=$${t2_bn}; continue; }; \ + t2_target=$$(ls -l "$${t2_bn}" || break); t2_target=$${t2_target#* -> }; \ + test "$${t2_target}" = "$${target}" || break; \ + t1_bn=$${t2_bn}; done; test -n "$${t1_bn}" || \ + { echo "only applicable to SO symlink scheme"; exit 1; }; \ + echo "INPUT($${t1_bn})" > "$(DESTDIR)$(libdir)/libqb.so-t"; \ + cat $< >> "$(DESTDIR)$(libdir)/libqb.so-t"; \ + mv -f "$(DESTDIR)$(libdir)/libqb.so-t" "$(DESTDIR)$(libdir)/libqb.so" pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libqb.pc diff --git a/lib/log.c b/lib/log.c index bfd218f..3cb703b 100644 --- a/lib/log.c +++ b/lib/log.c @@ -40,6 +40,13 @@ #include "util_int.h" #include +#ifdef QB_NEED_ATTRIBUTE_SECTION_WORKAROUND +/* following only needed to force these symbols be global + with ld 2.29: https://bugzilla.redhat.com/1477354 */ +struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_START[] = { 0 }; +struct qb_log_callsite __attribute__((weak)) QB_ATTR_SECTION_STOP[] = { 0 }; +#endif + static struct qb_log_target conf[QB_LOG_TARGET_MAX]; static uint32_t conf_active_max = 0; static int32_t in_logger = QB_FALSE; diff --git a/lib/qblog_script.ld.in b/lib/qblog_script.ld.in new file mode 100644 index 0000000..2d430ab --- /dev/null +++ b/lib/qblog_script.ld.in @@ -0,0 +1,15 @@ +#include +/* GNU ld script + This atypical arrangement enforces global visibility of boundary symbols + (QB_ATTR_SECTION_START, QB_ATTR_SECTION_STOP) for the custom section + QB_ATTR_SECTION used for compile-time offloading of the logging call sites + tracking. While libqb relies on these being global, default linker from + binutils change the visibility as of version 2.29, making the logging + unusable without artificial stimulus: https://bugzilla.redhat.com/1477354 */ +SECTIONS { + QB_ATTR_SECTION : { + QB_ATTR_SECTION_START = .; + *(QB_ATTR_SECTION); + QB_ATTR_SECTION_STOP = .; + } +} diff --git a/tests/Makefile.am b/tests/Makefile.am index fe54741..44401cd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,6 +21,9 @@ MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = CLEANFILES = AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include +if NEED_GCC_ATTRIBUTE_SECTION_WORKAROUND +AM_LDFLAGS = $(top_builddir)/lib/qblog_script.ld +endif noinst_PROGRAMS = bmc bmcpt bms rbreader rbwriter \ bench-log format_compare_speed loop print_ver -- 2.14.0