---
name: "avcall"
section: "3"
platform: "linux"
package: "ffcall"
version: "2.5-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/avcall"
---

# avcall(3)

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

## 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)](/stdarg/3.md) 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)](/stdarg/3.md), [**varargs**(3)](/varargs/3.md).

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

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