From eb3c46a17ebe3dfe1b374d40f8a8296a83e24751 Mon Sep 17 00:00:00 2001 From: Ranjit Mathew Date: Fri, 6 Dec 2002 01:16:45 +0000 Subject: [PATCH] ffi.h.in: Added FFI_STDCALL ffi_type enumeration for X86_WIN32. 2002-11-10 Ranjit Mathew * include/ffi.h.in: Added FFI_STDCALL ffi_type enumeration for X86_WIN32. * src/x86/win32.S: Added ffi_call_STDCALL function definition. * src/x86/ffi.c (ffi_call/ffi_raw_call): Added switch cases for recognising FFI_STDCALL and calling ffi_call_STDCALL if target is X86_WIN32. * src/ffitest.c (my_stdcall_strlen/stdcall_many): stdcall versions of the "my_strlen" and "many" test functions (for X86_WIN32). Added test cases to test stdcall invocation using these functions. From-SVN: r59878 --- libffi/ChangeLog | 15 ++++++ libffi/include/ffi.h.in | 4 +- libffi/src/ffitest.c | 89 +++++++++++++++++++++++++++++++++- libffi/src/x86/ffi.c | 42 +++++++++++++++- libffi/src/x86/win32.S | 105 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 250 insertions(+), 5 deletions(-) diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 423c4b058fb..8ed3398ea1e 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,18 @@ +2002-11-10 Ranjit Mathew + + * include/ffi.h.in: Added FFI_STDCALL ffi_type + enumeration for X86_WIN32. + * src/x86/win32.S: Added ffi_call_STDCALL function + definition. + * src/x86/ffi.c (ffi_call/ffi_raw_call): Added + switch cases for recognising FFI_STDCALL and + calling ffi_call_STDCALL if target is X86_WIN32. + * src/ffitest.c (my_stdcall_strlen/stdcall_many): + stdcall versions of the "my_strlen" and "many" + test functions (for X86_WIN32). + Added test cases to test stdcall invocation using + these functions. + 2002-11-27 Ulrich Weigand * src/s390/sysv.S (.eh_frame section): Make section read-only. diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in index 4f7667e6d4d..c660ede75af 100644 --- a/libffi/include/ffi.h.in +++ b/libffi/include/ffi.h.in @@ -198,6 +198,8 @@ typedef enum ffi_abi { /* ---- Intel x86 Win32 ---------- */ #ifdef X86_WIN32 FFI_SYSV, + FFI_STDCALL, + /* TODO: Add fastcall support for the sake of completeness */ FFI_DEFAULT_ABI = FFI_SYSV, #endif @@ -287,7 +289,7 @@ typedef struct _ffi_type /*@null@*/ struct _ffi_type **elements; } ffi_type; -/* These are defined in ffi.c */ +/* These are defined in types.c */ extern ffi_type ffi_type_void; extern ffi_type ffi_type_uint8; extern ffi_type ffi_type_sint8; diff --git a/libffi/src/ffitest.c b/libffi/src/ffitest.c index 163c4a8c36e..da528317bb3 100644 --- a/libffi/src/ffitest.c +++ b/libffi/src/ffitest.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- - ffitest.c - Copyright (c) 1996, 1997, 1998 Cygnus Solutions + ffitest.c - Copyright (c) 1996, 1997, 1998, 2002 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -49,6 +49,13 @@ static size_t my_strlen(char *s) return (strlen(s)); } +#ifdef X86_WIN32 +static size_t __attribute__((stdcall)) my_stdcall_strlen(char *s) +{ + return (strlen(s)); +} +#endif /* X86_WIN32 */ + static int promotion(signed char sc, signed short ss, unsigned char uc, unsigned short us) { @@ -112,6 +119,25 @@ static float many(float f1, return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); } +#ifdef X86_WIN32 +static float __attribute__((stdcall)) stdcall_many(float f1, + float f2, + float f3, + float f4, + float f5, + float f6, + float f7, + float f8, + float f9, + float f10, + float f11, + float f12, + float f13) +{ + return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} +#endif /* X86_WIN32 */ + static double dblit(float f) { return f/3.0; @@ -954,6 +980,67 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) printf("Structure passing doesn't work on Win32.\n"); #endif /* X86_WIN32 */ +#ifdef X86_WIN32 + /* stdcall strlen tests */ + { + args[0] = &ffi_type_pointer; + values[0] = (void*) &s; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 1, + &ffi_type_sint, args) == FFI_OK); + + s = "a"; + ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); + CHECK(rint == 1); + + s = "1234567"; + ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); + CHECK(rint == 7); + + s = "1234567890123456789012345"; + ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); + CHECK(rint == 25); + + printf("stdcall strlen tests passed\n"); + } + + /* stdcall many arg tests */ + { + float ff; + float fa[13]; + + for (ul = 0; ul < 13; ul++) + { + args[ul] = &ffi_type_float; + values[ul] = &fa[ul]; + fa[ul] = (float) ul; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 13, + &ffi_type_float, args) == FFI_OK); + + /*@-usedef@*/ + ff = stdcall_many(fa[0], fa[1], + fa[2], fa[3], + fa[4], fa[5], + fa[6], fa[7], + fa[8], fa[9], + fa[10],fa[11],fa[12]); + /*@=usedef@*/ + + ffi_call(&cif, FFI_FN(stdcall_many), &f, values); + + /*@-realcompare@*/ + if (f - ff < FLT_EPSILON) + /*@=realcompare@*/ + printf("stdcall many arg tests ok!\n"); + else + CHECK(0); + } +#endif /* X86_WIN32 */ + # if FFI_CLOSURES /* A simple closure test */ { diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c index 77193250311..68135f97c35 100644 --- a/libffi/src/x86/ffi.c +++ b/libffi/src/x86/ffi.c @@ -1,5 +1,8 @@ /* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 1996, 1998, 1999 Cygnus Solutions + ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle x86 Foreign Function Interface @@ -148,6 +151,18 @@ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), /*@=declundef@*/ /*@=exportheader@*/ +#ifdef X86_WIN32 +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ +#endif /* X86_WIN32 */ + void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, @@ -180,6 +195,14 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; +#ifdef X86_WIN32 + case FFI_STDCALL: + /*@-usedef@*/ + ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif /* X86_WIN32 */ default: FFI_ASSERT(0); break; @@ -448,6 +471,15 @@ ffi_call_SYSV(void (*)(char *, extended_cif *), /*@out@*/ unsigned *, void (*fn)()); +#ifdef X86_WIN32 +extern void +ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +#endif /* X86_WIN32 */ + void ffi_raw_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), @@ -482,6 +514,14 @@ ffi_raw_call(/*@dependent@*/ ffi_cif *cif, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; +#ifdef X86_WIN32 + case FFI_STDCALL: + /*@-usedef@*/ + ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif /* X86_WIN32 */ default: FFI_ASSERT(0); break; diff --git a/libffi/src/x86/win32.S b/libffi/src/x86/win32.S index 520d1fc0898..796af18754b 100644 --- a/libffi/src/x86/win32.S +++ b/libffi/src/x86/win32.S @@ -1,5 +1,8 @@ /* ----------------------------------------------------------------------- - win32.S - Copyright (c) 1996, 1998, 2001 Cygnus Solutions + win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. + Copyright (c) 2001 John Beniton + Copyright (c) 2002 Ranjit Mathew + X86 Foreign Function Interface @@ -52,7 +55,10 @@ _ffi_call_SYSV: # Return stack to previous state and call the function addl $8,%esp - call *28(%ebp) + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) # Remove the space we pushed for the args movl 16(%ebp),%ecx @@ -123,3 +129,98 @@ epilogue: ret .ffi_call_SYSV_end: + + # This assumes we are using gas. + .balign 16 +.globl _ffi_call_STDCALL + +_ffi_call_STDCALL: + pushl %ebp + movl %esp,%ebp + + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) + + # stdcall functions pop arguments off the stack themselves + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne sc_retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne sc_noretval + fstp %st(0) + + jmp sc_epilogue + +sc_retint: + cmpl $FFI_TYPE_INT,%ecx + jne sc_retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp sc_epilogue + +sc_retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne sc_retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp sc_epilogue + +sc_retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne sc_retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp sc_epilogue + +sc_retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne sc_retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp sc_epilogue + +sc_retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne sc_retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +sc_retstruct: + # Nothing to do! + +sc_noretval: +sc_epilogue: + movl %ebp,%esp + popl %ebp + ret + +.ffi_call_STDCALL_end: