This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch libffi]: Add thiscall-closure support for fixing regression PR/51500


Hi,

this patch adds missing support of the X86_WIN32 calling-convention
for thiscall-closures. ?As thiscall-convention can be only used in C++
for class-member calls, the assumption that first argument gets passed
in register is always valid. ?As it is either the "this" pointer, or
the structure-aggregate-return-pointer.
This patch is necessary to fix on gcc's trunk the PR 51500 completely.

ChangeLog

2012-01-31 ?Kai Tietz ?<ktietz@redhat.com>

? ? ? ?* src/prep_cif.c (ffi_prep_cif): Allow for X86_WIN32
? ? ? ?also FFI_THISCALL.
? ? ? ?* src/x86/ffi.c (ffi_closure_THISCALL): Add prototype.
? ? ? ?(FFI_INIT_TRAMPOLINE_THISCALL): New trampoline code.
? ? ? ?(ffi_prep_closure_loc): Add FFI_THISCALL support.
? ? ? ?* src/x86/ffitarget.h (FFI_TRAMPOLINE_SIZE): Adjust size.
? ? ? ?* src/x86/win32.S (ffi_closure_THISCALL): New closure code
? ? ? ?for thiscall-calling convention.
? ? ? ?* testsuite/libffi.call/closure_thiscall.c: New test.

Regression tested for i686-w64-mingw32, i686-pc-cygwin, and
x86_64-unknown-linux-gnu. ?Ok for apply?

Regards,
Kai

Index: gcc/libffi/src/prep_cif.c
===================================================================
--- gcc.orig/libffi/src/prep_cif.c
+++ gcc/libffi/src/prep_cif.c
@@ -93,7 +93,12 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ff
? ffi_type **ptr;

? FFI_ASSERT(cif != NULL);
+#ifndef X86_WIN32
? FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
+#else
+ ?FFI_ASSERT(abi > FFI_FIRST_ABI && abi <= FFI_DEFAULT_ABI
+ ? ? ? ? ? ?|| abi == FFI_THISCALL);
+#endif

? cif->abi = abi;
? cif->arg_types = atypes;
Index: gcc/libffi/src/x86/ffi.c
===================================================================
--- gcc.orig/libffi/src/x86/ffi.c
+++ gcc/libffi/src/x86/ffi.c
@@ -449,6 +449,8 @@ void FFI_HIDDEN ffi_closure_raw_SYSV (ff
?#ifdef X86_WIN32
?void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
? ? ?__attribute__ ((regparm(1)));
+void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *)
+ ? ? __attribute__ ((regparm(1)));
?#endif
?#ifdef X86_WIN64
?void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
@@ -608,6 +610,24 @@ ffi_prep_incoming_args_SYSV(char *stack,
? ?*(unsigned int*) ?&__tramp[6] = __dis; /* jmp __fun ?*/ \
?}

+#define FFI_INIT_TRAMPOLINE_THISCALL(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 - (__ctx + 22); ?\
+ ? unsigned short __size = (unsigned short)(SIZE); \
+ ? *(unsigned int *) &__tramp[0] = 0x8924048b; /* mov (%esp), %eax */ \
+ ? *(unsigned int *) &__tramp[4] = 0xec83240c; /* mov %ecx, (%esp) */ \
+ ? *(unsigned int *) &__tramp[8] = 0x24048904; /* sub $4,(%esp) */ \
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* mov %eax, (%esp) */ \
+ ? *(unsigned char*) &__tramp[12] = 0xb8; \
+ ? *(unsigned int*) ?&__tramp[13] = __ctx; /* movl __ctx, %eax */ \
+ ? *(unsigned char *) ?&__tramp[17] = 0xe8; \
+ ? *(unsigned int*) ?&__tramp[18] = __dis; /* call __fun ?*/ \
+ ? *(unsigned char*) ?&__tramp[22] = 0xc2; /* ret ?*/ \
+ ? *(unsigned short*) ?&__tramp[23] = __size; /* ret __size ?*/ \
+ }
+
?#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) ?\
?{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
? ?unsigned int ?__fun = (unsigned int)(FUN); \
@@ -650,6 +670,13 @@ ffi_prep_closure_loc (ffi_closure* closu
? ? ? ? ? ? ? ? ? ? ? ? ? ?(void*)codeloc);
? ? }
?#ifdef X86_WIN32
+ ?else if (cif->abi == FFI_THISCALL)
+ ? ?{
+ ? ? ?FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &ffi_closure_THISCALL,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (void*)codeloc,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cif->bytes);
+ ? ?}
? else if (cif->abi == FFI_STDCALL)
? ? {
? ? ? FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
Index: gcc/libffi/src/x86/ffitarget.h
===================================================================
--- gcc.orig/libffi/src/x86/ffitarget.h
+++ gcc/libffi/src/x86/ffitarget.h
@@ -103,7 +103,7 @@ typedef enum ffi_abi {
?#define FFI_NATIVE_RAW_API 0
?#else
?#ifdef X86_WIN32
-#define FFI_TRAMPOLINE_SIZE 13
+#define FFI_TRAMPOLINE_SIZE 25
?#else
?#ifdef X86_WIN64
?#define FFI_TRAMPOLINE_SIZE 29
Index: gcc/libffi/src/x86/win32.S
===================================================================
--- gcc.orig/libffi/src/x86/win32.S
+++ gcc/libffi/src/x86/win32.S
@@ -170,6 +170,16 @@ ca_epilogue:
? ? ? ? ret
?ffi_call_win32 ENDP

+ffi_closure_THISCALL PROC NEAR FORCEFRAME
+ ? ? ? push ? ?ebp
+ ? ? ? mov ? ? ebp, esp
+ ? ? ? sub ? ? esp, 40
+ ? ? ? lea ? ? edx, [ebp -24]
+ ? ? ? mov ? ? [ebp - 12], edx /* resp */
+ ? ? ? lea ? ? edx, [ebp + 12] ?/* account for stub return address on stack */
+ ? ? ? jmp ? ? stub
+ffi_closure_THISCALL ENDP
+
?ffi_closure_SYSV PROC NEAR FORCEFRAME
? ? ;; the ffi_closure ctx is passed in eax by the trampoline.

@@ -177,6 +187,7 @@ ffi_closure_SYSV PROC NEAR FORCEFRAME
? ? ? ? lea ?edx, [ebp - 24]
? ? ? ? mov ?[ebp - 12], edx ? ? ? ? ;; resp
? ? ? ? lea ?edx, [ebp + 8]
+stub:
? ? ? ? mov ?[esp + 8], edx ? ? ? ? ?;; args
? ? ? ? lea ?edx, [ebp - 12]
? ? ? ? mov ?[esp + 4], edx ? ? ? ? ?;; &resp
@@ -573,6 +584,19 @@ _ffi_call_win32:
? ? ? ? popl %ebp
? ? ? ? ret
?.ffi_call_win32_end:
+ ? ? ? ?.balign 16
+ ? ? ? .globl ?_ffi_closure_THISCALL
+#ifndef __OS2__
+ ? ? ? .def ? ?_ffi_closure_THISCALL; ?.scl ? ?2; ? ? ?.type ? 32; ? ? .endef
+#endif
+_ffi_closure_THISCALL:
+ ? ? ? 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 */
+ ? ? ? jmp ? ? .stub
?.LFE1:

? ? ? ? # This assumes we are using gas.
@@ -591,6 +615,7 @@ _ffi_closure_SYSV:
? ? ? ?leal ? ?-24(%ebp), %edx
? ? ? ?movl ? ?%edx, -12(%ebp) /* resp */
? ? ? ?leal ? ?8(%ebp), %edx
+.stub:
? ? ? ?movl ? ?%edx, 4(%esp) ? /* args = __builtin_dwarf_cfa () */
? ? ? ?leal ? ?-12(%ebp), %edx
? ? ? ?movl ? ?%edx, (%esp) ? ?/* &resp */
Index: gcc/libffi/testsuite/libffi.call/closure_thiscall.c
===================================================================
--- /dev/null
+++ gcc/libffi/testsuite/libffi.call/closure_thiscall.c
@@ -0,0 +1,64 @@
+/* Area: ? ? ? closure_call (thiscall convention)
+ ? Purpose: ? ?Check handling when caller expects thiscall callee
+ ? Limitations: ? ? ? ?none.
+ ? PR: ? ? ? ? none.
+ ? Originator: <ktietz@redhat.com> */
+
+/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+#include "ffitest.h"
+
+static void
+closure_test_thiscall(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)(intptr_t)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 (__thiscall *closure_test_type0)(int, int, int, int);
+
+int main (void)
+{
+ ?ffi_cif cif;
+ ?void *code;
+ ?ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ?ffi_type * cl_arg_types[17];
+ ?int res;
+ ?void* sp_pre;
+ ?void* sp_post;
+ ?char buf[1024];
+
+ ?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_THISCALL, 4,
+ ? ? ? ? ? ? ? ? ? ?&ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ ?CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_thiscall,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? (void *) 3 /* userdata */, code) == FFI_OK);
+
+ ?asm volatile (" movl %%esp,%0" : "=g" (sp_pre));
+ ?res = (*(closure_test_type0)code)(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);
+}


-- 
|? (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

Attachment: pr51500_libffi_tc_closure.txt
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]