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.
__builtin_saveregs ()
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
'.
Code generated for the call to __builtin_saveregs
appears at the
beginning of the function, as opposed to where the call to
__builtin_saveregs
is written, regardless of what the code is.
This is because the registers must be saved before the function starts
to use them for its own purposes.
__builtin_args_info (category)
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 (lastarg)
__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. Also use it in va_start
to
verify that the second parameter lastarg is the last named argument
of the current function.
__builtin_classify_type (object)
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)
__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,
__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.