#include <avcall.h>
av_alist alist;
av_start_type (alist, &func, [[return_type,] &return_value]);
av_type (alist, [arg_type,] value);
av_call(alist);
Function calling conventions differ considerably on different
machines and avcall
attempts to provide some degree
of isolation from such architecture dependencies.
The interface is like stdarg
(3) in reverse. All of the
macros return 0 for success, < 0 for failure (e.g., argument
list overflow or type-not-supported).
#include <avcall.h>
and declare the argument list
structure av_alist alist;
#define
s before the #include <avcall.h>
statement. However, the configure script should have
determined which #define
s are needed and put them
at the top of avcall.h.
E.g.,
The splittable flag specifies whether the struct_type can be returned in registers such that every struct field fits entirely in a single register. This needs to be specified for structs of size 2*sizeof(long). For structs of size <= sizeof(long), splittable is ignored and assumed to be 1. For structs of size > 2*sizeof(long), splittable is ignored and assumed to be 0. There are some handy macros for this:av_start_int (alist, &func, &int_return);
av_start_double (alist, &func, &double_return);
av_start_void (alist, &func);
av_start_struct (alist, &func, struct_type, splittable, &struct_return);
av_start_ptr (alist, &func, pointer_type, &pointer_return);
For a struct with three slotsav_word_splittable_1 (type1)
av_word_splittable_2 (type1, type2)
av_word_splittable_3 (type1, type2, type3)
av_word_splittable_4 (type1, type2, type3, type4)
struct { type1 id1; type2 id2; type3 id3; }
you can specify splittable as
av_word_splittable_3 (type1, type2, type3)
.
av_int (alist, int_value);
av_double (alist, double_value);
av_struct (alist, struct_or_union_type, struct_value);
av_ptr (alist, pointer_type, pointer_value);
av_call (alist);
char
and short
to
int
, float
to double
) whether they are compiled by a K&R
or an ANSI compiler, because the true argument types may
not be known at the call point. Such functions typically
back-convert their arguments to the declared types on
function entry. (In fact, the only way to pass a true
char
, short
or float
in K&R C is by an explicit cast:
func((char)c,(float)f)
). Similarly, some K&R compilers
(such as Sun cc on the sparc) actually return a float
as a
double
.
Hence, for arguments of functions declared in K&R style
you should use av_int()
and av_double() rather than
av_char()
, av_short()
or av_float()
. If you use a K&R
compiler, the avcall header files may be able to detect
this and define av_float()
, etc, appropriately, but with
an ANSI compiler there is no way avcall can know how a
function was declared, so you have to correct the argument
types yourself.
av_struct()
and
av_ptr()
macros are typically used to calculate size,
alignment, and passing conventions. This may not be sufficient for some machines with unusual structure and
pointer handling: in this case additional av_start_type()
and av_type()
macros may be defined.
av_start_longlong()
,
av_start_ulonglong()
, av_longlong()
and
av_ulonglong()
work only if the C compiler has a working
long long
64-bit integer type.
av_start_struct()
and
av_struct()
must only contain (signed or unsigned) int,
long, long long or pointer fields. Struct types containing
(signed or unsigned) char, short, float, double or other
structs are not supported.
stdarg
(3), varargs
(3).
struct { char a,b,c; }
in registers and
struct { char a[3]; }
in memory, although both types have the same size and the same alignment.
avcall
package is therefore multithread-safe.
Knowledge about argument passing conventions can be found in the gcc source, file gcc-2.6.3/config/cpu/cpu.h, section "Stack layout; function entry, exit and calling."
Some of the grunge is usually handled by a C or assembly
level glue routine that actually pushes the arguments,
calls the function and unpacks any return value. This is
called __builtin_avcall()
. A precompiled assembler version for
people without gcc is also made available. The routine should ideally
have flags for the passing conventions of other compilers.
Many of the current routines waste a lot of stack space and generally do hairy things to stack frames - a bit more assembly code would probably help things along quite a bit here.
Author
Bill Triggs <Bill.Triggs@inrialpes.fr>, <Bill.Triggs@imag.fr>.
Acknowledgements
Some initial ideas were stolen from the C interface to the
Zelk extensions to Oliver Laumann's Elk scheme interpreter
by J.P.Lewis, NEC C&C Research, <zilla@ccrl.nj.nec.com>
(for Sun4 & SGI), and Roy Featherstone's
<roy@robots.oxford.ac.uk> personal C interface library for
Sun3, Sun4 & SGI. I also looked at the machine-dependent
parts of the GCC and GDB distributions, and put the gcc
asm()
extensions to good use. Thanks guys!
This work was partly supported by EC-ESPRIT Basic Research Action SECOND.
Last modified: 14 January 2001.