I have a project that consists of a bunch of dynamically loaded modules. Originally, everything was always built with MSVC 2003, but lately I've been working on getting it to work with GCC. Everything has been going pretty smoothly, except for one problem. For 64-bit code, GCC and MSVC don't agree about what a va_list
is. For 32-bit, things seem to line up fine. The problem the 64-bit mismatch causes is when a module built with one compiler has a public function with a va_list
parameter and that function is called from a module built by the other compiler.
The spec says nothing about what a va_list
is, outside of Section 7.15 Variable arguments <stdarg.h>
, paragraph 3:
The type declared is
va_list
which is an object type suitable for holding information needed by the macros
va_start
,va_arg
,va_end
, andva_copy
.
That paragraph just means this is all compiler dependent stuff - so, is there a way to make these two compilers agree on the contents of a 64-bit va_list
? For least impact to my system, making GCC match the MSVC va_list
would be best, but I'll take any solution I can get.
Thanks for helping out!
Edit:
I did some 32-bit testing, and I have problems there too, which surprised me since there are supposedly no ABI differences between any 32-bit Intel platforms. The MSVC codebase I'm using defines all of the variadic function macros as:
typedef char *va_list;
#define intsizeof(n) ((sizeof(n) + sizeof(int) - 1) &~(sizeof(int) - 1))
#define va_start(ap, v) (ap = (va_list)&(v) + intsizeof(v))
#define va_arg(ap, t) (*(t *) ((ap += intsizeof(t)) - intsizeof(t)))
#define va_end(ap) (ap = (va_list)0)
I've simplified a bit from the real project, but this is the code I was using for my test. With GCC, this code definitely isn't correctly getting my arguments. Maybe it is just a bug, as Zack suggests below?
Edit again:
I get working results for the following 32-bit test application with -O0
, -O0
, and -O2
, but not -O3
, -Os
, and -Oz
:
typedef char *va_list;
#define intsizeof(n) ((sizeof(n) + sizeof(int) - 1) &~(sizeof(int) - 1))
#define va_start(ap, v) (ap = (va_list)&(v) + intsizeof(v))
#define va_arg(ap, t) (*(t *) ((ap += intsizeof(t)) - intsizeof(t)))
#define va_end(ap) (ap = (va_list)0)
int printf(const char *format, ...);
int f(int n, ...)
{
int r = 0;
va_list ap;
va_start(ap, n);
while (n--)
r = va_arg(ap, int);
va_end(ap);
return r;
}
int main(int argc, char **argv)
{
int r;
r = f(1, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(2, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(3, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(4, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(5, 1, 2, 3, 4, 5);
printf("%x\n", r);
return 0;
}
va_*
definitions from MSVC's<stdarg.h>
into a file which you then compiled with GCC, is that it? Because that will definitely not work, and does not tell you anything useful. You absolutely must use GCC's<stdarg.h>
to define variadic functions compiled with GCC (and MSVC's for MSVC) or your code will be miscompiled. – Luckf
to its own file, replace all the hand definitions ofva_*
with#include <stdarg.h>
, put "extern int f(int n, ...);
abovemain
in that file, compile one with GCC and the other with MSVC, and link the two object files. That should work in either direction (MSVC calls GCC or GCC calls MSVC) on either x32 or x64. – Luck