va_list q
David O'Brien
obrien at freebsd.org
Thu Apr 22 08:11:07 PDT 2004
On Wed, Apr 21, 2004 at 10:58:01PM -0700, Peter Wemm wrote:
> > int
> > vslprintf(buf, buflen, fmt, args)
> > [...]
> > #ifndef __powerpc__
> > > n = vslprintf(buf, buflen + 1, f, va_arg(args,
> > > va_list));
> > #else
> > /* On the powerpc, a va_list is an array of 1 structure
> > */ n = vslprintf(buf, buflen + 1, f, va_arg(args, void *)); #endif
...
> amd64 needs to use the same code that is in the #ifdef __powerpc__. Its
> what we use in src/usr.sbin/pppd FWIW.
...
> As an aside, this breaks code that assums it can copy va_lists by
> assignment. On powerpc and amd64, you *must* use va_copy(), or you
> simply copy the pointer, not the actual argument passing state.
If we step back a little, the code breaks because it is not ISO-C
compliant.
One must use va_copy() just like one needs to use strcpy() to get a
unique copy of a C string. There is zero need for the
"#ifdef __powerpc__" -- that code is ISO-C compliant and should work on
all platforms.
1. Adhere to ISO C specification for stdargs:
Do not copy ap directly:
void foo (va_list ap) {
va_list tap = ap;
/* use tap */
}
Correct usage:
#include <stdargs.h>
void foo (va_list ap) {
va_list tap;
va_copy (tap, ap);
/* use tap */
}
GCCs ap is a pointer for AMD64. &ap does not do what you may expect.
REVIEW ISO C99 STANDARD, SECTION 7.15.
2. Correct Prototypes when using stdargs
By convention, GCC stdargs and varargs on AMD64 use the %al register
to indicate the number of floating-point arguments. The entry point
of a function using stdargs or varargs, expects the
%al register to be initialized properly.
If the function prototype used by caller doesn't include the (...),
gcc won't initialize %al as part of the call. And a crash and/or
strange behavior will occur after the call.
--
-- David (obrien at FreeBSD.org)
More information about the freebsd-amd64
mailing list