Skip to content
Snippets Groups Projects
Commit 0926a3ca authored by sof's avatar sof
Browse files

[project @ 1999-01-18 14:35:20 by sof]

Fixed a couple of bad bugs in the implementation of 'foreign export ccall dynamic'.
parent 9eca3c26
No related merge requests found
...@@ -269,7 +269,7 @@ dsFExport i ty ext_name cconv isDyn = ...@@ -269,7 +269,7 @@ dsFExport i ty ext_name cconv isDyn =
Dynamic -> panic "dsFExport: Dynamic - shouldn't ever happen." Dynamic -> panic "dsFExport: Dynamic - shouldn't ever happen."
f_helper_glob = mkIdVisible mod uniq f_helper f_helper_glob = mkIdVisible mod uniq f_helper
(h_stub, c_stub) = fexportEntry c_nm f_helper_glob wrapper_arg_tys the_result_ty cconv (h_stub, c_stub) = fexportEntry c_nm f_helper_glob wrapper_arg_tys the_result_ty cconv isDyn
in in
returnDs (NonRec f_helper_glob the_body, h_stub, c_stub) returnDs (NonRec f_helper_glob the_body, h_stub, c_stub)
...@@ -430,8 +430,14 @@ The C stub constructs the application of the exported Haskell function ...@@ -430,8 +430,14 @@ The C stub constructs the application of the exported Haskell function
using the hugs/ghc rts invocation API. using the hugs/ghc rts invocation API.
\begin{code} \begin{code}
fexportEntry :: FAST_STRING -> Id -> [Type] -> Maybe Type -> CallConv -> (SDoc, SDoc) fexportEntry :: FAST_STRING
fexportEntry c_nm helper args res cc = (header_bits, c_bits) -> Id
-> [Type]
-> Maybe Type
-> CallConv
-> Bool
-> (SDoc, SDoc)
fexportEntry c_nm helper args res cc isDyn = (header_bits, c_bits)
where where
-- name of the (Haskell) helper function generated by the desugarer. -- name of the (Haskell) helper function generated by the desugarer.
h_nm = ppr helper <> text "_closure" h_nm = ppr helper <> text "_closure"
...@@ -439,7 +445,7 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits) ...@@ -439,7 +445,7 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits)
header_bits = ptext SLIT("extern") <+> fun_proto <> semi header_bits = ptext SLIT("extern") <+> fun_proto <> semi
fun_proto = cResType <+> pprCconv <+> ptext c_nm <> fun_proto = cResType <+> pprCconv <+> ptext c_nm <>
parens (hsep (punctuate comma (zipWith (<+>) cParamTypes c_args))) parens (hsep (punctuate comma (zipWith (<+>) cParamTypes proto_args)))
c_bits = c_bits =
externDecl $$ externDecl $$
...@@ -458,7 +464,7 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits) ...@@ -458,7 +464,7 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits)
appArg acc (a,c_a) = appArg acc (a,c_a) =
text "rts_apply" <> parens (acc <> comma <> mkHObj a <> parens c_a) text "rts_apply" <> parens (acc <> comma <> mkHObj a <> parens c_a)
cParamTypes = map showStgType args cParamTypes = map showStgType real_args
cResType = cResType =
case res of case res of
...@@ -487,7 +493,21 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits) ...@@ -487,7 +493,21 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits)
Nothing -> empty Nothing -> empty
Just t -> unpackHObj t <> parens (text "ret") Just t -> unpackHObj t <> parens (text "ret")
c_args = zipWith (\ _ n -> text ('a':show n)) args [0..] c_args = mkCArgNames 0 args
{-
If we're generating an entry point for a 'foreign export ccall dynamic',
then we receive the return address of the C function that wants to
invoke a Haskell function as any other C function, as second arg.
This arg is unused within the body of the generated C stub, but
needed by the Adjustor.c code to get the stack cleanup right.
-}
(proto_args, real_args)
| cc == cCallConv && isDyn = ( text "a0" : text "a_" : mkCArgNames 1 (tail args)
, head args : addrTy : tail args)
| otherwise = (mkCArgNames 0 args, args)
mkCArgNames n as = zipWith (\ _ n -> text ('a':show n)) as [n..]
mkHObj :: Type -> SDoc mkHObj :: Type -> SDoc
mkHObj t = text "rts_mk" <> showFFIType t mkHObj t = text "rts_mk" <> showFFIType t
......
...@@ -38,15 +38,15 @@ Haskell side. ...@@ -38,15 +38,15 @@ Haskell side.
*/ */
#include "Rts.h" #include "Rts.h"
#include "RtsUtils.h" #include "RtsUtils.h"
#include "RtsFlags.h"
/* Heavily arch-specific, I'm afraid.. */ /* Heavily arch-specific, I'm afraid.. */
#if defined(i386_TARGET_ARCH) #if defined(i386_TARGET_ARCH)
char* void*
createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr) createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
{ {
void *adjustor,*adj; void *adjustor;
unsigned char* adj_code; unsigned char* adj_code;
int i;
size_t sizeof_adjustor; size_t sizeof_adjustor;
if (cconv == 0) { /* the adjustor will be _stdcall'ed */ if (cconv == 0) { /* the adjustor will be _stdcall'ed */
...@@ -56,35 +56,33 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr) ...@@ -56,35 +56,33 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
(offset and machine code prefixed): (offset and machine code prefixed):
<0>: 58 popl %eax # temp. remove ret addr.. <0>: 58 popl %eax # temp. remove ret addr..
<1>: 68 63 fd fc fe fa pushl 0xfafefcfd # constant is large enough to <1>: 68 fd fc fe fa pushl 0xfafefcfd # constant is large enough to
# hold a StgStablePtr # hold a StgStablePtr
<6>: 50 pushl %eax # put back ret. addr <6>: 50 pushl %eax # put back ret. addr
<7>: b8 fa ef ff 00 movl $0x00ffeffa, %eax # load up wptr <7>: b8 fa ef ff 00 movl $0x00ffeffa, %eax # load up wptr
<c>: ff e0 jmp %eax # and jump to it. <c>: ff e0 jmp %eax # and jump to it.
# the callee cleans up the it will then clean up the stack # the callee cleans up the stack
*/ */
sizeof_adjustor = 15*sizeof(char); sizeof_adjustor = 14*sizeof(char);
if ((adjustor = stgMallocBytes(sizeof_adjustor,"createAdjustor")) == NULL) { if ((adjustor = stgMallocBytes(sizeof_adjustor,"createAdjustor")) == NULL) {
return NULL; return NULL;
} }
adj_code = (unsigned char*)adjustor; adj_code = (unsigned char*)adjustor;
adj_code[0] = (unsigned char)0x58; /* popl %eax */ adj_code[0x00] = (unsigned char)0x58; /* popl %eax */
adj_code[1] = (unsigned char)0x68; /* pushl hptr (which is a dword immediate ) */
adj = (StgStablePtr*)(adj_code+2); adj_code[0x01] = (unsigned char)0x68; /* pushl hptr (which is a dword immediate ) */
*((StgStablePtr*)adj) = (StgStablePtr)hptr; *((StgStablePtr*)(adj_code + 0x02)) = (StgStablePtr)hptr;
i = 2 + sizeof(StgStablePtr); adj_code[0x06] = (unsigned char)0x50; /* pushl %eax */
adj_code[i] = (unsigned char)0x50; /* pushl %eax */
adj_code[i+1] = (unsigned char)0xb8; /* movl $wptr, %eax */ adj_code[0x07] = (unsigned char)0xb8; /* movl $wptr, %eax */
adj = (char*)(adj_code+i+2); *((StgFunPtr*)(adj_code + 0x08)) = (StgFunPtr)wptr;
*((StgFunPtr*)adj) = (StgFunPtr)wptr;
adj_code[0x0c] = (unsigned char)0xff; /* jmp %eax */
adj_code[0x0d] = (unsigned char)0xe0;
i = i+2+sizeof(StgFunPtr);
adj_code[i] = (unsigned char)0xff; /* jmp %eax */
adj_code[i+1] = (unsigned char)0xe0;
} else { /* the adjustor will be _ccall'ed */ } else { /* the adjustor will be _ccall'ed */
...@@ -92,60 +90,68 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr) ...@@ -92,60 +90,68 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
the following assembly language snippet the following assembly language snippet
(offset and machine code prefixed): (offset and machine code prefixed):
<0>: 58 popl %eax # temp. remove ret addr.. <00>: 68 ef be ad de pushl $0xdeadbeef # constant is large enough to
<1>: 68 63 fd fc fe fa pushl 0xfafefcfd # constant is large enough to
# hold a StgStablePtr # hold a StgStablePtr
<6>: 50 pushl %eax # put back ret. addr <05>: b8 fa ef ff 00 movl $0x00ffeffa, %eax # load up wptr
<7>: b8 fa ef ff 00 movl $0x00ffeffa, %eax # load up wptr <0a>: ff d0 call %eax # and call it.
<c>: ff d0 call %eax # and call it. <0c>: 83 c4 04 addl $0x4,%esp # remove stable pointer.
<e>: 58 popl %eax # store away return address. <0f>: c3 ret # return to where you came from.
<f>: 83 c4 04 addl $0x4,%esp # remove stable pointer
<12>: 50 pushl %eax # put back return address. The ccall'ing version is a tad different, passing in the return
<13>: c3 ret # return to where you came from. address of the caller to the auto-generated C stub (which enters
via the stable pointer.) (The auto-generated C stub is on this
game, don't worry :-)
The adjustor makes the assumption that any return value
coming back from the C stub is not stored on the stack.
That's (thankfully) the case here with the restricted set of
return types that we support.
*/ */
sizeof_adjustor = 20*sizeof(char); sizeof_adjustor = 16*sizeof(char);
if ((adjustor = stgMallocBytes(sizeof_adjustor,"createAdjustor")) == NULL) { if ((adjustor = stgMallocBytes(sizeof_adjustor,"createAdjustor")) == NULL) {
return NULL; return NULL;
} }
adj_code = (unsigned char*)adjustor; adj_code = (unsigned char*)adjustor;
adj_code[0] = (unsigned char)0x58; /* popl %eax */
adj_code[1] = (unsigned char)0x68; /* pushl hptr (which is a dword immediate ) */ adj_code[0x00] = (unsigned char)0x68; /* pushl hptr (which is a dword immediate ) */
*((StgStablePtr*)(adj_code+0x01)) = (StgStablePtr)hptr;
adj = (StgStablePtr*)(adj_code+2);
*((StgStablePtr*)adj) = (StgStablePtr)hptr; adj_code[0x05] = (unsigned char)0xb8; /* movl $wptr, %eax */
*((StgFunPtr*)(adj_code + 0x06)) = (StgFunPtr)wptr;
i = 2 + sizeof(StgStablePtr);
adj_code[i] = (unsigned char)0x50; /* pushl %eax */ adj_code[0x0a] = (unsigned char)0xff; /* call %eax */
adj_code[i+1] = (unsigned char)0xb8; /* movl $wptr, %eax */ adj_code[0x0b] = (unsigned char)0xd0;
adj = (char*)(adj_code+i+2);
*((StgFunPtr*)adj) = (StgFunPtr)wptr; adj_code[0x0c] = (unsigned char)0x83; /* addl $0x4, %esp */
adj_code[0x0d] = (unsigned char)0xc4;
i = i+2+sizeof(StgFunPtr); adj_code[0x0e] = (unsigned char)0x04;
adj_code[i] = (unsigned char)0xff; /* call %eax */
adj_code[i+1] = (unsigned char)0xd0; adj_code[0x0f] = (unsigned char)0xc3; /* ret */
adj_code[i+2] = (unsigned char)0x58; /* popl %eax */
adj_code[i+3] = (unsigned char)0x83; /* addl $0x4, %esp */
adj_code[i+4] = (unsigned char)0xc4;
adj_code[i+5] = (unsigned char)0x04;
adj_code[i+6] = (unsigned char)0x50; /* pushl %eax */
adj_code[i+7] = (unsigned char)0xc3; /* ret */
} }
/* Have fun! */ /* Have fun! */
return (adjustor); return ((void*)adjustor);
} }
void void
freeHaskellFunctionPtr(void* ptr) freeHaskellFunctionPtr(void* ptr)
{ {
char* tmp; if ( *(unsigned char*)ptr != 0x68 &&
*(unsigned char*)ptr != 0x58 ) {
fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
return;
}
/* Free the stable pointer first..*/ /* Free the stable pointer first..*/
tmp=(char*)ptr+2; if (*(unsigned char*)ptr == 0x68) { /* Aha, a ccall adjustor! */
freeStablePointer(*((StgStablePtr*)tmp)); freeStablePointer(*((StgStablePtr*)((unsigned char*)ptr + 0x01)));
} else {
freeStablePointer(*((StgStablePtr*)((unsigned char*)ptr + 0x02)));
}
*((unsigned char*)ptr) = '\0';
free(ptr); free(ptr);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment