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

FreeBSD Manual Pages

  
 
  

home | help
NAME
     dyncall  -- encapsulation of architecture-, OS- and compiler-specific func-
     tion 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-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.

     In other words, instead of calling a function directly, the dyncall library
     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 mecha-
     nisms 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  variety  of  compiler/tool-
     chain/platform-specific binary interfaces subtleties, 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 ar-
     guments 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 platform) 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 CallVM (some-
     times  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  ob-
     ject, as dcNewCallVM doesn't do this, implicitly.

     dcArgBool(), dcArgChar(), dcArgShort(), dcArgInt(), dcArgLong(), dcArgLong-
     Long(),  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(), dc-
     CallLong(),  dcCallLongLong(),   dcCallFloat(),   dcCallDouble(),	 dcCall-
     Pointer()	and dcCallAggr() call the function with the previously bound ar-
     guments and return the named type, where funcptr is a pointer to the  func-
     tion  to call. After the invocation of the function call, the argument val-
     ues are still bound to the CallVM and a second call using	the  same  argu-
     ments  can  be issued. Call dcReset() (as described above) to clear the in-
     ternal 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 argu-
     ment  or  return  type  needs  some  extra info describing its layout via a
     DCaggr structure (except for non-trivial C++ aggregates, see AGGREGATE  DE-
     SCRIPTION for more information, below). Passing such arguments is then done
     by using dcArgAggr(), where ag is a pointer to the description and value is
     a	pointer to the aggregate in question. Calling a function that returns an
     aggregate by value is done via two functions, dcBeginCallAggr(), which han-
     dles special cases to facilitate the  implementation  and	must  be  called
     before  pushing  any  arguments,  and  finally  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 description
     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-trivial construc-
     tion  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 dcAr-
     gAggr(), in order to preserver the call's by-value semantics).

     dcArgF(), dcVArgF(), dcCallF() and 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 vm object (and
     ignore return types specified in the signature), whereas the latter two is-
     sue 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  dyn-
     call_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  aggregate  in
     question.	For  returning	aggregates using those functions, pass 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 dcBe-
     ginCallAggr()  is not needed in those cases, and a pointer to the to be re-
     turned aggregate is returned via result.

AGGREGATE DESCRIPTION
     In order to describe an aggregate (except for C++	non-trivial  aggregates,
     as  mentioned  above),  create  a	DCaggr	object	using dcNewAggr(), where
     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 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 order),
     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  off-
     setof(3)),  and array_len being the number of array elements, iff the field
     is  an  array,  otherwise	use  1.  For  nested  aggregates   (when   using
     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  simplicity
     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  dif-
     ferent 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  func-
     tion:

	   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  virtual
     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 dc-
     Mode(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  support
     for  anonymous  structs/unions  (which  were introduced officially in c11).
     Given that those are generally supported by pretty much all major c99  con-
     forming  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.1.quarterly>

home | help