libhugetlbfs redefines shmget() so that it can transparently optionally add the hugepage flag. Unfortunately, it uses dlsym() to to find the next shmget() to call in the dynamic library call chain. This does not work on statically-linked executables. Even if the executable is linked against -ldl, dlsym() in a statically-linked executable does not return a reference to the glibc shmget() library routine.
Work around this by making all references to libdl weak, and testing for its presence. If libdl symbols are not not present, assume static linking, and directly make the shmget syscall. Making the dl* symbols weak does not affect dynamic executables as libdl.so is: * Automatically added to the library dependency list when liked with -lhugetlbfs * Mapped into the programs address space when used with LD_PRELOAD. Based on a patch originally authored by Dean Luick <lu...@cray.com>. Signed-off-by: Andrew Hastings <a...@cray.com> on behalf of Cray Inc. --- Changes from V1: - Add code to support platforms such as ia32 that use the SYS_ipc syscall instead of SYS_shmget. Tested on x86_64 (32- and 64-bit) and ia32. Changes from V2: - Add to the libhugetlbfs test Makefile support for static linking. - Build a static version of the shmoverride_linked test. - Correct runtests.py to run all cases of shmoverride: with and without LD_PRELOAD, with and without HUGETLB_SHM, with and without prelinking. -Andrew Hastings Cray Inc. shm.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++--- tests/Makefile | 33 +++++++++++++++++++++++- tests/run_tests.py | 4 ++ 3 files changed, 103 insertions(+), 5 deletions(-) diff -ruNp libhugetlbfs-2.11/shm.c libhugetlbfs-2.11-shm/shm.c --- libhugetlbfs-2.11/shm.c 2010-12-16 11:38:22.000000000 -0600 +++ libhugetlbfs-2.11-shm/shm.c 2011-01-05 15:53:54.000000000 -0600 @@ -28,6 +28,61 @@ #include <sys/types.h> #include "libhugetlbfs_internal.h" #include "hugetlbfs.h" +#include <sys/syscall.h> + +#if defined(SYS_shmget) || defined(SYS_ipc) +#define HAVE_SHMGET_SYSCALL +#endif + +#ifdef HAVE_SHMGET_SYSCALL +/* + * The calls to dlsym() and dlerror() in the shmget() wrapper below force + * a dependency on libdl.so. This does not work for static executables + * as the glibc dynamic library implementation does not automatically + * have static dl* function stubs linked into static executables. + * + * Work around this problem by adding a weak attribute to the declarations + * of dlsym() and dlerror(). (The declaration is otherwise the same as in + * <dlfcn.h>). This allows a static executable to be linked without -ldl. + * If &dlsym is NULL then this is a static executable and a call to the + * system shmget() may be performed without worry as there is no dynamic + * call chain. + */ +extern void *dlsym (void *__restrict __handle, __const char *__restrict __name) + __attribute__((weak)) __THROW __nonnull ((2)); +extern char *dlerror (void) __attribute__((weak)) __THROW; + + +/* call syscall shmget through the generic syscall mechanism */ +static int syscall_shmget(key_t key, size_t size, int shmflg) +{ +#ifdef SYS_shmget + return syscall(SYS_shmget, key, size, shmflg); +#else + /* + * Some platforms do not have have a direct shmget syscall. Instead, + * all SysV IPC calls are funneled through the ipc() system call. + * + * ipc() is expected to only be used by libc implementors, so using + * it has not been smoothed out. There is no function declaration. + * The needed define for SHMGET is in linux/ipc.h, but that file + * also includes a conflicting definition of ipc_perm. So, + * just define the needed items here. + * + * When compiling -m32 on x86_64, the ipc glibc wrapper does not + * exist. Instead, just use SYS_ipc. + * + * The ipc system call below does not set the IPC_64 version flag + * with SHMGET because that would have required more private defines + * and the version number is not used for the SHMGET call. + */ + #define SHMGET 23 + + return syscall(SYS_ipc, SHMGET, key, size, shmflg, (void *)NULL, 0L); +#endif +} + +#endif /* HAVE_SHMGET_SYSCALL */ int shmget(key_t key, size_t size, int shmflg) { @@ -40,10 +95,18 @@ int shmget(key_t key, size_t size, int s /* Get a handle to the "real" shmget system call */ if (!real_shmget) { - real_shmget = dlsym(RTLD_NEXT, "shmget"); - if ((error = dlerror()) != NULL) { - ERROR("%s", error); - return -1; +#ifdef HAVE_SHMGET_SYSCALL + if (&dlsym == NULL) { + /* in a static executable, call shmget directly */ + real_shmget = syscall_shmget; + } else +#endif /* HAVE_SHMGET_SYSCALL */ + { + real_shmget = dlsym(RTLD_NEXT, "shmget"); + if ((error = dlerror()) != NULL) { + ERROR("%s", error); + return -1; + } } } diff -ruNp libhugetlbfs-2.11/tests/Makefile libhugetlbfs-2.11-shm/tests/Makefile --- libhugetlbfs-2.11/tests/Makefile 2010-12-16 11:38:22.000000000 -0600 +++ libhugetlbfs-2.11-shm/tests/Makefile 2011-01-14 14:38:58.357087000 -0600 @@ -27,7 +27,9 @@ BADTOOLCHAIN = bad-toolchain.sh CFLAGS = -O2 -Wall -g CPPFLAGS = -I.. -LDLIBS = -Wl,--no-as-needed -ldl -lpthread -lhugetlbfs_privutils +STATIC_LIBHUGE = -Wl,--whole-archive -lhugetlbfs -Wl,--no-whole-archive +STATIC_LDLIBS = -Wl,--no-as-needed -lpthread +LDLIBS = $(STATIC_LDLIBS) -ldl -lhugetlbfs_privutils LDFLAGS32 = -L../obj32 LDFLAGS64 = -L../obj64 INSTALL = install @@ -71,6 +73,19 @@ ifdef CC64 ALLTESTS += $(TESTS_64:%=obj64/%) endif +# For now, build only one test as a static binary. +# Can be changed once libhugetlbfs has better support for static linking. +# Also, some tests should be changed to use syscall() instead of +# dlsym() / rtld_next(). +ifdef CC32 +#ALLTESTS += $(LIB_TESTS:%=obj32/%_static) $(STRESS_TESTS:%=obj32/%_static) +ALLTESTS += obj32/shmoverride_linked_static +endif +ifdef CC64 +#ALLTESTS += $(LIB_TESTS:%=obj64/%_static) $(STRESS_TESTS:%=obj64/%_static) +ALLTESTS += obj64/shmoverride_linked_static +endif + objs_needing_wrappers = \ $(foreach W,$(WRAPPERS:%.sh=%),$(filter $(1)/$(W),$(ALLTESTS))) WRAPPERS32 = $(addsuffix .sh,$(call objs_needing_wrappers,obj32)) @@ -120,6 +135,14 @@ $(LIB_TESTS:%=obj64/%) $(LIB_TESTS_64:%= @$(VECHO) LD64 "(lib test)" $@ $(CC64) $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(LDLIBS) -lhugetlbfs +$(LIB_TESTS:%=obj32/%_static): %_static: %.o obj32/testutils.o obj32/libtestutils.o + @$(VECHO) LD32 "(lib test)" $@ + $(CC32) -static $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(STATIC_LDLIBS) $(STATIC_LIBHUGE) + +$(LIB_TESTS:%=obj64/%_static) $(LIB_TESTS_64:%=obj64/%_static): %_static: %.o obj64/testutils.o obj64/libtestutils.o + @$(VECHO) LD64 "(lib test)" $@ + $(CC64) -static $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(STATIC_LDLIBS) $(STATIC_LIBHUGE) + $(NOLIB_TESTS:%=obj32/%): %: %.o obj32/testutils.o @$(VECHO) LD32 "(nolib test)" $@ $(CC32) $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(LDLIBS) @@ -172,6 +195,14 @@ $(STRESS_TESTS:%=obj64/%): %: %.o obj64/ @$(VECHO) LD64 "(lib test)" $@ $(CC64) $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(LDLIBS) -lhugetlbfs +$(STRESS_TESTS:%=obj32/%_static): %_static: %.o obj32/testutils.o + @$(VECHO) LD32 "(lib test)" $@ + $(CC32) -static $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(STATIC_LDLIBS) $(STATIC_LIBHUGE) + +$(STRESS_TESTS:%=obj64/%_static): %_static: %.o obj64/testutils.o + @$(VECHO) LD64 "(lib test)" $@ + $(CC64) -static $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(STATIC_LDLIBS) $(STATIC_LIBHUGE) + obj32/xB.%: $(SCRIPTS32).xB $(HUGETLBFS_LD) obj32/%.o obj32/testutils.o @$(VECHO) LD32 "(xB test)" $@ @mkdir -p obj32 diff -ruNp libhugetlbfs-2.11/tests/run_tests.py libhugetlbfs-2.11-shm/tests/run_tests.py --- libhugetlbfs-2.11/tests/run_tests.py 2010-12-16 11:38:22.000000000 -0600 +++ libhugetlbfs-2.11-shm/tests/run_tests.py 2011-01-14 14:40:13.263279000 -0600 @@ -597,7 +597,11 @@ def functional_tests(): # Test overriding of shmget() do_shm_test("shmoverride_linked") + do_shm_test("shmoverride_linked", HUGETLB_SHM="yes") + do_shm_test("shmoverride_linked_static") + do_shm_test("shmoverride_linked_static", HUGETLB_SHM="yes") do_shm_test("shmoverride_unlinked", LD_PRELOAD="libhugetlbfs.so") + do_shm_test("shmoverride_unlinked", LD_PRELOAD="libhugetlbfs.so", HUGETLB_SHM="yes") # Test hugetlbfs filesystem quota accounting do_test("quota.sh") ------------------------------------------------------------------------------ Protect Your Site and Customers from Malware Attacks Learn about various malware tactics and how to avoid them. Understand malware threats, the impact they can have on your business, and how you can protect your company and customers by using code signing. http://p.sf.net/sfu/oracle-sfdevnl _______________________________________________ Libhugetlbfs-devel mailing list Libhugetlbfs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel