How to force cdecl on variadic function
-
26-05-2021 - |
Pregunta
I'm writing a 64bit operating system using g++, and I have a variadic function like:
void DbgPrint(const char *fmt, ...);
which shall behave quite like printf. The problem here is that g++ follows the System V ABI, and thus it passes the first arguments in RDI, RSI, RDX, RCX, R8, R9, then pushes remaining (if any) on the stack.
Using the old stdarg.h macros va_start, va_arg, etc, with cdecl, was all quite easy as va_arg just took the next element on the stack. But now those macros won't work at all until the 7th argument.
The only possibile solutions are (IMHO):
- Forcing g++ to create a cdecl function. This seems impossible as __attribute__((cdecl)) is deliberately and clearly highlighted as ignored.
- Have a new set of macros that work with the new way of passing arguments.
(I'm actually working on Win, so I don't have the glibc headers to check their implementation).
Anyone with a solution? Thanks in advance.
Solución
stdarg.h is NOT part of libc, it's part of the compiler itself. So if you're using g++ it should have a stdarg.h that comes with it to handle this -- it generally gets installed in gcc's private include directory, which is searched automatically before the system includes.
If you look in gcc's stdarg.h, you see that the va_ macros are all defined to map to __builtin functions that the compiler magically knows how to deal with:
typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
and those builtins all understand the calling conventions that are used by the target ABI.