diff options
author | Adam Sandberg Ericsson <adam@sandbergericsson.se> | 2020-07-01 14:44:12 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-07-07 13:56:05 -0400 |
commit | 0effc57d48ace6b719a9f4cbeac67c95ad55010b (patch) | |
tree | 7ea0f0c0052ec6c3c4c30dba5343d2530e30b0b3 | |
parent | c59faf67fec83c98ffd1b65f1be0775b34f36595 (diff) | |
download | haskell-0effc57d48ace6b719a9f4cbeac67c95ad55010b.tar.gz |
rts linker: teach the linker about GLIBC's special handling of *stat, mknod and atexit functions #7072
-rw-r--r-- | rts/Linker.c | 34 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/Makefile | 7 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/T7072-main.c | 39 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/T7072-obj.c | 17 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/T7072.stderr | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/all.T | 7 |
6 files changed, 102 insertions, 3 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index 3e8847d8fc..443de6a356 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -637,23 +637,51 @@ internal_dlsym(const char *symbol) { // We acquire dl_mutex as concurrent dl* calls may alter dlerror ACQUIRE_LOCK(&dl_mutex); + + // clears dlerror dlerror(); + // look in program first v = dlsym(dl_prog_handle, symbol); if (dlerror() == NULL) { RELEASE_LOCK(&dl_mutex); + IF_DEBUG(linker, debugBelch("internal_dlsym: found symbol '%s' in program\n", symbol)); return v; } for (o_so = openedSOs; o_so != NULL; o_so = o_so->next) { v = dlsym(o_so->handle, symbol); if (dlerror() == NULL) { + IF_DEBUG(linker, debugBelch("internal_dlsym: found symbol '%s' in shared object\n", symbol)); RELEASE_LOCK(&dl_mutex); return v; } } RELEASE_LOCK(&dl_mutex); - return v; + +# if defined(HAVE_SYS_STAT_H) && defined(linux_HOST_OS) && defined(__GLIBC__) + // HACK: GLIBC implements these functions with a great deal of trickery where + // they are either inlined at compile time to their corresponding + // __xxxx(SYS_VER, ...) function or direct syscalls, or resolved at + // link time via libc_nonshared.a. + // + // We borrow the approach that the LLVM JIT uses to resolve these + // symbols. See http://llvm.org/PR274 and #7072 for more info. + + IF_DEBUG(linker, debugBelch("internal_dlsym: looking for symbol '%s' in GLIBC special cases\n", symbol)); + + if (strcmp(symbol, "stat") == 0) return (void*)&stat; + if (strcmp(symbol, "fstat") == 0) return (void*)&fstat; + if (strcmp(symbol, "lstat") == 0) return (void*)&lstat; + if (strcmp(symbol, "stat64") == 0) return (void*)&stat64; + if (strcmp(symbol, "fstat64") == 0) return (void*)&fstat64; + if (strcmp(symbol, "lstat64") == 0) return (void*)&lstat64; + if (strcmp(symbol, "atexit") == 0) return (void*)&atexit; + if (strcmp(symbol, "mknod") == 0) return (void*)&mknod; +# endif + + // we failed to find the symbol + return NULL; } # endif @@ -829,13 +857,13 @@ SymbolAddr* lookupSymbol_ (SymbolName* lbl) SymbolAddr* lookupSymbol_ (SymbolName* lbl) { - IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s\n", lbl)); + IF_DEBUG(linker, debugBelch("lookupSymbol: looking up '%s'\n", lbl)); ASSERT(symhash != NULL); RtsSymbolInfo *pinfo; if (!ghciLookupSymbolInfo(symhash, lbl, &pinfo)) { - IF_DEBUG(linker, debugBelch("lookupSymbol: symbol not found\n")); + IF_DEBUG(linker, debugBelch("lookupSymbol: symbol '%s' not found, trying dlsym\n", lbl)); # if defined(OBJFORMAT_ELF) return internal_dlsym(lbl); diff --git a/testsuite/tests/rts/linker/Makefile b/testsuite/tests/rts/linker/Makefile index de4c19b0ce..738e5ef6a3 100644 --- a/testsuite/tests/rts/linker/Makefile +++ b/testsuite/tests/rts/linker/Makefile @@ -96,3 +96,10 @@ linker_error3: "$(TEST_HC)" -c linker_error3.c -o linker_error3_o.o "$(TEST_HC)" linker_error3.o -o linker_error3 -no-hs-main -optc-g -debug -threaded ./linker_error3 linker_error3_o.o + +.PHONY: T7072 +T7072: + "$(TEST_HC)" -c T7072-obj.c -o T7072-obj.o + "$(TEST_HC)" -c T7072-main.c -o T7072-main.o + "$(TEST_HC)" T7072-main.c -o T7072-main -no-hs-main -debug + ./T7072-main T7072-obj.o diff --git a/testsuite/tests/rts/linker/T7072-main.c b/testsuite/tests/rts/linker/T7072-main.c new file mode 100644 index 0000000000..36760de16c --- /dev/null +++ b/testsuite/tests/rts/linker/T7072-main.c @@ -0,0 +1,39 @@ +#include "ghcconfig.h" +#include "Rts.h" +#include <stdio.h> +#include <stdlib.h> + +int main (int argc, char *argv[]) +{ + int r; + char *obj; + + hs_init(&argc, &argv); + + initLinker_(0); + + // Load object file argv[1] repeatedly + + if (argc != 2) { + errorBelch("usage: T7072-main <object-file>"); + exit(1); + } + + obj = argv[1]; + + r = loadObj(obj); + if (!r) { + debugBelch("loadObj(%s) failed\n", obj); + exit(1); + } + r = resolveObjs(); + if (!r) { + debugBelch("resolveObjs failed\n"); + unloadObj(obj); + exit(1); + } + debugBelch("loading succeeded"); + + hs_exit(); + return 0; +} diff --git a/testsuite/tests/rts/linker/T7072-obj.c b/testsuite/tests/rts/linker/T7072-obj.c new file mode 100644 index 0000000000..d0b6af5738 --- /dev/null +++ b/testsuite/tests/rts/linker/T7072-obj.c @@ -0,0 +1,17 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> + +typedef int stat_func(const char*, struct stat*); + +stat_func *foo = &stat; + +void stat_test(void) +{ + struct stat buf; + + printf("About to stat-test.c\n"); + foo("stat-test.c", &buf); + printf("Done\n"); +} diff --git a/testsuite/tests/rts/linker/T7072.stderr b/testsuite/tests/rts/linker/T7072.stderr new file mode 100644 index 0000000000..dfd9cfbe46 --- /dev/null +++ b/testsuite/tests/rts/linker/T7072.stderr @@ -0,0 +1 @@ +loading succeeded
\ No newline at end of file diff --git a/testsuite/tests/rts/linker/all.T b/testsuite/tests/rts/linker/all.T index ba4837fc23..5789c860c7 100644 --- a/testsuite/tests/rts/linker/all.T +++ b/testsuite/tests/rts/linker/all.T @@ -102,3 +102,10 @@ test('rdynamic', [ unless(opsys('linux') or opsys('mingw32'), skip) , omit_ways(['ghci']) ], compile_and_run, ['-rdynamic -package ghc']) + + +test('T7072', + [extra_files(['T7072-main.c', 'T7072-obj.c']), + unless(opsys('linux'), skip), + req_rts_linker], + makefile_test, ['T7072']) |