minix/include/stdarg.h
Lorenzo Cavallaro 8dfc7699a6 cdecl calling convention requires to push arguments on the stack in a
reverse order to easily support variadic arguments. Thus, instead of
using the proper stdarg.h macros (that nowadays are
compiler-dependent), it may be tempting to directly take the address of
the last argument and considering it as the start of an array. This is
a shortcut that avoid looping to get all the arguments as the CPU
already pushed them on the stack before the call to the function.

Unfortunately, such an assumption is strictly compiler-dependent and
compilers are free to move the last argument on the stack, as a local
variable, and return the address of the location where the argument was
stored, if asked for. This will break things as the rest of the array's
argument are stored elsewhere (typically, a couple of words above the
location where the argument was stored).

This patch fixes the issue by allowing ACK to take the shortcut and
enabling gcc/llvm-gcc to follow the right way.
2010-03-30 09:36:46 +00:00

78 lines
2.6 KiB
C

/* The <stdarg.h> header is ANSI's way to handle variable numbers of params.
* Some programming languages require a function that is declared with n
* parameters to be called with n parameters. C does not. A function may
* called with more parameters than it is declared with. The well-known
* printf function, for example, may have arbitrarily many parameters.
* The question arises how one can access all the parameters in a portable
* way. The C standard defines three macros that programs can use to
* advance through the parameter list. The definition of these macros for
* MINIX are given in this file. The three macros are:
*
* va_start(ap, parmN) prepare to access parameters
* va_arg(ap, type) get next parameter value and type
* va_end(ap) access is finished
*
* Ken Thompson's famous line from V6 UNIX is equally applicable to this file:
*
* "You are not expected to understand this"
*
*/
#ifndef _STDARG_H
#define _STDARG_H
#ifdef __GNUC__
/* The GNU C-compiler uses its own, but similar varargs mechanism. */
typedef char *va_list;
/* Amount of space required in an argument list for an arg of type TYPE.
* TYPE may alternatively be an expression whose type is used.
*/
#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
#if __GNUC__ < 2
#ifndef __sparc__
#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif
void va_end (va_list); /* Defined in gnulib */
#define va_end(AP)
#define va_arg(AP, TYPE) \
(AP += __va_rounded_size (TYPE), \
*((TYPE *) (AP - __va_rounded_size (TYPE))))
#else /* __GNUC__ >= 2 */
#define va_start(ap, last) __builtin_va_start((ap), (last))
#define va_arg(ap, type) __builtin_va_arg((ap), type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy((dest), (src))
#endif /* __GNUC__ >= 2 */
#else /* not __GNUC__ */
typedef char *va_list;
#define __vasz(x) ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int) -1))
#define va_start(ap, parmN) ((ap) = (va_list)&parmN + __vasz(parmN))
#define va_arg(ap, type) \
(*((type *)((va_list)((ap) = (void *)((va_list)(ap) + __vasz(type))) \
- __vasz(type))))
#define va_copy(ap2, ap) (ap2) = (ap)
#define va_end(ap)
#endif /* __GNUC__ */
#endif /* _STDARG_H */