Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
NAME
       dyncall	--  encapsulation  of architecture-, OS- and compiler-specific
       function	call semantics

SYNOPSIS
       #include	<dyncall.h>

       DCCallVM	*
       dcNewCallVM(DCsize size);

       void
       dcFree(DCCallVM * vm);

       void
       dcMode(DCCallVM * vm, DCint mode);

       void
       dcReset(DCCallVM	* vm);

       void
       dcArgBool(DCCallVM * vm,	DCbool arg);

       void
       dcArgChar(DCCallVM * vm,	DCchar arg);

       void
       dcArgShort(DCCallVM * vm, DCshort arg);

       void
       dcArgInt(DCCallVM * vm, DCint arg);

       void
       dcArgLong(DCCallVM * vm,	DClong arg);

       void
       dcArgLongLong(DCCallVM *	vm, DClonglong arg);

       void
       dcArgFloat(DCCallVM * vm, DCfloat arg);

       void
       dcArgDouble(DCCallVM * vm, DCdouble arg);

       void
       dcArgPointer(DCCallVM * vm, DCpointer arg);

       void
       dcArgAggr(DCCallVM * vm,	const DCaggr * ag, const void *	value);

       DCvoid
       dcCallVoid(DCCallVM * vm, DCpointer funcptr);

       DCbool
       dcCallBool(DCCallVM * vm, DCpointer funcptr);

       DCchar
       dcCallChar(DCCallVM * vm, DCpointer funcptr);

       DCshort
       dcCallShort(DCCallVM * vm, DCpointer funcptr);

       DCint
       dcCallInt(DCCallVM * vm,	DCpointer funcptr);

       DClong
       dcCallLong(DCCallVM * vm, DCpointer funcptr);

       DClonglong
       dcCallLongLong(DCCallVM * vm, DCpointer funcptr);

       DCfloat
       dcCallFloat(DCCallVM * vm, DCpointer funcptr);

       DCdouble
       dcCallDouble(DCCallVM * vm, DCpointer funcptr);

       DCpointer
       dcCallPointer(DCCallVM *	vm, DCpointer funcptr);

       DCpointer
       dcCallAggr(DCCallVM  *  vm,  DCpointer  funcptr,	 const	DCaggr	*  ag,
	   DCpointer ret);

       void
       dcBeginCallAggr(DCCallVM	* vm, const DCaggr * ag);

       void
       dcArgF(DCCallVM * vm, const DCsigchar * signature, ...);

       void
       dcVArgF(DCCallVM	* vm, const DCsigchar *	signature, va_list args);

       void
       dcCallF(DCCallVM	  *   vm,   DCValue   *	  result,  DCpointer  funcptr,
	   const DCsigchar * signature,	...);

       void
       dcVCallF(DCCallVM  *  vm,  DCValue   *	result,	  DCpointer   funcptr,
	   const DCsigchar * signature,	va_list	args);

       DCaggr*
       dcNewAggr(DCsize	maxFieldCount, DCsize size);

       void
       dcAggrField(DCaggr* ag, DCsigchar type, DCint offset, DCsize array_len,
	   ...);

       void
       dcCloseAggr(DCaggr* ag);

       void
       dcFreeAggr(DCaggr* ag);

DESCRIPTION
       The  dyncall  library encapsulates architecture-, OS- and compiler-spe-
       cific 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.

       In other	words, instead of calling a function directly, the dyncall li-
       brary provides a	mechanism to push the function parameters manually and
       to issue	the call afterwards.

       Since the idea behind this concept is similar to	call dispatching mech-
       anisms 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  dyncall  library
       project	intends	to be a	portable and open-source approach to the vari-
       ety  of	compiler/toolchain/platform-specific  binary  interfaces  sub-
       tleties,	and so on...

       dcNewCallVM() creates a new CallVM object, where	size specifies the max
       size  of	the internal stack that	will be	allocated and used to bind the
       arguments to. Use dcFree() to destroy the CallVM	object.

       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 plat-
       form) and are silently ignored.

       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 Cal-
       lVM (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 Cal-
       lVM object, as dcNewCallVM doesn't do this, implicitly.

       dcArgBool(),  dcArgChar(),   dcArgShort(),   dcArgInt(),	  dcArgLong(),
       dcArgLongLong(),	  dcArgFloat(),	  dcArgDouble(),   dcArgPointer()  and
       dcArgAggr() are used to bind arguments of the named types to the	CallVM
       object. Arguments should	be bound in left to right order	regarding  the
       C function prototype.

       dcCallVoid(),  dcCallBool(),  dcCallChar(), dcCallShort(), dcCallInt(),
       dcCallLong(),	dcCallLongLong(),    dcCallFloat(),    dcCallDouble(),
       dcCallPointer()	and dcCallAggr() call the function with	the previously
       bound arguments and return the named type, where	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 dcReset()	(as  described	above)
       to clear	the internal argument stack.

       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 lay-
       out via a DCaggr	structure (except for non-trivial C++ aggregates,  see
       AGGREGATE  DESCRIPTION for more information, below). Passing such argu-
       ments is	then done by using dcArgAggr(),	where ag is a pointer  to  the
       description  and	value is a pointer to the aggregate in question. Call-
       ing a function that returns an aggregate	by value is done via two func-
       tions, dcBeginCallAggr(), which handles special cases to	facilitate the
       implementation and must be called before	pushing	any arguments, and fi-
       nally dcCallAggr() where	ag is a	pointer	to the description  (for  both
       calls) and ret points to	memory large enough to hold the	to be returned
       aggregate.  dcCallAggr()	returns	a pointer to ret.

       NOTE:  C++  non-trivial aggregates (check with the std::is_trivial type
       trait) need some	special	handling. First	of all,	no aggregate  descrip-
       tion  is	 needed	and NULL must be passed	wherever a DCaggr* argument is
       needed. Also, as	dyncall	is oblivious to	how to do any custom/non-triv-
       ial construction	or copy, and thus cannot do the	copy of	the aggregate,
       passed by-value,	itself,	the user has to	provide	such copies, manually,
       where needed (e.g. when passing such an aggregate as  an	 argument  by-
       value, using dcArgAggr(), in order to preserver the call's by-value se-
       mantics).

       dcArgF(), dcVArgF(), dcCallF() and dcVCallF() can be used to bind argu-
       ments in	a printf-style call, using a signature string encoding the ar-
       gument and return types.	The former 2 only bind the arguments to	the 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 result.  The signature string also
       features	calling	convention mode	selection.  For	information about  the
       signature format, refer to dyncall_signature.h or the dyncall manual.

       For  passing  aggregates	 using	dc*F() functions, pass two varargs for
       each aggregate, first a pointer to DCaggr, then a pointer to the	aggre-
       gate in question. For returning aggregates using	those functions,  pass
       two final extra arguments, first	a pointer to DCaggr describing the re-
       turn  value,  then  a pointer to	memory large enough to hold it.	An ex-
       plicit call do dcBeginCallAggr()	is not needed in those	cases,	and  a
       pointer to the to be returned aggregate is returned via result.

AGGREGATE DESCRIPTION
       In  order  to  describe an aggregate (except for	C++ non-trivial	aggre-
       gates, as mentioned above), create a DCaggr object  using  dcNewAggr(),
       where maxFieldCount is greater or equal to the number of	fields the ag-
       gregate	has  (a	nested aggregate or an array is	counted	as one field),
       and size	is the size of the aggregate (e.g. as determined by sizeof()).

       dcFreeAggr() destroys the DCaggr	object.

       dcAggrField() is	used to	describe the aggregate,	field-by-field (in or-
       der), with type being a DC_SIGCHAR_* (see dyncall_signature.h),	offset
       being  the offset of the	field from the beginning of the	aggregate (use
       C's offsetof(3)), and array_len being the number	of array elements, iff
       the field is an array, otherwise	use 1. For nested aggregates (when us-
       ing DC_SIGCHAR_AGGREGATE	as type), one needs to pass the	pointer	to the
       nested aggregate's DCaggr object	as last	argument (in ...).

       Call dcCloseAggr() after	having described all fields of an aggregate.

       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.

EXAMPLES
       Note:  none  of	the examples below perform any error checking for sim-
       plicity of the example.

       Let's start with	a simple  example,  making  a  call  to	 the  function
       sqrt(3).	  Using	 the dyncall library, this function would be called as
       follows:

	     double r;
	     DCCallVM* vm = dcNewCallVM(4096);
	     dcMode(vm,	DC_CALL_C_DEFAULT);
	     dcReset(vm);
	     /*	call: double sqrt(double x); */
	     dcArgDouble(vm, 4.2373);
	     r = dcCallDouble(vm, (DCpointer)&sqrt);
	     dcFree(vm);

       Note that the DCCallVM object can be reused and	shouldn't  be  created
       and  freed  per	call,  for performance reasons.	The following examples
       will omit creation and freeing of the DCCallVM, for simplicity.

       In a more complicated example, let's call printf(3), which  requires  a
       different initial mode, as well as a mode switch	for the	varargs	part:

	     int n_written_chars, r;
	     /*	initial	callconv mode */
	     dcMode(vm,	DC_CALL_C_ELLIPSIS);
	     dcReset(vm);
	     /*	int printf(const char *	restrict format, ...); */
	     dcArgPointer(vm, "my printf(%d) %s	string%n");
	     /*	switch mode for	varargs	part */
	     dcMode(vm,	DC_CALL_C_ELLIPSIS_VARARGS);
	     dcArgInt(vm, 3);
	     dcArgPointer(vm, "format");
	     dcArgPointer(vm, &n_written_chars);
	     r = dcCallInt(vm, (DCpointer)&printf);

   C/trivial aggregates	by-value
       Onto  an	 example passing an aggregate by value (note that this is only
       available on platforms where macro DC__Feature_AggrByVal	 is  defined).
       E.g. passing the	following struct S to f():

	     struct S {	char x[3]; double y; };
	     void f(int, struct	S);

       requires	 a DCaggr description of the fields/layout of struct S,	and is
       called as follows:

	     struct S s	= { { 56, -23, 0 }, -6.28 };

	     DCaggr *a = dcNewAggr(2, sizeof(struct S));
	     dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
	     dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
	     dcCloseAggr(a);

	     dcMode(vm,	DC_CALL_C_DEFAULT);
	     dcArgInt(vm, 999);
	     dcArgAggr(vm, a, &s);

	     dcCallVoid(vm, (DCpointer)&f);

	     dcFreeAggr(a);

       Let's look at an	example	returning by value the	above  struct  S  from
       function:

	     struct S g(int, short);

       Omitting	creation of the	DCaggr *a description, for simplicity:

	     struct S s;

	     dcMode(vm,	DC_CALL_C_DEFAULT);

	     /*	needed when returning aggrs by value, *before* pushing args */
	     dcBeginCallAggr(vm, a);

	     dcArgInt(vm, 9);
	     dcArgShort(vm, 7);

	     dcCallAggr(vm, (DCpointer)&g, a, &s);

   C++
       In  our	next  example, let's look at calling a simple C++ method, with
       the method declaration being:

	     virtual void Klass::Method(float, int);

       To keep the example simple, let's assume	we have	a pointer to this vir-
       tual method in var mptr (e.g. grabbed from the instance's vtable),  and
       a pointer to the	instance in var	thisptr:

	     /*	thiscall calling convention */
	     dcMode(vm,	DC_CALL_C_DEFAULT_THIS);
	     dcReset(vm);
	     /*	C++ methods use	this-ptr as first/hidden argument */
	     dcArgPointer(vm, thisptr);
	     dcArgFloat(vm, 2.3f);
	     dcArgInt(vm, -19);
	     dcCallVoid(vm, (DCpointer)mptr);

       Extending  the  last  example  to  a vararg method would	need some more
       dcMode(3) calls.	E.g.:

	     virtual void Klass::Method(float, int, ...);

       would be	called as follows:

	     /*	thiscall calling convention (to	pass this-ptr) */
	     dcMode(vm,	DC_CALL_C_DEFAULT_THIS);
	     dcReset(vm);
	     /*	C++ methods use	this-ptr as first/hidden argument */
	     dcArgPointer(vm, thisptr);
	     /*	fixed part of arguments	*/
	     dcMode(vm,	DC_CALL_C_ELLIPSIS);
	     dcArgFloat(vm, 2.3f);
	     dcArgInt(vm, -19);
	     /*	variable part of arguments */
	     dcMode(vm,	DC_CALL_C_ELLIPSIS_VARARGS);
	     dcArgInt(vm, 7);
	     dcArgDouble(vm, 7.99);
	     dcCallVoid(vm, (DCpointer)mptr);

CONFORMING TO
       The dyncall library needs at least a c99	compiler with additional  sup-
       port  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.

SEE ALSO
       dyncallback(3), dynload(3) and the dyncall manual  (available  in  HTML
       and PDF format) for more	information.

AUTHORS
       Daniel Adler <dadler@uni-goettingen.de>
       Tassilo Philipp <tphilipp@potion-studios.com>

				  $Mdocdate$			    dyncall(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=dyncall&sektion=3&manpath=FreeBSD+Ports+15.0>

home | help