From: kevin@traffic.den.mmc.com (Kevin Rodgers)
Subject: Re: gcc-2.2.2: varargs problem?
Organization: Martin Marietta Western Internal Systems, Technical Operations
Date: Mon, 31 Aug 1992 16:01:01 GMT

In article <1992Aug28.215327.2534@unixg.ubc.ca> lindholm@ucs.ubc.ca (George Lindholm) writes:
>How do I prototype and define a procedure that takes a variable number of
>arguments?

Here's the beginning of the relevant Info node:

|File: gcc.info,  Node: Varargs,  Next: Trampolines,  Prev: Stack and Calling,  Up: Target Macros
|
|Implementing the Varargs Macros
|===============================
|
|   GNU CC comes with an implementation of `varargs.h' and `stdarg.h'
|that work without change on machines that pass arguments on the stack. 
|Other machines require their own implementations of varargs, and the
|two machine independent header files must have conditionals to include
|it.
|
|   ANSI `stdarg.h' differs from traditional `varargs.h' mainly in the
|calling convention for `va_start'.  The traditional implementation
|takes just one argument, which is the variable in which to store the
|argument pointer.  The ANSI implementation of `va_start' takes an
|additional second argument.  The user is supposed to write the last
|named argument of the function here.
|
|   However, `va_start' should not use this argument.  The way to find
|the end of the named arguments is with the built-in functions described
|below.

What is the justification for these last two sentences?  Gcc 2.2.2 seems
to compile vanilla ANSI stdarg code (under SunOS 4.1.1) just fine.

And FYI, here's the rest of that Info node:

|`__builtin_saveregs ()'
|     Use this built-in function to save the argument registers in
|     memory so that the varargs mechanism can access them.  Both ANSI
|     and traditional versions of `va_start' must use
|     `__builtin_saveregs', unless you use `SETUP_INCOMING_VARARGS' (see
|     below) instead.
|
|     On some machines, `__builtin_saveregs' is open-coded under the
|     control of the macro `EXPAND_BUILTIN_SAVEREGS'.  On other machines,
|     it calls a routine written in assembler language, found in
|     `libgcc2.c'.
|
|     Regardless of what code is generated for the call to
|     `__builtin_saveregs', it appears at the beginning of the function,
|     not where the call to `__builtin_saveregs' is written.  This is
|     because the registers must be saved before the function starts to
|     use them for its own purposes.
|
|`__builtin_args_info (CATEGORY)'
|     Use this built-in function to find the first anonymous arguments in
|     registers.
|
|     In general, a machine may have several categories of registers
|     used for arguments, each for a particular category of data types. 
|     (For example, on some machines, floating-point registers are used
|     for floating-point arguments while other arguments are passed in
|     the general registers.) To make non-varargs functions use the
|     proper calling convention, you have defined the `CUMULATIVE_ARGS'
|     data type to record how many registers in each category have been
|     used so far
|
|     `__builtin_args_info' accesses the same data structure of type
|     `CUMULATIVE_ARGS' after the ordinary argument layout is finished
|     with it, with CATEGORY specifying which word to access.  Thus, the
|     value indicates the first unused register in a given category.
|
|     Normally, you would use `__builtin_args_info' in the implementation
|     of `va_start', accessing each category just once and storing the
|     value in the `va_list' object.  This is because `va_list' will
|     have to update the values, and there is no way to alter the values
|     accessed by `__builtin_args_info'.
|
|`__builtin_next_arg ()'
|     This is the equivalent of `__builtin_args_info', for stack
|     arguments.  It returns the address of the first anonymous stack
|     argument, as type `void *'. If `ARGS_GROW_DOWNWARD', it returns
|     the address of the location above the first anonymous stack
|     argument. Use it in `va_start' to initialize the pointer for
|     fetching arguments from the stack.
|
|`__builtin_classify_type (OBJECT)'
|     Since each machine has its own conventions for which data types are
|     passed in which kind of register, your implementation of `va_arg'
|     has to embody these conventions.  The easiest way to categorize the
|     specified data type is to use `__builtin_classify_type' together
|     with `sizeof' and `__alignof__'.
|
|     `__builtin_classify_type' ignores the value of OBJECT, considering
|     only its data type.  It returns an integer describing what kind of
|     type that is--integer, floating, pointer, structure, and so on.
|
|     The file `typeclass.h' defines an enumeration that you can use to
|     interpret the values of `__builtin_classify_type'.
|
|   These machine description macros help implement varargs:
|
|`EXPAND_BUILTIN_SAVEREGS (ARGS)'
|     If defined, is a C expression that produces the machine-specific
|     code for a call to `__builtin_saveregs'.  This code will be moved
|     to the very beginning of the function, before any parameter access
|     are made. The return value of this function should be an RTX that
|     contains the value to use as the return of `__builtin_saveregs'.
|
|     The argument ARGS is a `tree_list' containing the arguments that
|     were passed to `__builtin_saveregs'.
|
|     If this macro is not defined, the compiler will output an ordinary
|     call to the library function `__builtin_saveregs'.
|
|`SETUP_INCOMING_VARARGS (ARGS_SO_FAR, MODE, TYPE, PRETEND_ARGS_SIZE, SECOND_TIME)'
|     This macro offers an alternative to using `__builtin_saveregs' and
|     defining the macro `EXPAND_BUILTIN_SAVEREGS'.  Use it to store the
|     anonymous register arguments into the stack so that all the
|     arguments appear to have been passed consecutively on the stack. 
|     Once this is done, you can use the standard implementation of
|     varargs that works for machines that pass all their arguments on
|     the stack.
|
|     The argument ARGS_SO_FAR is the `CUMULATIVE_ARGS' data structure,
|     containing the values that obtain after processing of the named
|     arguments.  The arguments MODE and TYPE describe the last named
|     argument--its machine mode and its data type as a tree node.
|
|     The macro implementation should do two things: first, push onto the
|     stack all the argument registers *not* used for the named
|     arguments, and second, store the size of the data thus pushed into
|     the `int'-valued variable whose name is supplied as the argument
|     PRETEND_ARGS_SIZE.  The value that you store here will serve as
|     additional offset for setting up the stack frame.
|
|     Because you must generate code to push the anonymous arguments at
|     compile time without knowing their data types,
|     `SETUP_INCOMING_VARARGS' is only useful on machines that have just
|     a single category of argument register and use it uniformly for
|     all data types.
|
|     If the argument SECOND_TIME is nonzero, it means that the
|     arguments of the function are being analyzed for the second time. 
|     This happens for an inline function, which is not actually
|     compiled until the end of the source file.  The macro
|     `SETUP_INCOMING_VARARGS' should not generate any instructions in
|     this case.
-- 
Kevin Rodgers				kevin@traffic.den.mmc.com
Martin Marietta MS A16401		(303) 790-3971
116 Inverness Dr. East
Englewood CO 80112 USA			GO BUFFS!
Newsgroups: gnu.gcc.help