Mercurial > pub > dyncall > dyncall
diff dyncall/dyncall_callf.c @ 533:71c884e610f0
- integration of patches from Raphael Luba, Thekla, Inc.:
* integration of aggregate-by-value (struct, union) support patch for x64 (win and sysv)
* windows/x64 asm additions to specify how stack unwinds (help for debuggers, exception handling, etc.)
* see Changelog for details
- new calling convention modes for thiscalls (platform agnostic, was specific before)
* new signature character for platform agnostic thiscalls ('*' / DC_SIGCHAR_CC_THISCALL)
- dcCallF(), dcVCallF(), dcArgF() and dcVArgF():
* added support for aggregates-by-value (wasn't part of patch)
* change that those functions don't implicitly call dcReset() anymore, which was unflexible (breaking change)
- added macros to feature test implementation for aggregate-by-value and syscall support
- changed libdyncall_s.lib and libdyncallback_s.lib order in callback test makefiles, as some toolchains are picky about order
- doc:
* man page updates to describe aggregate interface
* manual overview changes to highlight platforms with aggregate-by-value support
- test/plain: replaced tests w/ old/stale sctruct interface with new aggregate one
author | Tassilo Philipp |
---|---|
date | Thu, 21 Apr 2022 13:35:47 +0200 |
parents | 78dfa2f9783a |
children |
line wrap: on
line diff
--- a/dyncall/dyncall_callf.c Sat Apr 16 15:00:58 2022 +0200 +++ b/dyncall/dyncall_callf.c Thu Apr 21 13:35:47 2022 +0200 @@ -6,7 +6,7 @@ Description: formatted call C interface (extension module) License: - Copyright (c) 2007-2018 Daniel Adler <dadler@uni-goettingen.de>, + Copyright (c) 2007-2022 Daniel Adler <dadler@uni-goettingen.de>, Tassilo Philipp <tphilipp@potion-studios.com> Permission to use, copy, modify, and distribute this software for any @@ -28,13 +28,24 @@ #include "dyncall_callf.h" +static void handle_mode(DCCallVM* vm, const DCsigchar** sigptr) +{ + if(*((*sigptr)+1) != '\0') { + DCint mode = dcGetModeFromCCSigChar(*(*sigptr)++); + if(mode != DC_ERROR_UNSUPPORTED_MODE) + dcMode(vm, mode); + } +} + + /* Shareable implementation for argument binding used in ArgF and CallF below. */ static void dcArgF_impl(DCCallVM* vm, const DCsigchar** sigptr, va_list args) { DCsigchar ch; - dcReset(vm); while((ch=*(*sigptr)++) != '\0' && ch != DC_SIGCHAR_ENDARG) { switch(ch) { + /* calling convention modes */ + case DC_SIGCHAR_CC_PREFIX: handle_mode(vm, sigptr); break; /* types */ case DC_SIGCHAR_BOOL: dcArgBool (vm, (DCbool) va_arg(args, DCint )); break; case DC_SIGCHAR_CHAR: dcArgChar (vm, (DCchar) va_arg(args, DCint )); break; @@ -51,14 +62,12 @@ case DC_SIGCHAR_DOUBLE: dcArgDouble (vm, (DCdouble) va_arg(args, DCdouble )); break; case DC_SIGCHAR_POINTER: dcArgPointer (vm, (DCpointer) va_arg(args, DCpointer )); break; case DC_SIGCHAR_STRING: dcArgPointer (vm, (DCpointer) va_arg(args, DCpointer )); break; - /* calling convention modes */ - case DC_SIGCHAR_CC_PREFIX: - if(*((*sigptr)+1) != '\0') { - DCint mode = dcGetModeFromCCSigChar(*(*sigptr)++); - if(mode != DC_ERROR_UNSUPPORTED_MODE) - dcMode(vm, mode); - } + case DC_SIGCHAR_AGGREGATE: { + /* aggregates expect 2 va args, a DCaggr*, then a ptr to the aggregate */ + DCaggr* ag = va_arg(args, DCaggr*); + dcArgAggr(vm, ag, va_arg(args, DCpointer)); break; + } } } } @@ -76,11 +85,66 @@ va_end(va); } + +/* msvc introduced C99'w va_copy() late (in 2013 w/ msvc 18.00); plan9 APE does + * not have it either; luckily given their va_list being only a ptr in both + * cases, work around the issue for older versions */ +#if (defined(DC__C_MSVC) || defined(DC__OS_Plan9)) && !defined(va_copy) + #define va_copy(dst, src) ((dst)=(src)) +#endif + + void dcVCallF(DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, va_list args) { + DCaggr* ret_ag = NULL; /* only needed for when func returns an aggregate */ const DCsigchar* ptr = signature; + + /* need preparatory call if return type is an aggregate, so check end of sig */ + /* @@@ugly */ + while(*ptr && ptr[1]) ++ptr; + if(*ptr == DC_SIGCHAR_AGGREGATE) { + va_list args_; + va_copy(args_, args); + + /* iterate va_list to get return type related args*/ + ptr = signature; + while(*ptr) { + switch(*ptr++) { + /* calling convention modes */ + case DC_SIGCHAR_CC_PREFIX: handle_mode(vm, &ptr); break; /* needs handling before dcBeginCallAggr */ + /* types */ + case DC_SIGCHAR_BOOL: + case DC_SIGCHAR_CHAR: + case DC_SIGCHAR_UCHAR: + case DC_SIGCHAR_SHORT: + case DC_SIGCHAR_USHORT: + case DC_SIGCHAR_INT: + case DC_SIGCHAR_UINT: va_arg(args_, DCint ); break; + case DC_SIGCHAR_LONG: + case DC_SIGCHAR_ULONG: va_arg(args_, DClong ); break; + case DC_SIGCHAR_LONGLONG: + case DC_SIGCHAR_ULONGLONG: va_arg(args_, DClonglong); break; + case DC_SIGCHAR_FLOAT: + case DC_SIGCHAR_DOUBLE: va_arg(args_, DCdouble ); break; + case DC_SIGCHAR_POINTER: + case DC_SIGCHAR_STRING: va_arg(args_, DCpointer ); break; + case DC_SIGCHAR_AGGREGATE: + /* aggregate as retval expects 2 more va args, a DCaggr*, then a ptr to the aggregate */ + ret_ag = va_arg(args_, DCaggr*); + result->p = va_arg(args_, DCpointer); + break; + } + } + dcBeginCallAggr(vm, ret_ag); + + va_end(args_); + } + + /* push args */ + ptr = signature; dcArgF_impl(vm, &ptr, args); + /* call */ switch(*ptr) { case DC_SIGCHAR_VOID: dcCallVoid (vm,funcptr); break; case DC_SIGCHAR_BOOL: result->B = dcCallBool (vm,funcptr); break; @@ -98,6 +162,10 @@ case DC_SIGCHAR_DOUBLE: result->d = dcCallDouble (vm,funcptr); break; case DC_SIGCHAR_POINTER: result->p = dcCallPointer (vm,funcptr); break; case DC_SIGCHAR_STRING: result->Z = (DCstring)dcCallPointer(vm,funcptr); break; + case DC_SIGCHAR_AGGREGATE: { + result->p = dcCallAggr(vm, funcptr, ret_ag, result->p); + break; + } } }