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
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
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;
)
{
*(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)
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*). */
#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. */
#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;
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
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;
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);
__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
&ffi_closure_SYSV,
(void*)codeloc);
}
-#ifdef X86_WIN32
else if (cif->abi == FFI_THISCALL)
{
FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
&ffi_closure_STDCALL,
(void*)codeloc, cif->bytes);
}
+#ifdef X86_WIN32
else if (cif->abi == FFI_MS_CDECL)
{
FFI_INIT_TRAMPOLINE (&closure->tramp[0],
{
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
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)
{
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;
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);
/* ---- 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
#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
#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:
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
# 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:
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:
#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
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:
# 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:
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
.ffi_closure_STDCALL_end:
.LFE5:
-#ifndef __OS2__
+#if defined(X86_WIN32) && !defined(__OS2__)
.section .eh_frame,"w"
#endif
.Lframe1:
.align 4
.LEFDE1:
-
.LSFDE3:
.long .LEFDE3-.LASFDE3 /* FDE Length */
.LASFDE3:
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
}
+#ifndef _MSC_VER
+#define __stdcall __attribute__((stdcall))
+#endif
typedef int (__stdcall *closure_test_type0)(int, int, int, int);
int main (void)
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
}
+#ifndef _MSC_VER
+#define __thiscall __attribute__((thiscall))
+#endif
typedef int (__thiscall *closure_test_type0)(int, int, int, int);
int main (void)
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"
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"
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"
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>
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>
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"
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"
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
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