summaryrefslogtreecommitdiff
path: root/rts/sm
diff options
context:
space:
mode:
authorMoritz Angermann <moritz.angermann@gmail.com>2021-02-13 16:44:19 +0800
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-03-29 17:25:49 -0400
commite754ff7f178a629a2261cba77a29d9510391aebd (patch)
tree77aca9f315288b52efbc9d410a57300a4029279d /rts/sm
parent4421fb34b3a70db1323833337c94ac4364824124 (diff)
downloadhaskell-e754ff7f178a629a2261cba77a29d9510391aebd.tar.gz
Allocate Adjustors and mark them readable in two steps
This drops allocateExec for darwin, and replaces it with a alloc, write, mark executable strategy instead. This prevents us from trying to allocate an executable range and then write to it, which X^W will prohibit on darwin. This will *only* work if we can use mmap.
Diffstat (limited to 'rts/sm')
-rw-r--r--rts/sm/Storage.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
index dc0dd7fd01..37f32de0f5 100644
--- a/rts/sm/Storage.c
+++ b/rts/sm/Storage.c
@@ -11,6 +11,18 @@
*
* ---------------------------------------------------------------------------*/
+#include <ghcconfig.h>
+#if RTS_LINKER_USE_MMAP
+/*
+ * On FreeBSD and Darwin, when _XOPEN_SOURCE is defined, MAP_ANONYMOUS is not
+ * exposed from <sys/mman.h>. Include <sys/mman.h> before "PosixSource.h".
+ *
+ * Alternatively, we could drop "PosixSource.h" from this file, but for just
+ * one non-POSIX macro, that seems a needless price to pay.
+ */
+#include <sys/mman.h>
+#endif
+
#include "PosixSource.h"
#include "Rts.h"
@@ -34,6 +46,10 @@
#include "Hash.h"
#endif
+#if RTS_LINKER_USE_MMAP
+#include "LinkerInternals.h"
+#endif
+
#include <string.h>
#include "ffi.h"
@@ -1791,6 +1807,20 @@ void flushExec (W_ len, AdjustorExecutable exec_addr)
#endif
}
+#if RTS_LINKER_USE_MMAP
+AdjustorWritable allocateWrite(W_ bytes) {
+ return mmapForLinker(bytes, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
+}
+
+void markExec(W_ bytes, AdjustorWritable writ) {
+ mmapForLinkerMarkExecutable(writ, bytes);
+}
+
+void freeWrite(W_ bytes, AdjustorWritable writ) {
+ munmap(writ, bytes);
+}
+#endif
+
#if defined(linux_HOST_OS) || defined(netbsd_HOST_OS)
// On Linux we need to use libffi for allocating executable memory,
@@ -1820,7 +1850,7 @@ void freeExec (AdjustorExecutable addr)
RELEASE_SM_LOCK
}
-#elif (defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) && (defined(ios_HOST_OS) || defined(darwin_HOST_OS))
+#elif defined(darwin_HOST_OS)
static HashTable* allocatedExecs;
@@ -1828,6 +1858,11 @@ AdjustorWritable allocateExec(W_ bytes, AdjustorExecutable *exec_ret)
{
AdjustorWritable writ;
ffi_closure* cl;
+ // This check is necessary as we can't use allocateExec for anything *but*
+ // ffi_closures on ios/darwin on arm. libffi does some heavy lifting to
+ // get around the X^W restrictions, and we can't just use this codepath
+ // to allocate generic executable space. For those cases we have to refer
+ // back to allocateWrite/markExec/freeWrite (see above.)
if (bytes != sizeof(ffi_closure)) {
barf("allocateExec: for ffi_closure only");
}