AVCALL(3)                   Library Functions Manual                   AVCALL(3)

       avcall - build a C argument list incrementally and call a C function on

       #include <avcall.h>

       av_alist alist;

       av_start_type(alist, &func [[, return_type], &return_value ]);

       av_type(alist, [arg_type,] value);


       This set of macros builds an argument list for a C function and calls the
       function on it. It significantly reduces the amount of `glue' code
       required for parsers, debuggers, imbedded interpreters, C extensions to
       application programs and other situations where collections of functions
       need to be called on lists of externally-supplied arguments.

       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-

       (1)    #include <avcall.h>
              and declare the argument list structure
              av_alist alist;

       (2)    Set any special flags. This is architecture and compiler
              dependent.  Compiler options that affect passing conventions may
              need to be flagged by #defines before the #include <avcall.h>
              statement. However, the configure script should have determined
              which #defines are needed and put them at the top of avcall.h.

       (3)    Initialize the alist with the function address and return value
              pointer (if any). There is a separate macro for each simple return
              type ([u]char, [u]short, [u]int, [u]long, [u]longlong, float,
              double, where `u' indicates `unsigned'). The macros for functions
              returning structures or pointers require an explicit type


       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,

       av_start_ptr (alist, &func, pointer_type,

       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_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)
       For a struct with three slots
       struct { type1 id1; type2 id2; type3 id3; }
       you can specify splittable as av_word_splittable_3 (type1, type2, type3)

       (4)    Push the arguments on to the list in order. Again there is a macro
              for each simple built-in type, and the macros for structure and
              pointer arguments require an extra type argument:

       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);

       (5)    Call the function, set the return value, and tidy up:

       av_call (alist);

       (1) Functions whose first declaration is in Kernighan & Ritchie style
       (i.e., without a typed argument list) MUST use default K&R C expression
       promotions (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.

       (2) The explicit type arguments of the 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.

       (3) The macros 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.

       (4) The struct types used in 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).

       The current implementations have been tested on a selection of common
       cases but there are probably still many bugs.

       There are typically built-in limits on the size of the argument-list,
       which may also include the size of any structure arguments.

       The decision whether a struct is to be returned in registers or in memory
       considers only the struct's size and alignment. This is inaccurate: for
       example, gcc on m68k-next returns 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.

       All information is passed in CPU registers and the stack. The avcall
       package is therefore multithread-safe.

       Ports, bug-fixes, and suggestions are most welcome. The macros required
       for argument pushing are pretty grungy, but it does seem to be possible
       to port avcall to a range of machines. Ports to non-standard or
       non-32-bit machines are especially welcome so we can sort the interface
       out before it's too late.

       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.

       Bill Triggs <Bill.Triggs@inrialpes.fr>.

       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
       Sun[34] & 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.

                                 14 January 2001                       AVCALL(3)