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 /rts | |
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
Diffstat (limited to 'rts')
-rw-r--r-- | rts/Linker.c | 34 |
1 files changed, 31 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); |