This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, i386][PING] libffi stdcall closures
- From: Timothy Wall <twalljava at dev dot java dot net>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 23 Jan 2008 12:51:03 -0500
- Subject: [PATCH, i386][PING] libffi stdcall closures
Here's the cleaned up patch for stdcall closures in libffi. Includes
test case.
Index: ChangeLog
===================================================================
--- ChangeLog (revision 243)
+++ ChangeLog (working copy)
@@ -1,3 +1,12 @@
+2007-11-08 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.
+
2007-05-13 Release Manager
* GCC 4.2.0 released.
Index: src/x86/ffitarget.h
===================================================================
--- src/x86/ffitarget.h (revision 243)
+++ src/x86/ffitarget.h (working copy)
@@ -73,7 +73,11 @@
#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
Index: src/x86/win32.S
===================================================================
--- src/x86/win32.S (revision 243)
+++ src/x86/win32.S (working copy)
@@ -258,6 +258,22 @@
.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 @@
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
Index: src/x86/ffi.c
===================================================================
--- src/x86/ffi.c (revision 243)
+++ src/x86/ffi.c (working copy)
@@ -227,6 +227,10 @@
__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 */
@@ -302,13 +306,26 @@
({ 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 int __dis = __fun - ((unsigned int) __tramp + 10); \
*(unsigned char*) &__tramp[0] = 0xb8; \
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
*(unsigned char *) &__tramp[5] = 0xe9; \
*(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 + 10); \
+ 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 */
@@ -318,12 +335,25 @@
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
- FFI_ASSERT (cif->abi == FFI_SYSV);
+ 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;
+ }
- FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
- &ffi_closure_SYSV, \
- (void*)closure);
-
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
@@ -343,7 +373,9 @@
{
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
Index: testsuite/libffi.call/closure_stdcall.c
===================================================================
--- testsuite/libffi.call/closure_stdcall.c (revision 0)
+++ testsuite/libffi.call/closure_stdcall.c (revision 384)
@@ -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);
+}