AVCALL(3)                                               AVCALL(3)


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

SSYYNNOOPPSSIISS
       ##iinncclluuddee <<aavvccaallll..hh>>

       aavv__aalliisstt _a_l_i_s_t;;

       aavv__ssttaarrtt___t_y_p_e((_a_l_i_s_t,, _&_f_u_n_c [[,, _r_e_t_u_r_n___t_y_p_e],, _&_r_e_t_u_r_n___v_a_l_u_e
       ]));;

       aavv___t_y_p_e((_a_l_i_s_t,, [_a_r_g___t_y_p_e,,] _v_a_l_u_e));;

       aavv__ccaallll((_a_l_i_s_t));;

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

       Function  calling  conventions differ considerably on dif-
       ferent machines and _a_v_c_a_l_l attempts to provide some degree
       of isolation from such architecture dependencies.

       The  interface  is  like  ssttddaarrgg(3) in reverse. All of the
       macros return 0 for success, < 0 for failure (e.g.,  argu-
       ment list overflow or type-not-supported).

       (1)    ##iinncclluuddee <<aavvccaallll..hh>>
              and declare the argument list structure
              aavv__aalliisstt _a_l_i_s_t;;

       (2)    Set  any  special  flags.  This is architecture and
              compiler dependent.  Compiler options  that  affect
              passing  conventions  may  need  to  be  flagged by
              ##ddeeffiinnees before the ##iinncclluuddee <<aavvccaallll..hh>>  statement.
              However,  the  _c_o_n_f_i_g_u_r_e  script should have deter-
              mined which ##ddeeffiinnees are needed and put them at the
              top of aavvccaallll..hh.

       (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, dou-
              ble,  where  `u'  indicates `unsigned'). The macros
              for  functions  returning  structures  or  pointers
              require an explicit type argument.

       E.g.,



                         14 January 2001                        1





AVCALL(3)                                               AVCALL(3)


       aavv__ssttaarrtt__iinntt ((_a_l_i_s_t,, _&_f_u_n_c,, _&_i_n_t___r_e_t_u_r_n));;

       aavv__ssttaarrtt__ddoouubbllee ((_a_l_i_s_t,, _&_f_u_n_c,, _&_d_o_u_b_l_e___r_e_t_u_r_n));;

       aavv__ssttaarrtt__vvooiidd ((_a_l_i_s_t,, _&_f_u_n_c));;

       aavv__ssttaarrtt__ssttrruucctt ((_a_l_i_s_t,, _&_f_u_n_c,, _s_t_r_u_c_t___t_y_p_e,, _s_p_l_i_t_t_a_b_l_e,,
                        _&_s_t_r_u_c_t___r_e_t_u_r_n));;

       aavv__ssttaarrtt__ppttrr ((_a_l_i_s_t,, _&_f_u_n_c,, _p_o_i_n_t_e_r___t_y_p_e,,
                     _&_p_o_i_n_t_e_r___r_e_t_u_r_n));;

       The  _s_p_l_i_t_t_a_b_l_e flag specifies whether the _s_t_r_u_c_t___t_y_p_e 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),  _s_p_l_i_t_t_a_b_l_e  is ignored and assumed to be 1.
       For  structs  of  size  >  2*sizeof(long),  _s_p_l_i_t_t_a_b_l_e  is
       ignored  and  assumed to be 0. There are some handy macros
       for this:
       aavv__wwoorrdd__sspplliittttaabbllee__11 ((_t_y_p_e_1))
       aavv__wwoorrdd__sspplliittttaabbllee__22 ((_t_y_p_e_1,, _t_y_p_e_2))
       aavv__wwoorrdd__sspplliittttaabbllee__33 ((_t_y_p_e_1,, _t_y_p_e_2,, _t_y_p_e_3))
       aavv__wwoorrdd__sspplliittttaabbllee__44 ((_t_y_p_e_1,, _t_y_p_e_2,, _t_y_p_e_3,, _t_y_p_e_4))
       For a struct with three slots
       ssttrruucctt {{ _t_y_p_e_1 _i_d_1;; _t_y_p_e_2 _i_d_2;; _t_y_p_e_3 _i_d_3;; }}
       you can specify _s_p_l_i_t_t_a_b_l_e as aavv__wwoorrdd__sspplliittttaabbllee__33 ((_t_y_p_e_1,,
       _t_y_p_e_2,, _t_y_p_e_3)) .

       (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:

       aavv__iinntt ((_a_l_i_s_t,, _i_n_t___v_a_l_u_e));;

       aavv__ddoouubbllee ((_a_l_i_s_t,, _d_o_u_b_l_e___v_a_l_u_e));;

       aavv__ssttrruucctt ((_a_l_i_s_t,, _s_t_r_u_c_t___o_r___u_n_i_o_n___t_y_p_e,, _s_t_r_u_c_t___v_a_l_u_e));;

       aavv__ppttrr ((_a_l_i_s_t,, _p_o_i_n_t_e_r___t_y_p_e,, _p_o_i_n_t_e_r___v_a_l_u_e));;

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

       aavv__ccaallll ((_a_l_i_s_t));;


NNOOTTEESS
       (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



                         14 January 2001                        2





AVCALL(3)                                               AVCALL(3)


       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:
       ffuunncc((((cchhaarr))cc,,((ffllooaatt))ff)) ).  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  aavv__iinntt(())  and  aavv__ddoouubbllee(())  rather  than
       aavv__cchhaarr(()),, aavv__sshhoorrtt(()) or aavv__ffllooaatt(())..  If  you  use  a  K&R
       compiler,  the  avcall  header files may be able to detect
       this and define aavv__ffllooaatt(()),, etc, appropriately,  but  with
       an  ANSI  compiler  there  is no way _a_v_c_a_l_l can know how a
       function was declared, so you have to correct the argument
       types yourself.

       (2)  The  explicit  type  arguments of the aavv__ssttrruucctt(()) and
       aavv__ppttrr(()) macros are  typically  used  to  calculate  size,
       alignment,  and passing conventions.  This may not be suf-
       ficient for  some  machines  with  unusual  structure  and
       pointer  handling: in this case additional aavv__ssttaarrtt___t_y_p_e(())
       and aavv___t_y_p_e(()) macros may be defined.

       (3) The macros aavv__ssttaarrtt__lloonngglloonngg(()),  aavv__ssttaarrtt__uulloonngglloonngg(()),
       aavv__lloonngglloonngg(())  and  aavv__uulloonngglloonngg(()) work only if the C com-
       piler has a working lloonngg lloonngg 64-bit integer type.

       (4)  The  struct  types  used  in  aavv__ssttaarrtt__ssttrruucctt(())   and
       aavv__ssttrruucctt(())  must  only  contain (signed or unsigned) int,
       long, long long or pointer fields.  Struct types  contain-
       ing  (signed  or  unsigned)  char, short, float, double or
       other structs are not supported.


SSEEEE AALLSSOO
       ssttddaarrgg(3), vvaarraarrggss(3).


BBUUGGSS
       The current implementations have been tested on  a  selec-
       tion  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  regis-
       ters  or  in  memory  considers only the struct's size and
       alignment. This is inaccurate: for example, gcc  on  m68k-
       next  returns  ssttrruucctt  {{  cchhaarr  aa,,bb,,cc;;  }} in registers and
       ssttrruucctt {{ cchhaarr aa[[33]];; }} in memory, although both types  have
       the same size and the same alignment.



                         14 January 2001                        3





AVCALL(3)                                               AVCALL(3)


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


PPOORRTTIINNGG AAVVCCAALLLL
       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/_c_p_u/_c_p_u.h,  sec-
       tion "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.


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


AACCKKNNOOWWLLEEDDGGEEMMEENNTTSS
       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                        4