1) Pass all arguments in a strict order on the stack, or in registers and on the stack, where the registers correspond to some space on the stack that is written
to in the implementation of the variadic function. This allows a very simple implementation of va_arg that just advances a pointer into the argument area
on the stack by the size of the argument. The downsize is that when an argument is larger than the alignment unit of arguments on the stack, it might end
up straddling the boundary between the argument passing in registers and on the stack, and as you have seen, GCC is not good at handling this partial
argument passing, in terms of number of instructions used.
2) Have arguments that don't fit entirely in registers passed entirely on the stack. This also mixes well with ABIs that use different kinds of registers for
different types of arguments - e.g. if the target processor has specific registers for floating point values. The downside is that the implementation
of va_arg is more complicated. That means a little bit more code size / cycles in variadic functions, but mostly just compiler / runtime implementation.
3) Use different argument passing for variadic functions that for non-variadic functions, typically like 1) - preferrably without registers - for variadic functions, and
like 2) for non-variadic functions. The downside is that there's still code out in the wild that doesn't have proper prototypes for variadic functions in scope
for all calls. This might be code that pre-dates the ANSI/ISO C standards, or where the programmer ignored or was ignorant of these standards for one
reason or another. Such code will not work for a target that uses such an ABI when the variadic/non-variadic argument passing differes for an affected call.Statistics: Posted by amylaar — Tue Mar 26, 2013 11:47 pm
]]>