Skip to content

Commit

Permalink
WIP 2: Experimental fix for libqb logging not working with ld.bfd 2.29
Browse files Browse the repository at this point in the history
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ý <[email protected]>
  • Loading branch information
jnpkrn committed Aug 10, 2017
1 parent 3792394 commit 01c4700
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ configure
/.tarball-version
/tag-*

/lib/qblog_script.ld

libtool
.version
libqb.spec
Expand Down
59 changes: 48 additions & 11 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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 <assert.h>
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 <assert.h>
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 && \
Expand Down
4 changes: 4 additions & 0 deletions examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion include/qb/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
# along with libqb. If not, see <http://www.gnu.org/licenses/>.
#

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 \
Expand Down
28 changes: 28 additions & 0 deletions lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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
Expand All @@ -60,6 +65,29 @@ else
endif
endif

$(top_builddir)/lib/%.ld: $(top_srcdir)/lib/%.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
Expand Down
7 changes: 7 additions & 0 deletions lib/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@
#include "util_int.h"
#include <regex.h>

#if defined(QB_NEED_ATTRIBUTE_SECTION_WORKAROUND) && !defined(S_SPLINT_S)
/* 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 # defined(QB_NEED_ATTRIBUTE_SECTION_WORKAROUND) && !defined(S_SPLINT_S)

static struct qb_log_target conf[QB_LOG_TARGET_MAX];
static uint32_t conf_active_max = 0;
static int32_t in_logger = QB_FALSE;
Expand Down
15 changes: 15 additions & 0 deletions lib/qblog_script.ld.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <qb/qblog.h>
/* 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 = .;
}
}
3 changes: 3 additions & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 01c4700

Please sign in to comment.