Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
jberryman
GHC
Commits
c3062251
Commit
c3062251
authored
Sep 19, 2008
by
Simon Marlow
Browse files
On Linux use libffi for allocating executable memory (fixed #738)
parent
8f52645b
Changes
6
Hide whitespace changes
Inline
Side-by-side
compiler/ghci/ByteCodeFFI.lhs
View file @
c3062251
...
...
@@ -28,14 +28,16 @@ moan64 msg pp_rep
newExec :: Storable a => [a] -> IO (FunPtr ())
newExec code
= do ptr <- _allocateExec (fromIntegral $ codeSize undefined code)
= alloca $ \pcode -> do
ptr <- _allocateExec (fromIntegral $ codeSize undefined code) pcode
pokeArray ptr code
return (castPtrToFunPtr ptr)
code <- peek pcode
return (castPtrToFunPtr code)
where
codeSize :: Storable a => a -> [a] -> Int
codeSize dummy array = sizeOf(dummy) * length array
foreign import ccall unsafe "allocateExec"
_allocateExec :: CUInt -> IO (Ptr a)
_allocateExec :: CUInt ->
Ptr (Ptr a) ->
IO (Ptr a)
\end{code}
includes/RtsExternal.h
View file @
c3062251
...
...
@@ -111,7 +111,7 @@ void sendIOManagerEvent (HsWord32 event);
extern
void
setIOManagerPipe
(
int
fd
);
#endif
extern
void
*
allocateExec
(
unsigned
int
len
);
extern
void
*
allocateExec
(
unsigned
int
len
,
void
**
exec_addr
);
// Breakpoint stuff
...
...
includes/Storage.h
View file @
c3062251
...
...
@@ -204,7 +204,7 @@ doYouWantToGC( void )
}
/* memory allocator for executable memory */
extern
void
*
allocateExec
(
nat
bytes
);
extern
void
*
allocateExec
(
unsigned
int
len
,
void
**
exec_addr
);
extern
void
freeExec
(
void
*
p
);
/* for splitting blocks groups in two */
...
...
rts/Adjustor.c
View file @
c3062251
...
...
@@ -90,6 +90,7 @@ createAdjustor (int cconv,
ffi_type
*
result_type
;
ffi_closure
*
cl
;
int
r
,
abi
;
void
*
code
;
n_args
=
strlen
(
typeString
)
-
1
;
cif
=
stgMallocBytes
(
sizeof
(
ffi_cif
),
"createAdjustor"
);
...
...
@@ -115,13 +116,15 @@ createAdjustor (int cconv,
r
=
ffi_prep_cif
(
cif
,
abi
,
n_args
,
result_type
,
arg_types
);
if
(
r
!=
FFI_OK
)
barf
(
"ffi_prep_cif failed: %d"
,
r
);
// ToDo: use ffi_closure_alloc()
cl
=
allocateExec
(
sizeof
(
ffi_closure
));
cl
=
allocateExec
(
sizeof
(
ffi_closure
),
&
code
);
if
(
cl
==
NULL
)
{
barf
(
"createAdjustor: failed to allocate memory"
);
}
r
=
ffi_prep_closure
(
cl
,
cif
,
(
void
*
)
wptr
,
hptr
/*userdata*/
);
if
(
r
!=
FFI_OK
)
barf
(
"ffi_prep_closure failed: %d"
,
r
);
return
(
void
*
)
c
l
;
return
(
void
*
)
c
ode
;
}
#else // To end of file...
...
...
@@ -329,6 +332,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
)
{
void
*
adjustor
=
NULL
;
void
*
code
;
switch
(
cconv
)
{
...
...
@@ -346,7 +350,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
<c>: ff e0 jmp %eax # and jump to it.
# the callee cleans up the stack
*/
adjustor
=
allocateExec
(
14
);
adjustor
=
allocateExec
(
14
,
&
code
);
{
unsigned
char
*
const
adj_code
=
(
unsigned
char
*
)
adjustor
;
adj_code
[
0x00
]
=
(
unsigned
char
)
0x58
;
/* popl %eax */
...
...
@@ -391,7 +395,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
That's (thankfully) the case here with the restricted set of
return types that we support.
*/
adjustor
=
allocateExec
(
17
);
adjustor
=
allocateExec
(
17
,
&
code
);
{
unsigned
char
*
const
adj_code
=
(
unsigned
char
*
)
adjustor
;
...
...
@@ -416,7 +420,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
We offload most of the work to AdjustorAsm.S.
*/
AdjustorStub
*
adjustorStub
=
allocateExec
(
sizeof
(
AdjustorStub
));
AdjustorStub
*
adjustorStub
=
allocateExec
(
sizeof
(
AdjustorStub
)
,
&
code
);
adjustor
=
adjustorStub
;
extern
void
adjustorCode
(
void
);
...
...
@@ -514,7 +518,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
}
if
(
i
<
6
)
{
adjustor
=
allocateExec
(
0x30
);
adjustor
=
allocateExec
(
0x30
,
&
code
);
*
(
StgInt32
*
)
adjustor
=
0x49c1894d
;
*
(
StgInt32
*
)(
adjustor
+
0x4
)
=
0x8948c889
;
...
...
@@ -528,7 +532,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
}
else
{
adjustor
=
allocateExec
(
0x40
);
adjustor
=
allocateExec
(
0x40
,
&
code
);
*
(
StgInt32
*
)
adjustor
=
0x35ff5141
;
*
(
StgInt32
*
)(
adjustor
+
0x4
)
=
0x00000020
;
...
...
@@ -575,7 +579,7 @@ createAdjustor(int cconv, StgStablePtr hptr,
similarly, and local variables should be accessed via %fp, not %sp. In a
nutshell: This should work! (Famous last words! :-)
*/
adjustor
=
allocateExec
(
4
*
(
11
+
1
));
adjustor
=
allocateExec
(
4
*
(
11
+
1
)
,
&
code
);
{
unsigned
long
*
const
adj_code
=
(
unsigned
long
*
)
adjustor
;
...
...
@@ -652,7 +656,7 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for
4 bytes (getting rid of the nop), hence saving memory. [ccshan]
*/
ASSERT
(((
StgWord64
)
wptr
&
3
)
==
0
);
adjustor
=
allocateExec
(
48
);
adjustor
=
allocateExec
(
48
,
&
code
);
{
StgWord64
*
const
code
=
(
StgWord64
*
)
adjustor
;
...
...
@@ -757,7 +761,7 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for
*/
// allocate space for at most 4 insns per parameter
// plus 14 more instructions.
adjustor
=
allocateExec
(
4
*
(
4
*
n
+
14
));
adjustor
=
allocateExec
(
4
*
(
4
*
n
+
14
)
,
&
code
);
code
=
(
unsigned
*
)
adjustor
;
*
code
++
=
0x48000008
;
// b *+8
...
...
@@ -916,7 +920,7 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for
#ifdef FUNDESCS
adjustorStub
=
stgMallocBytes
(
sizeof
(
AdjustorStub
),
"createAdjustor"
);
#else
adjustorStub
=
allocateExec
(
sizeof
(
AdjustorStub
));
adjustorStub
=
allocateExec
(
sizeof
(
AdjustorStub
)
,
&
code
);
#endif
adjustor
=
adjustorStub
;
...
...
@@ -1089,7 +1093,7 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for
}
/* Have fun! */
return
adjustor
;
return
code
;
}
...
...
@@ -1167,7 +1171,8 @@ if ( *(unsigned char*)ptr != 0xe8 ) {
#else
ASSERT
(
0
);
#endif
*
((
unsigned
char
*
)
ptr
)
=
'\0'
;
// Can't write to this memory, it is only executable:
// *((unsigned char*)ptr) = '\0';
freeExec
(
ptr
);
}
...
...
rts/Makefile
View file @
c3062251
...
...
@@ -208,6 +208,7 @@ RtsUtils_CC_OPTS += -DGhcEnableTablesNextToCode=$(DQ)$(GhcEnableTablesNextToCode
# ffi.h triggers prototype warnings, so disable them here:
Interpreter_CC_OPTS
+=
-Wno-strict-prototypes
Adjustor_CC_OPTS
+=
-Wno-strict-prototypes
sm/
Storage_CC_OPTS
+=
-Wno-strict-prototypes
StgCRun_CC_OPTS
+=
-w
Typeable_CC_OPTS
+=
-w
...
...
rts/sm/Storage.c
View file @
c3062251
...
...
@@ -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
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment