aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Popov <arrowd@FreeBSD.org>2021-12-29 09:12:27 +0000
committerGleb Popov <arrowd@FreeBSD.org>2022-07-07 10:24:10 +0000
commitbe5f5db250995bdf3b4fa02b0ea958a0cf838f66 (patch)
tree395d60606bb3e8852b441e022eb83f4d48c32d45
parent2d7aef8d9ce1280eae5c445d1b06ba68b5997487 (diff)
downloadports-be5f5db250995bdf3b4fa02b0ea958a0cf838f66.tar.gz
ports-be5f5db250995bdf3b4fa02b0ea958a0cf838f66.zip
lang/ghc: Add RTS linker patch for the external interpreter.
-rw-r--r--lang/ghc/files/patch-rts-linker87
1 files changed, 87 insertions, 0 deletions
diff --git a/lang/ghc/files/patch-rts-linker b/lang/ghc/files/patch-rts-linker
new file mode 100644
index 000000000000..feb736f72176
--- /dev/null
+++ b/lang/ghc/files/patch-rts-linker
@@ -0,0 +1,87 @@
+diff --git a/rts/Linker.c b/rts/Linker.c
+index 72533ae52af48184fb76171fb93a73c04d025f2f..09cf5fa0593743f9b9f44603e2290cea9132ed89 100644
+--- rts/Linker.c
++++ rts/Linker.c
+@@ -78,6 +78,33 @@
+ #if defined(dragonfly_HOST_OS)
+ #include <sys/tls.h>
+ #endif
++
++/*
++ * Note [iconv and FreeBSD]
++ * ~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * On FreeBSD libc.so provides an implementation of the iconv_* family of
++ * functions. However, due to their implementation, these symbols cannot be
++ * resolved via dlsym(); rather, they can only be resolved using the
++ * explicitly-versioned dlvsym().
++ *
++ * This is problematic for the RTS linker since we may be asked to load
++ * an object that depends upon iconv. To handle this we include a set of
++ * fallback cases for these functions, allowing us to resolve them to the
++ * symbols provided by the libc against which the RTS is linked.
++ *
++ * See #20354.
++ */
++
++#if defined(freebsd_HOST_OS)
++extern void iconvctl();
++extern void iconv_open_into();
++extern void iconv_open();
++extern void iconv_close();
++extern void iconv_canonicalize();
++extern void iconv();
++#endif
++
+ /*
+ Note [runtime-linker-support]
+ -----------------------------
+@@ -655,6 +682,10 @@ internal_dlsym(const char *symbol) {
+ }
+ RELEASE_LOCK(&dl_mutex);
+
++ IF_DEBUG(linker, debugBelch("internal_dlsym: looking for symbol '%s' in special cases\n", symbol));
++# define SPECIAL_SYMBOL(sym) \
++ if (strcmp(symbol, #sym) == 0) return (void*)&sym;
++
+ # 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
+@@ -664,18 +695,28 @@ internal_dlsym(const char *symbol) {
+ // 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));
++ SPECIAL_SYMBOL(stat);
++ SPECIAL_SYMBOL(fstat);
++ SPECIAL_SYMBOL(lstat);
++ SPECIAL_SYMBOL(stat64);
++ SPECIAL_SYMBOL(fstat64);
++ SPECIAL_SYMBOL(lstat64);
++ SPECIAL_SYMBOL(atexit);
++ SPECIAL_SYMBOL(mknod);
++# endif
+
+- 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;
++ // See Note [iconv and FreeBSD]
++# if defined(freebsd_HOST_OS)
++ SPECIAL_SYMBOL(iconvctl);
++ SPECIAL_SYMBOL(iconv_open_into);
++ SPECIAL_SYMBOL(iconv_open);
++ SPECIAL_SYMBOL(iconv_close);
++ SPECIAL_SYMBOL(iconv_canonicalize);
++ SPECIAL_SYMBOL(iconv);
+ # endif
+
++#undef SPECIAL_SYMBOL
++
+ // we failed to find the symbol
+ return NULL;
+ }