summaryrefslogtreecommitdiff
path: root/rts/sm
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2008-09-19 13:46:02 +0000
committerSimon Marlow <marlowsd@gmail.com>2008-09-19 13:46:02 +0000
commitc3062251034f54944061e816ed018b0b2db1b849 (patch)
tree13376f17332ac575f637489ed9f6910b9d071225 /rts/sm
parent8f52645bd99ee3e636a34826c0cbfc5939920da1 (diff)
downloadhaskell-c3062251034f54944061e816ed018b0b2db1b849.tar.gz
On Linux use libffi for allocating executable memory (fixed #738)
Diffstat (limited to 'rts/sm')
-rw-r--r--rts/sm/Storage.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
index e10304c5a1..c9c9c1fc01 100644
--- a/rts/sm/Storage.c
+++ b/rts/sm/Storage.c
@@ -35,6 +35,8 @@
#include <stdlib.h>
#include <string.h>
+#include "ffi.h"
+
/*
* All these globals require sm_mutex to access in THREADED_RTS mode.
*/
@@ -46,6 +48,8 @@ bdescr *pinned_object_block; /* allocate pinned objects into this block */
nat alloc_blocks; /* number of allocate()d blocks since GC */
nat alloc_blocks_lim; /* approximate limit on alloc_blocks */
+static bdescr *exec_block;
+
generation *generations = NULL; /* all the generations */
generation *g0 = NULL; /* generation 0, for convenience */
generation *oldest_gen = NULL; /* oldest generation, for convenience */
@@ -261,6 +265,8 @@ initStorage( void )
alloc_blocks = 0;
alloc_blocks_lim = RtsFlags.GcFlags.minAllocAreaSize;
+ exec_block = NULL;
+
/* Tell GNU multi-precision pkg about our custom alloc functions */
mp_set_memory_functions(stgAllocForGMP, stgReallocForGMP, stgDeallocForGMP);
@@ -1134,9 +1140,37 @@ calcNeeded(void)
should be modified to use allocateExec instead of VirtualAlloc.
------------------------------------------------------------------------- */
-static bdescr *exec_block;
+#if defined(linux_HOST_OS)
+
+// On Linux we need to use libffi for allocating executable memory,
+// because it knows how to work around the restrictions put in place
+// by SELinux.
+
+void *allocateExec (nat bytes, void **exec_ret)
+{
+ void **ret, **exec;
+ ACQUIRE_SM_LOCK;
+ ret = ffi_closure_alloc (sizeof(void *) + (size_t)bytes, (void**)&exec);
+ RELEASE_SM_LOCK;
+ if (ret == NULL) return ret;
+ *ret = ret; // save the address of the writable mapping, for freeExec().
+ *exec_ret = exec + 1;
+ return (ret + 1);
+}
+
+// freeExec gets passed the executable address, not the writable address.
+void freeExec (void *addr)
+{
+ void *writable;
+ writable = *((void**)addr - 1);
+ ACQUIRE_SM_LOCK;
+ ffi_closure_free (writable);
+ RELEASE_SM_LOCK
+}
-void *allocateExec (nat bytes)
+#else
+
+void *allocateExec (nat bytes, void **exec_ret)
{
void *ret;
nat n;
@@ -1172,6 +1206,7 @@ void *allocateExec (nat bytes)
exec_block->free += n + 1;
RELEASE_SM_LOCK
+ *exec_ret = ret;
return ret;
}
@@ -1209,6 +1244,8 @@ void freeExec (void *addr)
RELEASE_SM_LOCK
}
+#endif /* mingw32_HOST_OS */
+
/* -----------------------------------------------------------------------------
Debugging