diff dyncall/dyncall.3 @ 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 52e87d4988e3
line wrap: on
line diff
--- a/dyncall/dyncall.3	Sat Apr 16 15:00:58 2022 +0200
+++ b/dyncall/dyncall.3	Thu Apr 21 13:35:47 2022 +0200
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2007-2020 Daniel Adler <dadler AT uni-goettingen DOT de>, 
+.\" Copyright (c) 2007-2022 Daniel Adler <dadler AT uni-goettingen DOT de>, 
 .\"                         Tassilo Philipp <tphilipp AT potion-studios DOT com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -47,6 +47,8 @@
 .Fn dcArgDouble "DCCallVM * vm" "DCdouble arg"
 .Ft void
 .Fn dcArgPointer "DCCallVM * vm" "DCpointer arg"
+.Ft void
+.Fn dcArgAggr "DCCallVM * vm" "const DCaggr * ag" "const void * value"
 .Ft DCvoid
 .Fn dcCallVoid "DCCallVM * vm" "DCpointer funcptr"
 .Ft DCbool
@@ -67,6 +69,10 @@
 .Fn dcCallDouble "DCCallVM * vm" "DCpointer funcptr"
 .Ft DCpointer
 .Fn dcCallPointer "DCCallVM * vm" "DCpointer funcptr"
+.Ft DCpointer
+.Fn dcCallAggr "DCCallVM * vm" "DCpointer funcptr" "const DCaggr * ag" "DCpointer ret"
+.Ft void
+.Fn dcBeginCallAggr "DCCallVM * vm" "const DCaggr * ag"
 .Ft void
 .Fn dcArgF "DCCallVM * vm" "const DCsigchar * signature" "..."
 .Ft void
@@ -75,6 +81,14 @@
 .Fn dcCallF "DCCallVM * vm" "DCValue * result" "DCpointer funcptr" "const DCsigchar * signature" "..."
 .Ft void
 .Fn dcVCallF "DCCallVM * vm" "DCValue * result" "DCpointer funcptr" "const DCsigchar * signature" "va_list args"
+.Ft DCaggr*
+.Fn dcNewAggr "DCsize maxFieldCount" "DCsize size"
+.Ft void
+.Fn dcAggrField "DCaggr* ag" "DCsigchar type" "DCint offset" "DCsize array_len" "..."
+.Ft void
+.Fn dcCloseAggr "DCaggr* ag"
+.Ft void
+.Fn dcFreeAggr "DCaggr* ag"
 .Sh DESCRIPTION
 The
 .Nm
@@ -95,7 +109,7 @@
 that nearly every platform comes with one or more distinct calling conventions, the
 .Nm
 library project intends to be a portable and open-source approach to the variety of
-compiler-specific binary interfaces, platform specific subtleties, and so on...
+compiler/toolchain/platform-specific binary interfaces subtleties, and so on...
 .Pp
 .Fn dcNewCallVM
 creates a new CallVM object, where
@@ -113,13 +127,13 @@
 .Pp
 .Fn dcReset
 resets the internal stack of arguments and prepares it for a new call. This
-function should be called after setting the call mode (using dcMode), but prior
-to binding arguments to the CallVM (except for when setting mode
-DC_SIGCHAR_CC_ELLIPSIS_VARARGS, which is used prior to binding varargs of
-variadic functions). Use it also when reusing a CallVM, as arguments don't get
-flushed automatically after a function call invocation.  Note: you should also
-call this function after initial creation of the a CallVM object, as
-dcNewCallVM doesn't do this, implicitly.
+function should be called after setting the initial/main call mode (using
+dcMode()), but prior to binding arguments to the CallVM (sometimes dcMode()
+calls are needed after pushing some args, e.g.  DC_SIGCHAR_CC_ELLIPSIS_VARARGS,
+which is used prior to binding varargs of variadic functions). Use it also when
+reusing a CallVM, as arguments don't get flushed automatically after a function
+call invocation. Note: you should also call this function after initial
+creation of the a CallVM object, as dcNewCallVM doesn't do this, implicitly.
 .Pp
 .Fn dcArgBool ,
 .Fn dcArgChar ,
@@ -128,9 +142,10 @@
 .Fn dcArgLong ,
 .Fn dcArgLongLong ,
 .Fn dcArgFloat ,
-.Fn dcArgDouble
+.Fn dcArgDouble ,
+.Fn dcArgPointer
 and
-.Fn dcArgPointer
+.Fn dcArgAggr
 are used to bind arguments of the named types to the CallVM object. Arguments should
 be bound in
 .Em "left to right"
@@ -144,16 +159,61 @@
 .Fn dcCallLong ,
 .Fn dcCallLongLong ,
 .Fn dcCallFloat ,
-.Fn dcCallDouble
+.Fn dcCallDouble ,
+.Fn dcCallPointer
 and
-.Fn dcCallPointer
-call the function with the bound arguments and returning the named type, where
+.Fn dcCallAggr
+call the function with the previously bound arguments and return the named
+type, where
 .Ar funcptr
 is a pointer to the function to call. After the invocation of the function
 call, the argument values are still bound to the CallVM and a second call
 using the same arguments can be issued. Call
-.Fn reset
-to clear the internal argument stack.
+.Fn dcReset
+(as described above) to clear the internal argument stack.
+.Pp
+The interfaces for passing and/or returning aggregates (struct, union) by value
+need to be explained as they are a bit more complex. Every such argument or
+return type needs some extra info describing its layout via a
+.Ft DCaggr
+structure (except for non-trivial C++ aggregates, see AGGREGATE DESCRIPTION for
+more information, below). Passing such arguments is then done by using
+.Fn dcArgAggr ,
+where
+.Ar ag
+is a pointer to the description and
+.Ar value
+is a pointer to the aggregate in question. Calling a function that returns an
+aggregate by value is done via two functions,
+.Fn dcBeginCallAggr ,
+which handles special cases to facilitate the implementation and
+.Sy must
+be called
+.Sy before
+pushing any arguments, and finally
+.Fn dcCallAggr
+where
+.Ar ag
+is a pointer to the description (for both calls) and
+.Ar ret
+points to memory large enough to hold the to be returned aggregate.
+.Fn dcCallAggr
+returns a pointer to
+.Ar ret .
+.Pp
+.Sy NOTE:
+C++ non-trivial aggregates (check with the std::is_trivial type trait) need
+some special handling. First of all, no aggregate description is needed and
+NULL must be passed wherever a
+.Ft DCaggr*
+argument is needed. Also, as
+.Nm
+is oblivious to how to do any custom/non-trivial construction or copy, and thus
+cannot do the copy of the aggregate, passed by-value, itself, the user has to
+provide such copies, where needed. E.g. when passing such an aggregate as an
+argument by-value, using
+.Fn dcArgAggr ,
+in order to preserver the call's by-value semantics.
 .Pp
 .Fn dcArgF ,
 .Fn dcVArgF ,
@@ -161,7 +221,7 @@
 and
 .Fn dcVCallF
 can be used to bind arguments in a printf-style call, using a signature
-string encoding the argument types and return type. The former 2 only bind
+string encoding the argument and return types. The former 2 only bind
 the arguments to the
 .Ar vm
 object (and ignore return types specified in the
@@ -169,9 +229,60 @@
 afterwards. The return value will be stored in
 .Ar result .
 The signature string also features calling convention mode selection.
-For information about the signature format, refer to the
+For information about the signature format, refer to dyncall_signature.h or the
 .Nm
-manual in PDF format.
+manual.
+.Pp
+For passing aggregates using
+.Fn dc*F
+functions, pass two varargs for each aggregate, first a pointer to DCaggr, then
+a pointer to the aggregate in question. For returning aggregates using those
+functions, pass
+.Sy two final extra
+arguments, first a pointer to DCaggr describing the return value, then a
+pointer to memory large enough to hold it. An explicit call do
+.Fn dcBeginCallAggr
+is not needed in those cases, and a pointer to the to be returned aggregate is
+returned via
+.Ar result .
+.Sh AGGREGATE DESCRIPTION
+In order to describe an aggregate (except for C++ non-trivial aggregates, as
+mentioned above), create a DCaggr object using
+.Fn dcNewAggr ,
+where
+.Ar maxFieldCount
+is greater or equal to the number of fields the aggregate has (a nested
+aggregate or an array is counted as one field), and
+.Ar size
+is the size of the aggregate (e.g. as determined by sizeof()).
+.Pp
+.Fn dcFreeAggr
+destroys the DCaggr object.
+.Pp
+.Fn dcAggrField
+is used to describe the aggregate, field-by-field (in order), with
+.Ar type
+being a DC_SIGCHAR_* (see dyncall_signature.h),
+.Ar offset
+being the offset of the field from the beginning of the aggregate (use C's
+offsetof(3)), and
+.Ar array_len
+being the number of array elements,
+.Sy iff
+the field is an array, otherwise use 1. For nested aggregates (when using
+DC_SIGCHAR_AGGREGATE as
+.Ft type ) ,
+one needs to pass the pointer to the nested aggregate's DCaggr object as last
+argument (in
+.Ar ... ) .
+.Pp
+Call
+.Fn dcCloseAggr
+after having described all fields of an aggregate.
+.Pp
+Note that c99 flexible array members do not count as a field, and must be
+omitted, as passing aggregates with a flexible array member by value in C would
+also omit it.
 .Sh EXAMPLE
 Let's say, we want to make a call to the function:
 .Bd -literal -offset indent