diff options
author | Simon Marlow <marlowsd@gmail.com> | 2008-09-19 13:46:02 +0000 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2008-09-19 13:46:02 +0000 |
commit | c3062251034f54944061e816ed018b0b2db1b849 (patch) | |
tree | 13376f17332ac575f637489ed9f6910b9d071225 /rts/sm | |
parent | 8f52645bd99ee3e636a34826c0cbfc5939920da1 (diff) | |
download | haskell-c3062251034f54944061e816ed018b0b2db1b849.tar.gz |
On Linux use libffi for allocating executable memory (fixed #738)
Diffstat (limited to 'rts/sm')
-rw-r--r-- | rts/sm/Storage.c | 41 |
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 |