What is the format of the x86_64 va_list structure?
Anyone have a reference for the representation of va_list
in the x86_64 ABI (the one used on Linux)? I'm trying to debug some code where the stack or arguments seem corrupt and it would really help to understand what I'm supposed to be seeing...
Solution 1:
The x86-64 System V ABi doc may help. It's a reference, albeit lightweight.
The Variable Argument List reference starts on page 54, then it goes on, page 56-57 documents va_list
:
The
va_list
TypeThe
va_list
type is an array containing a single element of one structure containing the necessary information to implement theva_arg
macro. The C definition ofva_list
type is given in figure 3.34.Figure 3.34:
va_list
Type Declarationtypedef struct { unsigned int gp_offset; unsigned int fp_offset; void *overflow_arg_area; void *reg_save_area; } va_list[1];
The
va_start
MacroThe
va_start
macro initializes the structure as follows:
reg_save_area
The element points to the start of the register save area.
overflow_arg_area
This pointer is used to fetch arguments passed on the stack. It is initialized with the address of the first argument passed on the stack, if any, and then always updated to point to the start of the next argument on the stack.
gp_offset
The element holds the offset in bytes fromreg_save_area
to the place where the next available general purpose argument register is saved. In case all argument registers have been exhausted, it is set to the value 48 (6 * 8).
fp_offset
The element holds the offset in bytes fromreg_save_area
to the place where the next available floating point argument register is saved. In case all argument registers have been exhausted, it is set to the value 304 (6 * 8 + 16 * 16).
Solution 2:
It turns out the problem was gcc's making va_list
an array type. My function was of the signature:
void foo(va_list ap);
and I wanted to pass a pointer to ap
to another function, so I did:
void foo(va_list ap)
{
bar(&ap);
}
Unfortunately, array types decay to pointer types in function argument lists, so rather than passing a pointer to the original structure, I was passing a pointer to a pointer.
To work around the problem, I changed the code to:
void foo(va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
bar(&ap2);
va_end(ap2);
}
This is the only portable solution I could come up with, that accounts for both the possibility that va_list
is an array type and the possibility that it's not.