]> granicus.if.org Git - python/commitdiff
Port _ctypes.pyd to win64 on AMD64.
authorThomas Heller <theller@ctypes.org>
Fri, 25 Aug 2006 07:27:33 +0000 (07:27 +0000)
committerThomas Heller <theller@ctypes.org>
Fri, 25 Aug 2006 07:27:33 +0000 (07:27 +0000)
Lib/ctypes/__init__.py
Lib/ctypes/test/test_win32.py
Modules/_ctypes/_ctypes.c
Modules/_ctypes/_ctypes_test.c
Modules/_ctypes/callbacks.c
Modules/_ctypes/callproc.c
Modules/_ctypes/cfield.c
Modules/_ctypes/libffi_msvc/ffi.c
Modules/_ctypes/libffi_msvc/ffi.h
Modules/_ctypes/libffi_msvc/ffitarget.h

index 61923b61e53de03d59a4b49e0883222aea7abb31..bd4b9436af5216e3acaaf1f9fefef8bbdb4d1d04 100644 (file)
@@ -427,6 +427,8 @@ if sizeof(c_uint) == sizeof(c_void_p):
     c_size_t = c_uint
 elif sizeof(c_ulong) == sizeof(c_void_p):
     c_size_t = c_ulong
+elif sizeof(c_ulonglong) == sizeof(c_void_p):
+    c_size_t = c_ulonglong
 
 # functions
 
index db530d3af4ad4392b20742387d49f8cafa0245fa..10deacad530331cb88bda3f92985356e99949d2b 100644 (file)
@@ -6,7 +6,8 @@ import unittest, sys
 
 import _ctypes_test
 
-if sys.platform == "win32":
+if sys.platform == "win32" and sizeof(c_void_p) == sizeof(c_int):
+    # Only windows 32-bit has different calling conventions.
 
     class WindowsTestCase(unittest.TestCase):
         def test_callconv_1(self):
index 5204a7fa3457ae210e51c06eaafa6ad1b1afa6c4..6234c2b2e5c13e3d6c180b32f96034312cea7324 100644 (file)
@@ -2589,16 +2589,22 @@ static PPROC FindAddress(void *handle, char *name, PyObject *type)
        PPROC address;
        char *mangled_name;
        int i;
-       StgDictObject *dict = PyType_stgdict((PyObject *)type);
+       StgDictObject *dict;
 
        address = (PPROC)GetProcAddress(handle, name);
+#ifdef _WIN64
+       /* win64 has no stdcall calling conv, so it should
+          also not have the name mangling of it.
+       */
+       return address;
+#else
        if (address)
                return address;
-
        if (((size_t)name & ~0xFFFF) == 0) {
                return NULL;
        }
 
+       dict = PyType_stgdict((PyObject *)type);
        /* It should not happen that dict is NULL, but better be safe */
        if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
                return address;
@@ -2617,6 +2623,7 @@ static PPROC FindAddress(void *handle, char *name, PyObject *type)
                        return address;
        }
        return NULL;
+#endif
 }
 #endif
 
index 7331d01dcd53515b955a93ab52dc11449f3767f2..d13fec4e9ead92e2cc0af9ea836266becc7e7f9c 100644 (file)
 
 /* some functions handy for testing */
 
+EXPORT(int)myprintf(char *fmt, ...)
+{
+       int result;
+       va_list argptr;
+       va_start(argptr, fmt);
+       result = vprintf(fmt, argptr);
+       va_end(argptr);
+       return result;
+}
+
 EXPORT(char *)my_strtok(char *token, const char *delim)
 {
        return strtok(token, delim);
index c8e669a86e67bc6e6f2855169361e4097b951a17..41ec0f50289bccf3baf14fd520d0bff4b4ad0823 100644 (file)
@@ -300,7 +300,7 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
        }
 
        cc = FFI_DEFAULT_ABI;
-#if defined(MS_WIN32) && !defined(_WIN32_WCE)
+#if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
        if (is_cdecl == 0)
                cc = FFI_STDCALL;
 #endif
index e0765e917cb336ee5a1ab443df0f2e2637735236..19c4da4c7ec6fe79f9bb8f2f4c60176483a18968 100644 (file)
@@ -638,7 +638,7 @@ static int _call_function_pointer(int flags,
        }
        
        cc = FFI_DEFAULT_ABI;
-#if defined(MS_WIN32) && !defined(_WIN32_WCE)
+#if defined(MS_WIN32) && !defined(MS_WIN64) && !defined(_WIN32_WCE)
        if ((flags & FUNCFLAG_CDECL) == 0)
                cc = FFI_STDCALL;
 #endif
@@ -683,6 +683,14 @@ static int _call_function_pointer(int flags,
                return -1;
        }
 #endif
+#ifdef MS_WIN64
+       if (delta != 0) {
+               PyErr_Format(PyExc_RuntimeError,
+                            "ffi_call failed with code %d",
+                            delta);
+               return -1;
+       }
+#else
        if (delta < 0) {
                if (flags & FUNCFLAG_CDECL)
                        PyErr_Format(PyExc_ValueError,
@@ -703,6 +711,7 @@ static int _call_function_pointer(int flags,
                             delta);
                return -1;
        }
+#endif
 #endif
        if ((flags & FUNCFLAG_PYTHONAPI) && PyErr_Occurred())
                return -1;
@@ -979,7 +988,11 @@ PyObject *_CallProc(PPROC pProc,
        }
        for (i = 0; i < argcount; ++i) {
                atypes[i] = args[i].ffi_type;
-               if (atypes[i]->type == FFI_TYPE_STRUCT)
+               if (atypes[i]->type == FFI_TYPE_STRUCT 
+#ifdef _WIN64
+                   && atypes[i]->size <= sizeof(void *)
+#endif
+                   )
                        avalues[i] = (void *)args[i].value.p;
                else
                        avalues[i] = (void *)&args[i].value;
@@ -1099,7 +1112,11 @@ static PyObject *load_library(PyObject *self, PyObject *args)
        hMod = LoadLibrary(name);
        if (!hMod)
                return PyErr_SetFromWindowsErr(GetLastError());
+#ifdef _WIN64
+       return PyLong_FromVoidPtr(hMod);
+#else
        return Py_BuildValue("i", hMod);
+#endif
 }
 
 static char free_library_doc[] =
index c16a387464f9c928a0dc89daf526a6e2fbbddca0..ad83195276f94d5ccec3f954ce956b6a807dc2b7 100644 (file)
@@ -1315,7 +1315,11 @@ z_set(void *ptr, PyObject *value, unsigned size)
                *(char **)ptr = PyString_AS_STRING(str);
                return str;
        } else if (PyInt_Check(value) || PyLong_Check(value)) {
+#if SIZEOF_VOID_P == SIZEOF_LONG_LONG
+               *(char **)ptr = (char *)PyInt_AsUnsignedLongLongMask(value);
+#else
                *(char **)ptr = (char *)PyInt_AsUnsignedLongMask(value);
+#endif
                _RET(value);
        }
        PyErr_Format(PyExc_TypeError,
@@ -1360,7 +1364,11 @@ Z_set(void *ptr, PyObject *value, unsigned size)
                if (!value)
                        return NULL;
        } else if (PyInt_Check(value) || PyLong_Check(value)) {
+#if SIZEOF_VOID_P == SIZEOF_LONG_LONG
+               *(wchar_t **)ptr = (wchar_t *)PyInt_AsUnsignedLongLongMask(value);
+#else
                *(wchar_t **)ptr = (wchar_t *)PyInt_AsUnsignedLongMask(value);
+#endif
                Py_INCREF(Py_None);
                return Py_None;
        } else if (!PyUnicode_Check(value)) {
index 9af6b716d2b08533abe6d34df3443af94e24310d..3f23a052eddce94b72eec4803e11a27b7daf1a9a 100644 (file)
@@ -34,6 +34,8 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
+extern void Py_FatalError(char *msg);
+
 /*@-exportheader@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
 /*@=exportheader@*/
@@ -44,11 +46,10 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
   register ffi_type **p_arg;
 
   argp = stack;
-
   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
     {
       *(void **) argp = ecif->rvalue;
-      argp += 4;
+      argp += sizeof(void *);
     }
 
   p_argv = ecif->avalue;
@@ -60,8 +61,8 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
       size_t z;
 
       /* Align if necessary */
-      if ((sizeof(int) - 1) & (unsigned) argp)
-       argp = (char *) ALIGN(argp, sizeof(int));
+      if ((sizeof(void *) - 1) & (size_t) argp)
+       argp = (char *) ALIGN(argp, sizeof(void *));
 
       z = (*p_arg)->size;
       if (z < sizeof(int))
@@ -108,7 +109,11 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
       p_argv++;
       argp += z;
     }
-  
+
+  if (argp - stack > ecif->cif->bytes) 
+    {
+      Py_FatalError("FFI BUG: not enough stack space for arguments");
+    }
   return;
 }
 
@@ -128,6 +133,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
       break;
 
     case FFI_TYPE_UINT64:
+#ifdef _WIN64
+    case FFI_TYPE_POINTER:
+#endif
       cif->flags = FFI_TYPE_SINT64;
       break;
 
@@ -139,6 +147,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   return FFI_OK;
 }
 
+#ifdef _WIN32
 /*@-declundef@*/
 /*@-exportheader@*/
 extern int
@@ -160,6 +169,16 @@ ffi_call_STDCALL(void (*)(char *, extended_cif *),
                 void (*fn)());
 /*@=declundef@*/
 /*@=exportheader@*/
+#endif
+
+#ifdef _WIN64
+extern int
+ffi_call_AMD64(void (*)(char *, extended_cif *),
+                /*@out@*/ extended_cif *,
+                unsigned, unsigned,
+                /*@out@*/ unsigned *,
+                void (*fn)());
+#endif
 
 int
 ffi_call(/*@dependent@*/ ffi_cif *cif, 
@@ -188,6 +207,7 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
   
   switch (cif->abi) 
     {
+#if !defined(_WIN64)
     case FFI_SYSV:
       /*@-usedef@*/
       return ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
@@ -201,6 +221,14 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
                              cif->flags, ecif.rvalue, fn);
       /*@=usedef@*/
       break;
+#else
+    case FFI_SYSV:
+      /*@-usedef@*/
+      return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, 
+                          cif->flags, ecif.rvalue, fn);
+      /*@=usedef@*/
+      break;
+#endif
 
     default:
       FFI_ASSERT(0);
@@ -213,10 +241,14 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
 /** private members **/
 
 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
-                                        void** args, ffi_cif* cif);
+                                         void** args, ffi_cif* cif);
 /* This function is jumped to by the trampoline */
 
+#ifdef _WIN64
+void *
+#else
 static void __fastcall
+#endif
 ffi_closure_SYSV (ffi_closure *closure, int *argp)
 {
   // this is our return value storage
@@ -244,6 +276,7 @@ ffi_closure_SYSV (ffi_closure *closure, int *argp)
 
   rtype = cif->flags;
 
+#if defined(_WIN32) && !defined(_WIN64)
 #ifdef _MSC_VER
   /* now, do a generic return based on the value of rtype */
   if (rtype == FFI_TYPE_INT)
@@ -303,6 +336,15 @@ ffi_closure_SYSV (ffi_closure *closure, int *argp)
           : "eax", "edx");
     }
 #endif
+#endif
+
+#ifdef _WIN64
+  /* The result is returned in rax.  This does the right thing for
+     result types except for floats; we have to 'mov xmm0, rax' in the
+     caller to correct this.
+  */
+  return *(void **)resp;
+#endif
 }
 
 /*@-exportheader@*/
@@ -330,8 +372,8 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
       size_t z;
 
       /* Align if necessary */
-      if ((sizeof(int) - 1) & (unsigned) argp) {
-       argp = (char *) ALIGN(argp, sizeof(int));
+      if ((sizeof(char *) - 1) & (size_t) argp) {
+       argp = (char *) ALIGN(argp, sizeof(char*));
       }
 
       z = (*p_arg)->size;
@@ -347,24 +389,8 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
   return;
 }
 
-/* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
-
-#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,BYTES) \
-{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
-   unsigned int  __fun = (unsigned int)(FUN); \
-   unsigned int  __ctx = (unsigned int)(CTX); \
-   unsigned int  __dis = __fun - ((unsigned int) __tramp + 8 + 4); \
-   *(unsigned char*)  &__tramp[0] = 0xb9; \
-   *(unsigned int*)   &__tramp[1] = __ctx; /* mov ecx, __ctx */ \
-   *(unsigned char*)  &__tramp[5] = 0x8b; \
-   *(unsigned char*)  &__tramp[6] = 0xd4; /* mov edx, esp */ \
-   *(unsigned char*)  &__tramp[7] = 0xe8; \
-   *(unsigned int*)   &__tramp[8] = __dis; /* call __fun  */ \
-   *(unsigned char*)  &__tramp[12] = 0xC2; /* ret BYTES */ \
-   *(unsigned short*) &__tramp[13] = BYTES; \
- }
-
 /* the cif must already be prep'ed */
+extern void ffi_closure_OUTER();
 
 ffi_status
 ffi_prep_closure (ffi_closure* closure,
@@ -373,19 +399,78 @@ ffi_prep_closure (ffi_closure* closure,
                  void *user_data)
 {
   short bytes;
+  char *tramp;
+#ifdef _WIN64
+  int mask;
+#endif
   FFI_ASSERT (cif->abi == FFI_SYSV);
   
   if (cif->abi == FFI_SYSV)
     bytes = 0;
+#if !defined(_WIN64)
   else if (cif->abi == FFI_STDCALL)
     bytes = cif->bytes;
+#endif
   else
     return FFI_BAD_ABI;
 
-  FFI_INIT_TRAMPOLINE (&closure->tramp[0],
-                      &ffi_closure_SYSV,
-                      (void*)closure,
-                      bytes);
+  tramp = &closure->tramp[0];
+
+#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
+#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
+#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
+#define INT(x) *(int*)tramp = x, tramp += sizeof(int)
+
+#ifdef _WIN64
+  if (cif->nargs >= 1 &&
+      (cif->arg_types[0]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
+    mask |= 1;
+  if (cif->nargs >= 2 &&
+      (cif->arg_types[1]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
+    mask |= 2;
+  if (cif->nargs >= 3 &&
+      (cif->arg_types[2]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
+    mask |= 4;
+  if (cif->nargs >= 4 &&
+      (cif->arg_types[3]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
+    mask |= 8;
+
+  /* 41 BB ----         mov         r11d,mask */
+  BYTES("\x41\xBB"); INT(mask);
+
+  /* 48 B8 --------     mov         rax, closure                       */
+  BYTES("\x48\xB8"); POINTER(closure);
+
+  /* 49 BA --------     mov         r10, ffi_closure_OUTER */
+  BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
+
+  /* 41 FF E2           jmp         r10 */
+  BYTES("\x41\xFF\xE2");
+
+#else
+
+  /* mov ecx, closure */
+  BYTES("\xb9"); POINTER(closure);
+
+  /* mov edx, esp */
+  BYTES("\x8b\xd4");
+
+  /* call ffi_closure_SYSV */
+  BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
+
+  /* ret bytes */
+  BYTES("\xc2");
+  SHORT(bytes);
+  
+#endif
+
+  if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
+    Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
+
   closure->cif  = cif;
   closure->user_data = user_data;
   closure->fun  = fun;
index 203142d9ce11bae52c9074a401dbff8cb724a1e9..a88d8744f7f240f7f7d83ce28ca22825ddda6bee 100644 (file)
@@ -174,12 +174,10 @@ typedef struct {
 
 /* ---- Definitions for the raw API -------------------------------------- */
 
-#ifndef FFI_SIZEOF_ARG
-# if LONG_MAX == 2147483647
-#  define FFI_SIZEOF_ARG        4
-# elif LONG_MAX == 9223372036854775807
-#  define FFI_SIZEOF_ARG        8
-# endif
+#ifdef _WIN64
+#define FFI_SIZEOF_ARG 8
+#else
+#define FFI_SIZEOF_ARG 4
 #endif
 
 typedef union {
index 78c0c37caeb3e81d0460b534152def505841463a..0da79d4c1ad700f5ad9e75d4fdae098967754fe3 100644 (file)
@@ -44,7 +44,9 @@ typedef enum ffi_abi {
 
   /* ---- Intel x86 Win32 ---------- */
   FFI_SYSV,
+#ifndef _WIN64
   FFI_STDCALL,
+#endif
   /* TODO: Add fastcall support for the sake of completeness */
   FFI_DEFAULT_ABI = FFI_SYSV,
 
@@ -67,8 +69,8 @@ typedef enum ffi_abi {
 
 #define FFI_CLOSURES 1
 
-#ifdef X86_64
-#define FFI_TRAMPOLINE_SIZE 24
+#ifdef _WIN64
+#define FFI_TRAMPOLINE_SIZE 29
 #define FFI_NATIVE_RAW_API 0
 #else
 #define FFI_TRAMPOLINE_SIZE 15