VACALL(3) VACALL(3) NNAAMMEE vacall - C functions called with variable arguments SSYYNNOOPPSSIISS ##iinncclluuddee <> eexxtteerrnn vvooiidd** vvaaccaallll__ffuunnccttiioonn;; vvooiidd _f_u_n_c_t_i_o_n ((_a_l_i_s_t)) vvaa__aalliisstt _a_l_i_s_t;; {{ vvaa__ssttaarrtt___t_y_p_e((_a_l_i_s_t[[,, _r_e_t_u_r_n___t_y_p_e]]));; _a_r_g == vvaa__aarrgg___t_y_p_e((_a_l_i_s_t[[,, _a_r_g___t_y_p_e]]));; vvaa__rreettuurrnn___t_y_p_e((_a_l_i_s_t[[[[,, _r_e_t_u_r_n___t_y_p_e]],, _r_e_t_u_r_n___v_a_l_u_e]]));; }} vvaaccaallll__ffuunnccttiioonn == _&_f_u_n_c_t_i_o_n;; _v_a_l == ((((_r_e_t_u_r_n___t_y_p_e ((**)) (()))) vvaaccaallll)) ((_a_r_g_1,,_a_r_g_2,,_._._.));; DDEESSCCRRIIPPTTIIOONN This set of macros permit a C function _f_u_n_c_t_i_o_n to be called with variable arguments and to return variable return values. This is much like the vvaarraarrggss(3) facility, but also allows the return value to be specified at run time. Function calling conventions differ considerably on dif- ferent machines, and _v_a_c_a_l_l attempts to provide some degree of isolation from such architecture dependencies. The function that can be called with any number and type of arguments and which will return any type of return value is vvaaccaallll. It will do some magic and call the func- tion stored in the variable vvaaccaallll__ffuunnccttiioonn. If you want to make more than one use of _v_a_c_a_l_l, use the _t_r_a_m_p_o_l_i_n_e(3) facility to store _&_f_u_n_c_t_i_o_n into vvaaccaallll__ffuunnccttiioonn just before calling vvaaccaallll. Within _f_u_n_c_t_i_o_n, the following macros can be used to walk through the argument list and specify a return value: vvaa__ssttaarrtt___t_y_p_e((_a_l_i_s_t[[,, _r_e_t_u_r_n___t_y_p_e]]));; starts the walk through the argument list and spec- ifies the return type. _a_r_g == vvaa__aarrgg___t_y_p_e((_a_l_i_s_t[[,, _a_r_g___t_y_p_e]]));; fetches the next argument from the argument list. vvaa__rreettuurrnn___t_y_p_e((_a_l_i_s_t[[[[,, _r_e_t_u_r_n___t_y_p_e]],, _r_e_t_u_r_n___v_a_l_u_e]]));; ends the walk through the argument list and speci- fies the return value. The _t_y_p_e in vvaa__ssttaarrtt___t_y_p_e and vvaa__rreettuurrnn___t_y_p_e shall be one 14 January 2001 1 VACALL(3) VACALL(3) of vvooiidd, iinntt, uuiinntt, lloonngg, uulloonngg, lloonngglloonngg, uulloonngglloonngg, ddoouu-- bbllee, ssttrruucctt, ppttrr or (for ANSI C calling conventions only) cchhaarr, sscchhaarr, uucchhaarr, sshhoorrtt, uusshhoorrtt, ffllooaatt, depending on the class of _r_e_t_u_r_n___t_y_p_e. The _t_y_p_e specifiers in vvaa__ssttaarrtt___t_y_p_e and vvaa__rreettuurrnn___t_y_p_e must be the same. The _r_e_t_u_r_n___t_y_p_e specifiers passed to vvaa__ssttaarrtt___t_y_p_e and vvaa__rreettuurrnn___t_y_p_e must be the same. The _t_y_p_e in vvaa__aarrgg___t_y_p_e shall be one of iinntt, uuiinntt, lloonngg, uulloonngg, lloonngglloonngg, uulloonngglloonngg, ddoouubbllee, ssttrruucctt, ppttrr or (for ANSI C calling conventions only) cchhaarr, sscchhaarr, uucchhaarr, sshhoorrtt, uusshhoorrtt, ffllooaatt, depending on the class of _a_r_g___t_y_p_e. In vvaa__ssttaarrtt__ssttrruucctt((_a_l_i_s_t,, _r_e_t_u_r_n___t_y_p_e,, _s_p_l_i_t_t_a_b_l_e));; the _s_p_l_i_t_t_a_b_l_e flag specifies whether the struct _r_e_t_u_r_n___t_y_p_e can be returned in registers such that every struct field fits entirely in a single register. This needs to be spec- ified 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: vvaa__wwoorrdd__sspplliittttaabbllee__11 ((_t_y_p_e_1)) vvaa__wwoorrdd__sspplliittttaabbllee__22 ((_t_y_p_e_1,, _t_y_p_e_2)) vvaa__wwoorrdd__sspplliittttaabbllee__33 ((_t_y_p_e_1,, _t_y_p_e_2,, _t_y_p_e_3)) vvaa__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 vvaa__wwoorrdd__sspplliittttaabbllee__33 ((_t_y_p_e_1,, _t_y_p_e_2,, _t_y_p_e_3)) . NNOOTTEESS Functions which want to emulate Kernighan & Ritchie style functions (i.e., in ANSI C, functions without a typed argument list) cannot use the _t_y_p_e values cchhaarr, sscchhaarr, uucchhaarr, sshhoorrtt, uusshhoorrtt, ffllooaatt. As prescribed by the default K&R C expression promotions, they have to use iinntt instead of cchhaarr, sscchhaarr, uucchhaarr, sshhoorrtt, uusshhoorrtt and ddoouubbllee instead of ffllooaatt. The macros vvaa__ssttaarrtt__lloonngglloonngg(()), vvaa__ssttaarrtt__uulloonngglloonngg(()), vvaa__rreettuurrnn__lloonngglloonngg(()), vvaa__rreettuurrnn__uulloonngglloonngg(()), vvaa__aarrgg__lloonngglloonngg(()) and vvaa__aarrgg__uulloonngglloonngg(()) work only if the C compiler has a working lloonngg lloonngg 64-bit integer type. The struct types used in vvaa__ssttaarrtt__ssttrruucctt(()) and vvaa__ssttrruucctt(()) 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. 14 January 2001 2 VACALL(3) VACALL(3) EEXXAAMMPPLLEE This example, a possible implementation of eexxeeccll(3) on top of eexxeeccvv(2) using vvaarraarrggss(3), ##iinncclluuddee <> ##ddeeffiinnee MMAAXXAARRGGSS 110000 //** eexxeeccll iiss ccaalllleedd bbyy eexxeeccll((ffiillee,, aarrgg11,, aarrgg22,, ......,, ((cchhaarr **))00));; **// iinntt eexxeeccll ((vvaa__aalliisstt)) vvaa__ddccll {{ vvaa__lliisstt aapp;; cchhaarr** ffiillee;; cchhaarr** aarrggss[[MMAAXXAARRGGSS]];; iinntt aarrggnnoo == 00;; vvaa__ssttaarrtt ((aapp));; ffiillee == vvaa__aarrgg((aapp,, cchhaarr**));; wwhhiillee ((((aarrggss[[aarrggnnoo]] == vvaa__aarrgg((aapp,, cchhaarr**)))) !!== ((cchhaarr **))00)) aarrggnnoo++++;; vvaa__eenndd ((aapp));; rreettuurrnn eexxeeccvv((ffiillee,, aarrggss));; }} looks like this using vvaaccaallll(3): ##iinncclluuddee <> ##ddeeffiinnee MMAAXXAARRGGSS 110000 //** eexxeeccll iiss ccaalllleedd bbyy vvaaccaallll((ffiillee,, aarrgg11,, aarrgg22,, ......,, ((cchhaarr **))00));; **// vvooiidd eexxeeccll ((aapp)) vvaa__aalliisstt aapp;; {{ cchhaarr** ffiillee;; cchhaarr** aarrggss[[MMAAXXAARRGGSS]];; iinntt aarrggnnoo == 00;; iinntt rreettvvaall;; vvaa__ssttaarrtt__iinntt ((aapp));; ffiillee == vvaa__aarrgg__ppttrr((aapp,, cchhaarr**));; wwhhiillee ((((aarrggss[[aarrggnnoo]] == vvaa__aarrgg__ppttrr((aapp,, cchhaarr**)))) !!== ((cchhaarr **))00)) aarrggnnoo++++;; rreettvvaall == eexxeeccvv((ffiillee,, aarrggss));; vvaa__rreettuurrnn__iinntt ((aapp,, rreettvvaall));; }} vvaaccaallll__ffuunnccttiioonn == &&eexxeeccll;; SSEEEE AALLSSOO vvaarraarrggss(3), ttrraammppoolliinnee(3), ccaallllbbaacckk(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 14 January 2001 3 VACALL(3) VACALL(3) 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. <> cannot be included when <> or <> is included. (Name clash for vvaa__aalliisstt.) The argument list can only be walked once. The use of the global variable vvaaccaallll__ffuunnccttiioonn is not reentrant. This is fixed in the ccaallllbbaacckk(3) package. PPOORRTTIINNGG 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." The implementation of varargs for gcc can be found in the gcc source, files gcc-2.6.3/ginclude/va*.h. gcc's __builtin_saveregs() function is defined in the gcc source, file gcc-2.6.3/libgcc2.c. AAUUTTHHOORR Bruno Haible AACCKKNNOOWWLLEEDDGGEEMMEENNTTSS Many ideas and a lot of code were cribbed from the gcc source. 14 January 2001 4