va_list q

David O'Brien obrien at
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

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.


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

More information about the freebsd-amd64 mailing list