[project @ 2004-08-21 12:49:14 by panne]
[ghc-hetmet.git] / ghc / rts / Adjustor.c
index ed3cb50..bf9e02b 100644 (file)
@@ -38,13 +38,58 @@ Haskell side.
 */
 #include "PosixSource.h"
 #include "Rts.h"
+#include "RtsExternal.h"
 #include "RtsUtils.h"
-#include "RtsFlags.h"
-
 #include <stdlib.h>
 
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
 /* Heavily arch-specific, I'm afraid.. */
 
+typedef enum { 
+    pageExecuteRead, 
+    pageExecuteReadWrite 
+} pageMode;
+
+/*
+ * Function: execPage()
+ *
+ * Set the executable bit on page containing addr.
+ *
+ * TODO: Can the code span more than one page? If yes, we need to make two
+ * pages executable!
+ */
+static rtsBool
+execPage (void* addr, pageMode mode)
+{
+#if defined(i386_TARGET_ARCH) && defined(_WIN32) && 0
+    SYSTEM_INFO sInfo;
+    DWORD dwOldProtect = 0;
+
+    /* doesn't return a result, so presumably it can't fail... */
+    GetSystemInfo(&sInfo);
+    
+    if ( VirtualProtect ( (void*)((unsigned long)addr & (sInfo.dwPageSize - 1)),
+                         sInfo.dwPageSize,
+                         ( mode == pageExecuteReadWrite ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ),
+                         &dwOldProtect) == 0 ) {
+# if 1
+       DWORD rc = GetLastError();
+       prog_belch("execPage: failed to protect 0x%p; error=%lu; old protection: %lu\n", addr, rc, dwOldProtect);
+# endif
+       return rtsFalse;
+    }
+    return rtsTrue;
+#else
+    (void)addr;   (void)mode;   /* keep gcc -Wall happy */
+    return rtsTrue;
+#endif
+}
+
+
+static unsigned char __obscure_ccall_ret_code [] = 
 #if defined(i386_TARGET_ARCH)
 /* Now here's something obscure for you:
 
@@ -65,15 +110,21 @@ Haskell side.
    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 */
   };
+#else
+/* No such mind-twisters on non-Intel platforms */
+  { };
 #endif
 
 #if defined(alpha_TARGET_ARCH)
 /* To get the definition of PAL_imb: */
-#include <machine/pal.h>
+# if defined(linux_TARGET_OS)
+#  include <asm/pal.h>
+# else
+#  include <machine/pal.h>
+# endif
 #endif
 
 #if defined(ia64_TARGET_ARCH)
@@ -142,6 +193,8 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
 
        adj_code[0x0c] = (unsigned char)0xff; /* jmp %eax */
        adj_code[0x0d] = (unsigned char)0xe0;
+       
+       execPage(adjustor, pageExecuteReadWrite);
     }
 #endif
     break;
@@ -186,6 +239,8 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
 
        adj_code[0x0f] = (unsigned char)0xff; /* jmp *%eax */
        adj_code[0x10] = (unsigned char)0xe0; 
+
+       execPage(adjustor, pageExecuteReadWrite);
     }
 #elif defined(sparc_TARGET_ARCH)
   /* Magic constant computed by inspecting the code length of the following
@@ -366,7 +421,7 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for
                        while(n--)
                        {
                                __asm__ volatile ("dcbf 0,%0\n\tsync\n\ticbi 0,%0"
-                                                   : : "g" (p));
+                                                   : : "r" (p));
                                p++;
                        }
                        __asm__ volatile ("sync\n\tisync");
@@ -472,7 +527,7 @@ freeHaskellFunctionPtr(void* ptr)
 #if defined(i386_TARGET_ARCH)
  if ( *(unsigned char*)ptr != 0x68 &&
       *(unsigned char*)ptr != 0x58 ) {
-   fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
+   prog_belch("freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
  }
 
@@ -484,7 +539,7 @@ freeHaskellFunctionPtr(void* ptr)
  }    
 #elif defined(sparc_TARGET_ARCH)
  if ( *(unsigned long*)ptr != 0x9C23A008UL ) {
-   fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
+   prog_belch("freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
  }
 
@@ -492,7 +547,7 @@ freeHaskellFunctionPtr(void* ptr)
  freeStablePtr(*((StgStablePtr*)((unsigned long*)ptr + 11)));
 #elif defined(alpha_TARGET_ARCH)
  if ( *(StgWord64*)ptr != 0xa77b0018a61b0010L ) {
-   fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
+   prog_belch("freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
  }
 
@@ -500,7 +555,7 @@ freeHaskellFunctionPtr(void* ptr)
  freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 0x10)));
 #elif defined(powerpc_TARGET_ARCH)
  if ( *(StgWord*)ptr != 0x7d0a4378 ) {
-   fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
+   prog_belch("freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
  }
  freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 4*12)));
@@ -509,7 +564,7 @@ freeHaskellFunctionPtr(void* ptr)
  StgWord64 *code = (StgWord64 *)(fdesc+1);
 
  if (fdesc->ip != (StgWord64)code) {
-   fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
+   prog_belch("freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
  }
  freeStablePtr((StgStablePtr)code[16]);
@@ -520,6 +575,17 @@ freeHaskellFunctionPtr(void* ptr)
 #endif
  *((unsigned char*)ptr) = '\0';
 
- free(ptr);
+ stgFree(ptr);
 }
 
+
+/*
+ * Function: initAdjustor()
+ *
+ * Perform initialisation of adjustor thunk layer (if needed.)
+ */
+rtsBool
+initAdjustor(void)
+{
+    return execPage(__obscure_ccall_ret_code, pageExecuteRead);
+}