Commit abc0bbf3813dc43e23d4c23e6fe794dbf287639b

green 2008-01-31T11:58:57

Add Tim Wall's x86 windows patch.

diff --git a/libffi/ChangeLog.libffi b/libffi/ChangeLog.libffi
index 187daa1..1981708 100644
--- a/libffi/ChangeLog.libffi
+++ b/libffi/ChangeLog.libffi
@@ -1,3 +1,12 @@
+2008-01-31  Timothy Wall <twall@users.sf.net>
+
+	* testsuite/libffi.call/closure_stdcall.c: Add test for stdcall
+	closures.
+	* src/x86/ffitarget.h: Increase size of trampoline for stdcall
+	closures.
+	* src/x86/win32.S: Add assembly for stdcall closure.
+	* src/x86/ffi.c: Initialize stdcall closure trampoline.
+
 2008-01-30  H.J. Lu <hongjiu.lu@intel.com>
 
 	PR libffi/34612
diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c
index a4d4798..eef8382 100644
--- a/libffi/src/x86/ffi.c
+++ b/libffi/src/x86/ffi.c
@@ -235,6 +235,10 @@ unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
      __attribute__ ((regparm(1)));
 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
      __attribute__ ((regparm(1)));
+#ifdef X86_WIN32
+void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
+     __attribute__ ((regparm(1)));
+#endif
 
 /* This function is jumped to by the trampoline */
 
@@ -317,6 +321,19 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
    *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
  })
 
+#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE)  \
+({ 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 + FFI_TRAMPOLINE_SIZE); \
+   unsigned short __size = (unsigned short)(SIZE); \
+   *(unsigned char*) &__tramp[0] = 0xb8; \
+   *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
+   *(unsigned char *)  &__tramp[5] = 0xe8; \
+   *(unsigned int*)  &__tramp[6] = __dis; /* call __fun  */ \
+   *(unsigned char *)  &__tramp[10] = 0xc2; \
+   *(unsigned short*)  &__tramp[11] = __size; /* ret __size  */ \
+ })
 
 /* the cif must already be prep'ed */
 
@@ -327,11 +344,24 @@ ffi_prep_closure_loc (ffi_closure* closure,
 		      void *user_data,
 		      void *codeloc)
 {
-  FFI_ASSERT (cif->abi == FFI_SYSV);
-
-  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
-		       &ffi_closure_SYSV,  \
-		       codeloc);
+  if (cif->abi == FFI_SYSV)
+    {
+      FFI_INIT_TRAMPOLINE (&closure->tramp[0],
+                           &ffi_closure_SYSV,
+                           (void*)closure);
+    }
+#ifdef X86_WIN32
+  else if (cif->abi == FFI_STDCALL)
+    {
+      FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
+                                   &ffi_closure_STDCALL,
+                                   (void*)closure, cif->bytes);
+    }
+#endif
+  else
+    {
+      return FFI_BAD_ABI;
+    }
     
   closure->cif  = cif;
   closure->user_data = user_data;
@@ -353,7 +383,9 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
 {
   int i;
 
-  FFI_ASSERT (cif->abi == FFI_SYSV);
+  if (cif->abi != FFI_SYSV) {
+    return FFI_BAD_ABI;
+  }
 
   // we currently don't support certain kinds of arguments for raw
   // closures.  This should be implemented by a separate assembly language
diff --git a/libffi/src/x86/ffitarget.h b/libffi/src/x86/ffitarget.h
index 3a1427c..fecdc24 100644
--- a/libffi/src/x86/ffitarget.h
+++ b/libffi/src/x86/ffitarget.h
@@ -77,7 +77,11 @@ typedef enum ffi_abi {
 #define FFI_TRAMPOLINE_SIZE 24
 #define FFI_NATIVE_RAW_API 0
 #else
+#ifdef X86_WIN32
+#define FFI_TRAMPOLINE_SIZE 13
+#else
 #define FFI_TRAMPOLINE_SIZE 10
+#endif
 #define FFI_NATIVE_RAW_API 1	/* x86 has native raw api support */
 #endif
 
diff --git a/libffi/src/x86/win32.S b/libffi/src/x86/win32.S
index 496953e..083039a 100644
--- a/libffi/src/x86/win32.S
+++ b/libffi/src/x86/win32.S
@@ -258,6 +258,22 @@ sc_epilogue:
 
 .ffi_call_STDCALL_end:
 
+	.globl _ffi_closure_STDCALL
+_ffi_closure_STDCALL:
+	pushl	%ebp
+	movl	%esp, %ebp
+	subl	$40, %esp
+	leal	-24(%ebp), %edx
+	movl	%edx, -12(%ebp)	/* resp */
+	leal	12(%ebp), %edx  /* account for stub return address on stack */
+	movl	%edx, 4(%esp)	/* args */
+	leal	-12(%ebp), %edx
+	movl	%edx, (%esp)	/* &resp */
+	call	_ffi_closure_SYSV_inner
+	movl	-12(%ebp), %ecx
+	jmp     .Lcls_return_result
+.ffi_closure_STDCALL_end:
+
 	.globl _ffi_closure_SYSV
 _ffi_closure_SYSV:
 	pushl	%ebp
@@ -271,6 +287,7 @@ _ffi_closure_SYSV:
 	movl	%edx, (%esp)	/* &resp */
 	call	_ffi_closure_SYSV_inner
 	movl	-12(%ebp), %ecx
+.Lcls_return_result:
 	cmpl	$FFI_TYPE_INT, %eax
 	je	.Lcls_retint
 	cmpl	$FFI_TYPE_FLOAT, %eax
diff --git a/libffi/testsuite/libffi.call/closure_stdcall.c b/libffi/testsuite/libffi.call/closure_stdcall.c
new file mode 100644
index 0000000..e80b10b
--- /dev/null
+++ b/libffi/testsuite/libffi.call/closure_stdcall.c
@@ -0,0 +1,72 @@
+/* Area:	closure_call (stdcall convention)
+   Purpose:	Check handling when caller expects stdcall callee
+   Limitations:	none.
+   PR:		none.
+   Originator:	<twalljava@dev.java.net> */
+
+/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+#include "ffitest.h"
+
+static void
+closure_test_stdcall(ffi_cif* cif __UNUSED__, void* resp, void** args,
+		 void* userdata)
+{
+  *(ffi_arg*)resp =
+    (int)*(int *)args[0] + (int)(*(int *)args[1])
+    + (int)(*(int *)args[2])  + (int)(*(int *)args[3])
+    + (int)(long)userdata;
+
+  printf("%d %d %d %d: %d\n",
+	 (int)*(int *)args[0], (int)(*(int *)args[1]),
+	 (int)(*(int *)args[2]), (int)(*(int *)args[3]),
+         (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (__stdcall *closure_test_type0)(int, int, int, int);
+
+int main (void)
+{
+  ffi_cif cif;
+#ifndef USING_MMAP
+  static ffi_closure cl;
+#endif
+  ffi_closure *pcl;
+  ffi_type * cl_arg_types[17];
+  int res;
+  void* sp_pre;
+  void* sp_post;
+  char buf[1024];
+
+#ifdef USING_MMAP
+  pcl = allocate_mmap (sizeof(ffi_closure));
+#else
+  pcl = &cl;
+#endif
+
+  cl_arg_types[0] = &ffi_type_uint;
+  cl_arg_types[1] = &ffi_type_uint;
+  cl_arg_types[2] = &ffi_type_uint;
+  cl_arg_types[3] = &ffi_type_uint;
+  cl_arg_types[4] = NULL;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 4,
+		     &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+  CHECK(ffi_prep_closure(pcl, &cif, closure_test_stdcall,
+			 (void *) 3 /* userdata */) == FFI_OK);
+
+  asm volatile (" movl %%esp,%0" : "=g" (sp_pre));
+  res = (*(closure_test_type0)pcl)(0, 1, 2, 3);
+  asm volatile (" movl %%esp,%0" : "=g" (sp_post));
+  /* { dg-output "0 1 2 3: 9" } */
+
+  printf("res: %d\n",res);
+  /* { dg-output "\nres: 9" } */
+
+  sprintf(buf, "mismatch: pre=%p vs post=%p", sp_pre, sp_post);
+  printf("stack pointer %s\n", (sp_pre == sp_post ? "match" : buf));
+  /* { dg-output "\nstack pointer match" } */
+  exit(0);
+}