This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
[PATCH 6/6 try 2] Add Microsoftian variant of the cdecl ABI
- From: Peter Rosin <peda at lysator dot liu dot se>
- To: libffi-discuss at sourceware dot org
- Cc: Peter Rosin <peda at lysator dot liu dot se>
- Date: Thu, 29 Mar 2012 20:20:59 +0200
- Subject: [PATCH 6/6 try 2] Add Microsoftian variant of the cdecl ABI
- References: <1332458731-15004-7-git-send-email-peda@lysator.liu.se>
---
ChangeLog | 19 +++++++++++++++++++
src/x86/ffi.c | 27 +++++++++++++++++++++------
src/x86/ffitarget.h | 7 ++++++-
src/x86/win32.S | 18 ++++++++++++++++++
4 files changed, 64 insertions(+), 7 deletions(-)
Hi!
This is an update so that it applies cleanly after the latest merge
and it also fixes a spelling mistake in the ChnageLog.
Cheers,
Peter
diff --git a/ChangeLog b/ChangeLog
index 7b8e2e9..466af62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2012-03-29 Peter Rosin <peda@lysator.liu.se>
+
+ * src/x86/ffitarget.h (ffi_abi): Add new ABI FFI_MS_CDECL and
+ make it the default for MSVC.
+ (FFI_TYPE_MS_STRUCT): New structure return convention.
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Tweak the structure
+ return convention for FFI_MS_CDECL to be FFI_TYPE_MS_STRUCT
+ instead of an ordinary FFI_TYPE_STRUCT.
+ (ffi_prep_args): Treat FFI_TYPE_MS_STRUCT as FFI_TYPE_STRUCT.
+ (ffi_call): Likewise.
+ (ffi_prep_incoming_args_SYSV): Likewise.
+ (ffi_raw_call): Likewise.
+ (ffi_prep_closure_loc): Treat FFI_MS_CDECL as FFI_SYSV.
+ * src/x86/win32.S (ffi_closure_SYSV): For FFI_TYPE_MS_STRUCT,
+ return a pointer to the result structure in eax and don't pop
+ that pointer from the stack, the caller takes care of it.
+ (ffi_call_win32): Treat FFI_TYPE_MS_STRUCT as FFI_TYPE_STRUCT.
+ (ffi_closure_raw_SYSV): Likewise.
+
2012-03-21 Peter Rosin <peda@lysator.liu.se>
* testsuite/libffi.call/float_va.c (float_va_fn): Use %f when
diff --git a/src/x86/ffi.c b/src/x86/ffi.c
index f643b34..22e2997 100644
--- a/src/x86/ffi.c
+++ b/src/x86/ffi.c
@@ -58,7 +58,8 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
argp = stack;
- if (ecif->cif->flags == FFI_TYPE_STRUCT
+ if ((ecif->cif->flags == FFI_TYPE_STRUCT
+ || ecif->cif->flags == FFI_TYPE_MS_STRUCT)
#ifdef X86_WIN64
&& (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
&& ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
@@ -279,7 +280,10 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
else
#endif
{
- cif->flags = FFI_TYPE_STRUCT;
+ if (cif->abi == FFI_MS_CDECL)
+ cif->flags = FFI_TYPE_MS_STRUCT;
+ else
+ cif->flags = FFI_TYPE_STRUCT;
/* allocate space for return value pointer */
cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
}
@@ -349,7 +353,8 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
#else
if (rvalue == NULL
- && cif->flags == FFI_TYPE_STRUCT)
+ && (cif->flags == FFI_TYPE_STRUCT
+ || cif->flags == FFI_TYPE_MS_STRUCT))
{
ecif.rvalue = alloca(cif->rtype->size);
}
@@ -368,6 +373,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
#elif defined(X86_WIN32)
case FFI_SYSV:
case FFI_STDCALL:
+ case FFI_MS_CDECL:
ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
@@ -513,7 +519,8 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
argp += sizeof(void *);
}
#else
- if ( cif->flags == FFI_TYPE_STRUCT ) {
+ if ( cif->flags == FFI_TYPE_STRUCT
+ || cif->flags == FFI_TYPE_MS_STRUCT ) {
*rvalue = *(void **) argp;
argp += sizeof(void *);
}
@@ -673,6 +680,12 @@ ffi_prep_closure_loc (ffi_closure* closure,
&ffi_closure_STDCALL,
(void*)codeloc, cif->bytes);
}
+ else if (cif->abi == FFI_MS_CDECL)
+ {
+ FFI_INIT_TRAMPOLINE (&closure->tramp[0],
+ &ffi_closure_SYSV,
+ (void*)codeloc);
+ }
#endif /* X86_WIN32 */
#endif /* !X86_WIN64 */
else
@@ -762,8 +775,9 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
- if ((rvalue == NULL) &&
- (cif->rtype->type == FFI_TYPE_STRUCT))
+ if (rvalue == NULL
+ && (cif->flags == FFI_TYPE_STRUCT
+ || cif->flags == FFI_TYPE_MS_STRUCT))
{
ecif.rvalue = alloca(cif->rtype->size);
}
@@ -776,6 +790,7 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
#ifdef X86_WIN32
case FFI_SYSV:
case FFI_STDCALL:
+ case FFI_MS_CDECL:
ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
diff --git a/src/x86/ffitarget.h b/src/x86/ffitarget.h
index 54a6121..f442654 100644
--- a/src/x86/ffitarget.h
+++ b/src/x86/ffitarget.h
@@ -80,9 +80,13 @@ typedef enum ffi_abi {
FFI_STDCALL,
FFI_THISCALL,
FFI_FASTCALL,
+ FFI_MS_CDECL,
FFI_LAST_ABI,
- /* TODO: Add fastcall support for the sake of completeness */
+#ifdef _MSC_VER
+ FFI_DEFAULT_ABI = FFI_MS_CDECL
+#else
FFI_DEFAULT_ABI = FFI_SYSV
+#endif
#elif defined(X86_WIN64)
FFI_WIN64,
@@ -109,6 +113,7 @@ typedef enum ffi_abi {
#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
+#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
#define FFI_TRAMPOLINE_SIZE 24
diff --git a/src/x86/win32.S b/src/x86/win32.S
index 7eec4f3..a4e9fde 100644
--- a/src/x86/win32.S
+++ b/src/x86/win32.S
@@ -121,6 +121,7 @@ ca_jumpdata:
dd offset ca_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset ca_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B
+ dd offset ca_epilogue ;; FFI_TYPE_MS_STRUCT
ca_retint8:
;; Load %ecx with the pointer to storage for the return value
@@ -217,6 +218,7 @@ cs_jumpdata:
dd offset cs_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cs_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B
+ dd offset cs_retmsstruct ;; FFI_TYPE_MS_STRUCT
cs_retint8:
mov al, [ecx]
@@ -252,6 +254,12 @@ cs_retstruct:
;; Epilogue code is autogenerated.
ret 4
+cs_retmsstruct:
+ ;; Caller expects us to return a pointer to the real return value.
+ mov eax, ecx
+ ;; Caller doesn't expects us to pop struct return value pointer hidden arg.
+ jmp cs_epilogue
+
cs_epilogue:
;; Epilogue code is autogenerated.
ret
@@ -315,6 +323,7 @@ cr_jumpdata:
dd offset cr_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cr_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B
+ dd offset cr_epilogue ;; FFI_TYPE_MS_STRUCT
cr_retint8:
mov al, [ecx]
@@ -515,6 +524,7 @@ _ffi_call_win32:
.long .Lretstruct1b /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lretstruct2b /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lretstruct4b /* FFI_TYPE_SMALL_STRUCT_4B */
+ .long .Lretstruct /* FFI_TYPE_MS_STRUCT */
1:
add %ecx, %ecx
add %ecx, %ecx
@@ -657,6 +667,7 @@ _ffi_closure_SYSV:
.long .Lcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */
+ .long .Lcls_retmsstruct /* FFI_TYPE_MS_STRUCT */
1:
add %eax, %eax
@@ -721,6 +732,12 @@ _ffi_closure_SYSV:
popl %ebp
ret $0x4
+.Lcls_retmsstruct:
+ # Caller expects us to return a pointer to the real return value.
+ mov %ecx, %eax
+ # Caller doesn't expects us to pop struct return value pointer hidden arg.
+ jmp .Lcls_epilogue
+
.Lcls_noretval:
.Lcls_epilogue:
movl %ebp, %esp
@@ -798,6 +815,7 @@ _ffi_closure_raw_SYSV:
.long .Lrcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lrcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lrcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */
+ .long .Lrcls_retstruct /* FFI_TYPE_MS_STRUCT */
1:
add %eax, %eax
add %eax, %eax
--
1.7.9