diff options
author | ktietz <ktietz@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-02-08 21:35:19 +0000 |
---|---|---|
committer | ktietz <ktietz@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-02-08 21:35:19 +0000 |
commit | e5fbea4091e302e6d696c978eea3abc231b17adf (patch) | |
tree | 04eccef5248b2631ad4b9a46a6f2bc4f49b8cd64 /libffi | |
parent | f19ce63be8c51cb72c08d1b83bb23fac0c82cb82 (diff) | |
download | gcc-e5fbea4091e302e6d696c978eea3abc231b17adf.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184021 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libffi')
-rw-r--r-- | libffi/ChangeLog | 12 | ||||
-rw-r--r-- | libffi/src/prep_cif.c | 5 | ||||
-rw-r--r-- | libffi/src/x86/ffi.c | 36 | ||||
-rw-r--r-- | libffi/src/x86/ffitarget.h | 2 | ||||
-rw-r--r-- | libffi/src/x86/win32.S | 25 | ||||
-rw-r--r-- | libffi/testsuite/libffi.call/closure_thiscall.c | 64 |
6 files changed, 143 insertions, 1 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 10ad4fcd3e3..47d31fa73c1 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,15 @@ +2012-02-08 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. + 2012-01-28 Kai Tietz <ktietz@redhat.com> * src/libffi/src/x86/ffi.c (ffi_call_win32): Add new diff --git a/libffi/src/prep_cif.c b/libffi/src/prep_cif.c index c1c3b9a6c86..e0a0c68cac5 100644 --- a/libffi/src/prep_cif.c +++ b/libffi/src/prep_cif.c @@ -93,7 +93,12 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, 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; diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c index bbfd95e5ec1..7c01c57c4db 100644 --- a/libffi/src/x86/ffi.c +++ b/libffi/src/x86/ffi.c @@ -449,6 +449,8 @@ void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) #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,33 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, *(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] = 0x8324048b; /* mov (%esp), %eax */ \ + *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \ + *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \ + *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \ + *(unsigned char*) &__tramp[13] = 0xb8; \ + *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \ + *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \ + *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \ + *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \ + *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \ + *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \ + *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \ + *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \ + *(unsigned char*) &__tramp[39] = 0xb8; \ + *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[44] = 0xe8; \ + *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \ + *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \ + *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \ + } + #define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ { unsigned char *__tramp = (unsigned char*)(TRAMP); \ unsigned int __fun = (unsigned int)(FUN); \ @@ -650,6 +679,13 @@ ffi_prep_closure_loc (ffi_closure* closure, (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], diff --git a/libffi/src/x86/ffitarget.h b/libffi/src/x86/ffitarget.h index 4154762d250..dfecd1b3c6e 100644 --- a/libffi/src/x86/ffitarget.h +++ b/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 52 #else #ifdef X86_WIN64 #define FFI_TRAMPOLINE_SIZE 29 diff --git a/libffi/src/x86/win32.S b/libffi/src/x86/win32.S index e472d623c06..e5c93ecf7b9 100644 --- a/libffi/src/x86/win32.S +++ b/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 */ diff --git a/libffi/testsuite/libffi.call/closure_thiscall.c b/libffi/testsuite/libffi.call/closure_thiscall.c new file mode 100644 index 00000000000..6c46f353728 --- /dev/null +++ b/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); +} |