view 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 source

.\" 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
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate$
.Dt dyncall 3
.Sh NAME
.Nm dyncall
.Nd encapsulation of architecture-, OS- and compiler-specific function call
semantics 
.Sh SYNOPSIS
.In dyncall.h
.Ft DCCallVM *
.Fn dcNewCallVM "DCsize size"
.Ft void
.Fn dcFree "DCCallVM * vm"
.Ft void
.Fn dcMode "DCCallVM * vm" "DCint mode"
.Ft void
.Fn dcReset "DCCallVM * vm"
.Ft void
.Fn dcArgBool "DCCallVM * vm" "DCbool arg"
.Ft void
.Fn dcArgChar "DCCallVM * vm" "DCchar arg"
.Ft void
.Fn dcArgShort "DCCallVM * vm" "DCshort arg"
.Ft void
.Fn dcArgInt "DCCallVM * vm" "DCint arg"
.Ft void
.Fn dcArgLong "DCCallVM * vm" "DClong arg"
.Ft void
.Fn dcArgLongLong "DCCallVM * vm" "DClonglong arg"
.Ft void
.Fn dcArgFloat "DCCallVM * vm" "DCfloat arg"
.Ft void
.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
.Fn dcCallBool "DCCallVM * vm" "DCpointer funcptr"
.Ft DCchar
.Fn dcCallChar "DCCallVM * vm" "DCpointer funcptr"
.Ft DCshort
.Fn dcCallShort "DCCallVM * vm" "DCpointer funcptr"
.Ft DCint
.Fn dcCallInt "DCCallVM * vm" "DCpointer funcptr"
.Ft DClong
.Fn dcCallLong "DCCallVM * vm" "DCpointer funcptr"
.Ft DClonglong
.Fn dcCallLongLong "DCCallVM * vm" "DCpointer funcptr"
.Ft DCfloat
.Fn dcCallFloat "DCCallVM * vm" "DCpointer funcptr"
.Ft DCdouble
.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
.Fn dcVArgF "DCCallVM * vm" "const DCsigchar * signature" "va_list args"
.Ft void
.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
library encapsulates architecture-, OS- and compiler-specific function call
semantics in a virtual "bind argument parameters from left to right and then
call" interface allowing programmers to call C functions in a completely
dynamic manner.
.Pp
In other words, instead of calling a function directly, the
.Nm
library provides a mechanism to push the function parameters manually and to
issue the call afterwards.
.Pp
Since the idea behind this concept is similar to call dispatching mechanisms
of virtual machines, the object that can be dynamically loaded with arguments,
and then used to actually invoke the call, is called CallVM. It is possible to
change the calling convention used by the CallVM at run-time. Due to the fact
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/toolchain/platform-specific binary interfaces subtleties, and so on...
.Pp
.Fn dcNewCallVM
creates a new CallVM object, where
.Ar size
specifies the max size of the internal stack that will be allocated and used to
bind the arguments to. Use
.Fn dcFree
to destroy the CallVM object.
.Pp
.Fn dcMode
sets the calling convention to use. See dyncall.h for a list of
available modes. Note that some mode/platform combinations don't make any
sense (e.g. using a PowerPC calling convention on a MIPS platform) and are
silently ignored.
.Pp
.Fn dcReset
resets the internal stack of arguments and prepares it for a new call. This
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 ,
.Fn dcArgShort ,
.Fn dcArgInt ,
.Fn dcArgLong ,
.Fn dcArgLongLong ,
.Fn dcArgFloat ,
.Fn dcArgDouble ,
.Fn dcArgPointer
and
.Fn dcArgAggr
are used to bind arguments of the named types to the CallVM object. Arguments should
be bound in
.Em "left to right"
order regarding the C function prototype.
.Pp
.Fn dcCallVoid ,
.Fn dcCallBool ,
.Fn dcCallChar ,
.Fn dcCallShort ,
.Fn dcCallInt ,
.Fn dcCallLong ,
.Fn dcCallLongLong ,
.Fn dcCallFloat ,
.Fn dcCallDouble ,
.Fn dcCallPointer
and
.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 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 ,
.Fn dcCallF
and
.Fn dcVCallF
can be used to bind arguments in a printf-style call, using a signature
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
signature), whereas the latter two issue a call to the given function pointer,
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 dyncall_signature.h or the
.Nm
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
	double sqrt(double x); 
.Ed
.Pp
Using the
.Nm
library, this function would be called as follows: 
.Bd -literal -offset indent
	double r;
	DCCallVM* vm = dcNewCallVM(4096);
	dcMode(vm, DC_CALL_C_DEFAULT);
	dcReset(vm);
	dcArgDouble(vm, 4.2373);
	r = dcCallDouble(vm, (DCpointer)&sqrt);
	dcFree(vm);
.Ed
.Sh CONFORMING TO
The dyncall library needs at least a c99 compiler with additional support for
anonymous structs/unions (which were introduced officially in c11). Given that
those are generally supported by pretty much all major c99 conforming compilers
(as default extension), it should build fine with a c99 toolchain. Strictly
speaking, dyncall conforms to c11, though.
.Ed
.Sh SEE ALSO
.Xr dyncallback 3 ,
.Xr dynload 3
and the
.Nm
manual (available in HTML and PDF format) for more information.
.Sh AUTHORS
.An "Daniel Adler" Aq dadler@uni-goettingen.de
.An "Tassilo Philipp" Aq tphilipp@potion-studios.com