$OpenBSD: patch-ghc_rts_Adjustor_c,v 1.3 2003/09/01 20:32:14 espie Exp $
Ok. This is the magical "adjustor thunk". The entry point into
Haskell land from C land. Problem is that it (1) uses dynamically
generated code stored on the heap, as well as (2) a nasty little hack
that invovles exec'ing some code in .data. 

Solved (1) by using a StablePtr, avoiding malloc memory
altogether for the adjustor thunk itself.

Solved (2) by writing an assembly function to do the code they
were too lazy to put into a .s file in the first place. See
obscure_ccall.s

--- ghc/rts/Adjustor.c.orig	Wed Mar 26 04:58:47 2003
+++ ghc/rts/Adjustor.c	Thu Jul 10 21:25:30 2003
@@ -65,10 +65,10 @@
    For this to work we make the assumption that bytes in .data
    are considered executable.
 */
-static unsigned char __obscure_ccall_ret_code [] = 
-  { 0x83, 0xc4, 0x04 /* addl $0x4, %esp */
-  , 0xc3             /* ret */
-  };
+
+/* from obscure_ccall.s */
+extern void __obscure_ccall_ret_code(void);
+
 #endif
 
 #if defined(alpha_TARGET_ARCH)
@@ -77,13 +77,14 @@
 #endif
 
 #if defined(ia64_TARGET_ARCH)
-#include "Storage.h"
-
 /* Layout of a function descriptor */
 typedef struct _IA64FunDesc {
     StgWord64 ip;
     StgWord64 gp;
 } IA64FunDesc;
+#endif
+
+#include "Storage.h"
 
 static void *
 stgAllocStable(size_t size_in_bytes, StgStablePtr *stable)
@@ -105,7 +106,6 @@
   /* and return a ptr to the goods inside the array */
   return(BYTE_ARR_CTS(arr));
 }
-#endif
 
 void*
 createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
@@ -128,20 +128,22 @@
      <c>: 	ff e0             jmp    %eax        	   # and jump to it.
 		# the callee cleans up the stack
     */
-    if ((adjustor = stgMallocBytes(14, "createAdjustor")) != NULL) {
-	unsigned char *const adj_code = (unsigned char *)adjustor;
-	adj_code[0x00] = (unsigned char)0x58;  /* popl %eax  */
-
-	adj_code[0x01] = (unsigned char)0x68;  /* pushl hptr (which is a dword immediate ) */
-	*((StgStablePtr*)(adj_code + 0x02)) = (StgStablePtr)hptr;
-
-	adj_code[0x06] = (unsigned char)0x50; /* pushl %eax */
+    {
+        StgStablePtr stable;
+        unsigned char *const adj_code;
 
-	adj_code[0x07] = (unsigned char)0xb8; /* movl  $wptr, %eax */
-	*((StgFunPtr*)(adj_code + 0x08)) = (StgFunPtr)wptr;
+        adjustor = stgAllocStable(18,&stable);
+	adj_code = (unsigned char *)adjustor;
 
-	adj_code[0x0c] = (unsigned char)0xff; /* jmp %eax */
-	adj_code[0x0d] = (unsigned char)0xe0;
+	adj_code[0] = (unsigned char)0x58;  /* popl %eax  */
+	adj_code[1] = (unsigned char)0x68;  /* pushl hptr (which is a dword immediate ) */
+	*((StgStablePtr*)(adj_code+2)) = (StgStablePtr)hptr;
+	adj_code[6] = (unsigned char)0x50; /* pushl %eax */
+	adj_code[7] = (unsigned char)0xb8; /* movl  $wptr, %eax */
+	*((StgFunPtr*)(adj_code+8)) = (StgFunPtr)wptr;
+	adj_code[12] = (unsigned char)0xff; /* jmp %eax */
+	adj_code[13] = (unsigned char)0xe0;
+	*((StgStablePtr*)(adj_code+14)) = (StgStablePtr)stable;
     }
 #endif
     break;
@@ -172,20 +174,22 @@
     That's (thankfully) the case here with the restricted set of 
     return types that we support.
   */
-    if ((adjustor = stgMallocBytes(17, "createAdjustor")) != NULL) {
-	unsigned char *const adj_code = (unsigned char *)adjustor;
-
-	adj_code[0x00] = (unsigned char)0x68;  /* pushl hptr (which is a dword immediate ) */
-	*((StgStablePtr*)(adj_code+0x01)) = (StgStablePtr)hptr;
-
-	adj_code[0x05] = (unsigned char)0xb8;  /* movl  $wptr, %eax */
-	*((StgFunPtr*)(adj_code + 0x06)) = (StgFunPtr)wptr;
-
-	adj_code[0x0a] = (unsigned char)0x68;  /* pushl __obscure_ccall_ret_code */
-	*((StgFunPtr*)(adj_code + 0x0b)) = (StgFunPtr)__obscure_ccall_ret_code;
-
-	adj_code[0x0f] = (unsigned char)0xff; /* jmp *%eax */
-	adj_code[0x10] = (unsigned char)0xe0; 
+   { 
+        StgStablePtr stable;
+        unsigned char *const adj_code;
+
+        adjustor = stgAllocStable(21, &stable);
+	adj_code = (unsigned char *)adjustor;
+
+	adj_code[0] = (unsigned char)0x68;  /* pushl hptr (which is a dword immediate ) */
+	*((StgStablePtr*)(adj_code+1)) = (StgStablePtr)hptr;
+	adj_code[5] = (unsigned char)0xb8;  /* movl  $wptr, %eax */
+	*((StgFunPtr*)(adj_code+6)) = (StgFunPtr)wptr;
+	adj_code[10] = (unsigned char)0x68;  /* pushl __obscure_ccall_ret_code */
+	*((StgFunPtr*)(adj_code+11)) = (StgFunPtr)__obscure_ccall_ret_code;
+	adj_code[15] = (unsigned char)0xff; /* jmp *%eax */
+	adj_code[16] = (unsigned char)0xe0; 
+	*((StgStablePtr*)(adj_code+17)) = (StgStablePtr)stable;
     }
 #elif defined(sparc_TARGET_ARCH)
   /* Magic constant computed by inspecting the code length of the following
@@ -476,12 +480,16 @@
    return;
  }
 
- /* Free the stable pointer first..*/
+ /* Free the internal stable pointer first..*/
  if (*(unsigned char*)ptr == 0x68) { /* Aha, a ccall adjustor! */
-    freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 0x01)));
+    freeStablePtr( *((StgStablePtr*)((unsigned char*)ptr +  1)) );
+    freeStablePtr( *((StgStablePtr*)((unsigned char*)ptr + 17)) );
  } else {
-    freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 0x02)));
+    freeStablePtr( *((StgStablePtr*)((unsigned char*)ptr +  2)) );
+    freeStablePtr( *((StgStablePtr*)((unsigned char*)ptr + 14)) );
  }    
+ return;
+
 #elif defined(sparc_TARGET_ARCH)
  if ( *(unsigned long*)ptr != 0x9C23A008UL ) {
    fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
