Merge pull request #85 from joshtriplett/stdcall
authorAnthony Green <green@moxielogic.com>
Sun, 16 Mar 2014 12:05:51 +0000 (08:05 -0400)
committerAnthony Green <green@moxielogic.com>
Sun, 16 Mar 2014 12:05:51 +0000 (08:05 -0400)
stdcall support on Linux

16 files changed:
ChangeLog
Makefile.am
src/x86/ffi.c
src/x86/ffitarget.h
src/x86/win32.S
testsuite/libffi.call/closure_stdcall.c
testsuite/libffi.call/closure_thiscall.c
testsuite/libffi.call/fastthis1_win32.c
testsuite/libffi.call/fastthis2_win32.c
testsuite/libffi.call/fastthis3_win32.c
testsuite/libffi.call/many2_win32.c
testsuite/libffi.call/many_win32.c
testsuite/libffi.call/strlen2_win32.c
testsuite/libffi.call/strlen_win32.c
testsuite/libffi.call/struct1_win32.c
testsuite/libffi.call/struct2_win32.c

index 627844c..6db0465 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,39 @@
 2014-03-16  Josh Triplett <josh@joshtriplett.org>
 
+       Add support for stdcall, thiscall, and fastcall on non-Windows x86-32.
+
+       Linux supports the stdcall calling convention, either via functions
+       explicitly declared with the stdcall attribute, or via code compiled
+       with -mrtd which effectively makes stdcall the default.
+
+       This introduces FFI_STDCALL, FFI_THISCALL, and FFI_FASTCALL on
+       non-Windows x86-32 platforms, as non-default calling conventions.
+
+       * Makefile.am: Compile in src/x86/win32.S on non-Windows x86-32.
+       * src/x86/ffitarget.h: Add FFI_STDCALL, FFI_THISCALL, and FFI_FASTCALL
+       on non-Windows x86-32.  Increase trampoline size to accomodate these
+       calling conventions, and unify some ifdeffery.
+       * src/x86/ffi.c: Add support for FFI_STDCALL, FFI_THISCALL, and
+       FFI_FASTCALL on non-Windows x86-32 platforms; update ifdeffery.
+       * src/x86/win32.S: Support compiling on non-Windows x86-32 platforms.
+       On those platforms, avoid redefining the SYSV symbols already provided
+       by src/x86/sysv.S.
+       * testsuite/libffi.call/closure_stdcall.c: Run on non-Windows.
+       #define __stdcall if needed.
+       * testsuite/libffi.call/closure_thiscall.c: Run on non-Windows.
+       #define __fastcall if needed.
+       * testsuite/libffi.call/fastthis1_win32.c: Run on non-Windows.
+       * testsuite/libffi.call/fastthis2_win32.c: Ditto.
+       * testsuite/libffi.call/fastthis3_win32.c: Ditto.
+       * testsuite/libffi.call/many2_win32.c: Ditto.
+       * testsuite/libffi.call/many_win32.c: Ditto.
+       * testsuite/libffi.call/strlen2_win32.c: Ditto.
+       * testsuite/libffi.call/strlen_win32.c: Ditto.
+       * testsuite/libffi.call/struct1_win32.c: Ditto.
+       * testsuite/libffi.call/struct2_win32.c: Ditto.
+
+2014-03-16  Josh Triplett <josh@joshtriplett.org>
+
        * prep_cif.c: Remove unnecessary ifdef for X86_WIN32.
        ffi_prep_cif_core had a special case for X86_WIN32, checking for
        FFI_THISCALL in addition to the FFI_FIRST_ABI-to-FFI_LAST_ABI range
index be11558..25e2121 100644 (file)
@@ -125,7 +125,7 @@ if BFIN
 nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
 endif
 if X86
-nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
+nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S src/x86/win32.S
 endif
 if X86_FREEBSD
 nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/freebsd.S
index 8071921..a02a8a1 100644 (file)
@@ -50,7 +50,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
   register void **p_argv;
   register char *argp;
   register ffi_type **p_arg;
-#ifdef X86_WIN32
+#ifndef X86_WIN64
   size_t p_stack_args[2];
   void *p_stack_data[2];
   char *argp2 = stack;
@@ -69,7 +69,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
       )
     {
       *(void **) argp = ecif->rvalue;
-#ifdef X86_WIN32
+#ifndef X86_WIN64
       /* For fastcall/thiscall this is first register-passed
          argument.  */
       if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
@@ -155,7 +155,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
           memcpy(argp, *p_argv, z);
         }
 
-#ifdef X86_WIN32
+#ifndef X86_WIN64
     /* For thiscall/fastcall convention register-passed arguments
        are the first two none-floating-point arguments with a size
        smaller or equal to sizeof (void*).  */
@@ -180,7 +180,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
 #endif
     }
 
-#ifdef X86_WIN32
+#ifndef X86_WIN64
   /* We need to move the register-passed arguments for thiscall/fastcall
      on top of stack, so that those can be moved to registers ecx/edx by
      call-handler.  */
@@ -318,7 +318,8 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 #endif
 
 #ifndef X86_WIN32
-  cif->bytes = (cif->bytes + 15) & ~0xF;
+  if (cif->abi != FFI_STDCALL && cif->abi != FFI_THISCALL && cif->abi != FFI_FASTCALL)
+    cif->bytes = (cif->bytes + 15) & ~0xF;
 #endif
 
   return FFI_OK;
@@ -328,11 +329,10 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
 extern int
 ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
                unsigned, unsigned, unsigned *, void (*fn)(void));
-#elif defined(X86_WIN32)
+#else
 extern void
 ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
                unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
-#else
 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
                           unsigned, unsigned, unsigned *, void (*fn)(void));
 #endif
@@ -374,10 +374,17 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
       ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
                      cif->flags, ecif.rvalue, fn);
       break;
-#elif defined(X86_WIN32)
+#else
+#ifndef X86_WIN32
+    case FFI_SYSV:
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
+                    fn);
+      break;
+#else
     case FFI_SYSV:
-    case FFI_STDCALL:
     case FFI_MS_CDECL:
+#endif
+    case FFI_STDCALL:
       ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
                     ecif.rvalue, fn);
       break;
@@ -410,11 +417,6 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
                        ecif.rvalue, fn);
       }
       break;
-#else
-    case FFI_SYSV:
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
-                    fn);
-      break;
 #endif
     default:
       FFI_ASSERT(0);
@@ -435,15 +437,14 @@ 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
+#ifndef X86_WIN64
 void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
      __attribute__ ((regparm(1)));
 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
+#else
 void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
 #endif
 
@@ -670,7 +671,6 @@ ffi_prep_closure_loc (ffi_closure* closure,
                            &ffi_closure_SYSV,
                            (void*)codeloc);
     }
-#ifdef X86_WIN32
   else if (cif->abi == FFI_THISCALL)
     {
       FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
@@ -684,6 +684,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
                                    &ffi_closure_STDCALL,
                                    (void*)codeloc, cif->bytes);
     }
+#ifdef X86_WIN32
   else if (cif->abi == FFI_MS_CDECL)
     {
       FFI_INIT_TRAMPOLINE (&closure->tramp[0],
@@ -717,12 +718,12 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
 {
   int i;
 
-  if (cif->abi != FFI_SYSV) {
-#ifdef X86_WIN32
-    if (cif->abi != FFI_THISCALL)
+  if (cif->abi != FFI_SYSV
+#ifndef X86_WIN64
+      && cif->abi != FFI_THISCALL
 #endif
+     )
     return FFI_BAD_ABI;
-  }
 
   /* we currently don't support certain kinds of arguments for raw
      closures.  This should be implemented by a separate assembly
@@ -735,13 +736,13 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
     }
   
-#ifdef X86_WIN32
+#ifndef X86_WIN64
   if (cif->abi == FFI_SYSV)
     {
 #endif
   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
                        codeloc);
-#ifdef X86_WIN32
+#ifndef X86_WIN64
     }
   else if (cif->abi == FFI_THISCALL)
     {
@@ -791,10 +792,17 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
   
   switch (cif->abi) 
     {
-#ifdef X86_WIN32
+#ifndef X86_WIN32
+    case FFI_SYSV:
+      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
+                    ecif.rvalue, fn);
+      break;
+#else
     case FFI_SYSV:
-    case FFI_STDCALL:
     case FFI_MS_CDECL:
+#endif
+#ifndef X86_WIN64
+    case FFI_STDCALL:
       ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
                     ecif.rvalue, fn);
       break;
@@ -827,11 +835,6 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
                        ecif.rvalue, fn);
       }
       break;
-#else
-    case FFI_SYSV:
-      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
-                    ecif.rvalue, fn);
-      break;
 #endif
     default:
       FFI_ASSERT(0);
index 46f294c..d2aaf9d 100644 (file)
@@ -98,6 +98,9 @@ typedef enum ffi_abi {
   /* ---- Intel x86 and AMD x86-64 - */
   FFI_SYSV,
   FFI_UNIX64,   /* Unix variants all use the same ABI for x86-64  */
+  FFI_THISCALL,
+  FFI_FASTCALL,
+  FFI_STDCALL,
   FFI_LAST_ABI,
 #if defined(__i386__) || defined(__i386)
   FFI_DEFAULT_ABI = FFI_SYSV
@@ -119,22 +122,14 @@ typedef enum ffi_abi {
 #if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
 #define FFI_TRAMPOLINE_SIZE 24
 #define FFI_NATIVE_RAW_API 0
-#else
-#ifdef X86_WIN32
-#define FFI_TRAMPOLINE_SIZE 52
-#else
-#ifdef X86_WIN64
+#elif defined(X86_WIN64)
 #define FFI_TRAMPOLINE_SIZE 29
 #define FFI_NATIVE_RAW_API 0
 #define FFI_NO_RAW_API 1
 #else
-#define FFI_TRAMPOLINE_SIZE 10
-#endif
-#endif
-#ifndef X86_WIN64
+#define FFI_TRAMPOLINE_SIZE 52
 #define FFI_NATIVE_RAW_API 1   /* x86 has native raw api support */
 #endif
-#endif
 
 #endif
 
index 24b7bbd..700cb61 100644 (file)
@@ -473,15 +473,21 @@ END
 
 #else
 
+#if defined(X86_WIN32)
+#define USCORE_SYMBOL(x) _##x
+#else
+#define USCORE_SYMBOL(x) x
+#endif
        .text
  
         # This assumes we are using gas.
         .balign 16
-       .globl  _ffi_call_win32
-#ifndef __OS2__
+FFI_HIDDEN(ffi_call_win32)
+       .globl  USCORE_SYMBOL(ffi_call_win32)
+#if defined(X86_WIN32) && !defined(__OS2__)
        .def    _ffi_call_win32;        .scl    2;      .type   32;     .endef
 #endif
-_ffi_call_win32:
+USCORE_SYMBOL(ffi_call_win32):
 .LFB1:
         pushl %ebp
 .LCFI0:
@@ -644,11 +650,12 @@ _ffi_call_win32:
         ret
 .ffi_call_win32_end:
         .balign 16
-       .globl  _ffi_closure_THISCALL
-#ifndef __OS2__
+FFI_HIDDEN(ffi_closure_THISCALL)
+       .globl  USCORE_SYMBOL(ffi_closure_THISCALL)
+#if defined(X86_WIN32) && !defined(__OS2__)
        .def    _ffi_closure_THISCALL;  .scl    2;      .type   32;     .endef
 #endif
-_ffi_closure_THISCALL:
+USCORE_SYMBOL(ffi_closure_THISCALL):
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40, %esp
@@ -660,11 +667,14 @@ _ffi_closure_THISCALL:
 
         # This assumes we are using gas.
         .balign 16
-       .globl  _ffi_closure_SYSV
-#ifndef __OS2__
+FFI_HIDDEN(ffi_closure_SYSV)
+#if defined(X86_WIN32)
+       .globl  USCORE_SYMBOL(ffi_closure_SYSV)
+#if defined(X86_WIN32) && !defined(__OS2__)
        .def    _ffi_closure_SYSV;      .scl    2;      .type   32;     .endef
 #endif
-_ffi_closure_SYSV:
+USCORE_SYMBOL(ffi_closure_SYSV):
+#endif
 .LFB3:
        pushl   %ebp
 .LCFI4:
@@ -678,7 +688,7 @@ _ffi_closure_SYSV:
        movl    %edx, 4(%esp)   /* args = __builtin_dwarf_cfa () */
        leal    -12(%ebp), %edx
        movl    %edx, (%esp)    /* &resp */
-       call    _ffi_closure_SYSV_inner
+       call    USCORE_SYMBOL(ffi_closure_SYSV_inner)
        movl    -12(%ebp), %ecx
 
 0:
@@ -789,11 +799,12 @@ _ffi_closure_SYSV:
 #define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
 #define CIF_FLAGS_OFFSET 20
         .balign 16
-       .globl  _ffi_closure_raw_THISCALL
-#ifndef __OS2__
+FFI_HIDDEN(ffi_closure_raw_THISCALL)
+       .globl  USCORE_SYMBOL(ffi_closure_raw_THISCALL)
+#if defined(X86_WIN32) && !defined(__OS2__)
        .def    _ffi_closure_raw_THISCALL;      .scl    2;      .type   32;     .endef
 #endif
-_ffi_closure_raw_THISCALL:
+USCORE_SYMBOL(ffi_closure_raw_THISCALL):
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %esi
@@ -805,11 +816,13 @@ _ffi_closure_raw_THISCALL:
        jmp     .stubraw
         # This assumes we are using gas.
         .balign 16
-       .globl  _ffi_closure_raw_SYSV
-#ifndef __OS2__
+#if defined(X86_WIN32)
+       .globl  USCORE_SYMBOL(ffi_closure_raw_SYSV)
+#if defined(X86_WIN32) && !defined(__OS2__)
        .def    _ffi_closure_raw_SYSV;  .scl    2;      .type   32;     .endef
 #endif
-_ffi_closure_raw_SYSV:
+USCORE_SYMBOL(ffi_closure_raw_SYSV):
+#endif /* defined(X86_WIN32) */
 .LFB4:
        pushl   %ebp
 .LCFI6:
@@ -925,11 +938,12 @@ _ffi_closure_raw_SYSV:
 
         # This assumes we are using gas.
        .balign 16
-       .globl  _ffi_closure_STDCALL
-#ifndef __OS2__
+FFI_HIDDEN(ffi_closure_STDCALL)
+       .globl  USCORE_SYMBOL(ffi_closure_STDCALL)
+#if defined(X86_WIN32) && !defined(__OS2__)
        .def    _ffi_closure_STDCALL;   .scl    2;      .type   32;     .endef
 #endif
-_ffi_closure_STDCALL:
+USCORE_SYMBOL(ffi_closure_STDCALL):
 .LFB5:
        pushl   %ebp
 .LCFI9:
@@ -942,7 +956,7 @@ _ffi_closure_STDCALL:
        movl    %edx, 4(%esp)   /* args */
        leal    -12(%ebp), %edx
        movl    %edx, (%esp)    /* &resp */
-       call    _ffi_closure_SYSV_inner
+       call    USCORE_SYMBOL(ffi_closure_SYSV_inner)
        movl    -12(%ebp), %ecx
 0:
        call    1f
@@ -1034,7 +1048,7 @@ _ffi_closure_STDCALL:
 .ffi_closure_STDCALL_end:
 .LFE5:
 
-#ifndef __OS2__
+#if defined(X86_WIN32) && !defined(__OS2__)
        .section        .eh_frame,"w"
 #endif
 .Lframe1:
@@ -1094,7 +1108,6 @@ _ffi_closure_STDCALL:
        .align 4
 .LEFDE1:
 
-
 .LSFDE3:
        .long   .LEFDE3-.LASFDE3        /* FDE Length */
 .LASFDE3:
index 2cc2e03..871d576 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: <twalljava@dev.java.net> */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 #include "ffitest.h"
 
 static void
@@ -23,6 +23,9 @@ closure_test_stdcall(ffi_cif* cif __UNUSED__, void* resp, void** args,
 
 }
 
+#ifndef _MSC_VER
+#define __stdcall __attribute__((stdcall))
+#endif
 typedef int (__stdcall *closure_test_type0)(int, int, int, int);
 
 int main (void)
index 33ce8b6..12a0a63 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: <ktietz@redhat.com> */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 #include "ffitest.h"
 
 static void
@@ -23,6 +23,9 @@ closure_test_thiscall(ffi_cif* cif __UNUSED__, void* resp, void** args,
 
 }
 
+#ifndef _MSC_VER
+#define __thiscall __attribute__((thiscall))
+#endif
 typedef int (__thiscall *closure_test_type0)(int, int, int, int);
 
 int main (void)
index cbc4724..2bac3b2 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 
index 7bdd0e1..e78018c 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 
index b5d606d..c3af801 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 
index 4adbe4d..de6f9bb 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 #include <float.h>
index d9038f4..e696c93 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 #include <float.h>
index 0d81061..465b6c3 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 
index 6fbcc87..2a14b96 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 
 #include "ffitest.h"
 
index b756f5a..6decf02 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 #include "ffitest.h"
 
 typedef struct
index 5d02285..17a4519 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: From the original ffitest.c  */
 
-/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */
+/* { dg-do run { target i?86-*-* } } */
 #include "ffitest.h"
 
 typedef struct