# AVCALL manual page

- Name
- Synopsis
- Description
- Notes
- See also
- Bugs
- Non-Bugs
- Porting AVCALL
- Author
- Acknowledgements

## Name

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

## Synopsis

    #include <avcall.h>
    av_alist alist;
    av_start_type (alist, &func, [[return_type,] &return_value]);
    av_type (alist, [arg_type,] value);
    av_call(alist);

## Description

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-supported).

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 `#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`.

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 argument.

   E.g.,

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

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

## Notes

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.

## See also

`stdarg`(3), `varargs`(3).

## Bugs

- 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.

## Non-Bugs

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

## Porting AVCALL

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 `avcall_call()`. 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.