I'll be writing a seperate blog post about how I went about doing that, but for now I want to talk about a sub-problem of this: given a number of arguments, how do you forward these to a variadic function? A re-statement could be, how to "dynamically" invoke a variadic function?
Looking this up in the net, I've found these two discussions to be the most relevant:
The second link mentions a library called FFCALL which can be used to pass parameters to variadics dynamically, and this probably is the ideal way of doing things.
I may have found another method for this - so far as I've seen it works on x86 and ARM. It's based on the assumption that the last mandatory parameter and all the variadic parameters reside continuously in the memory, as well as lots of terrible coding practices, but it should be illustrative enough.
What I'm doing is basically copying a fixed number of bytes from the memory region (=stack) where the variadic parameters are located into a buffer, then passing this buffer to another variadic function which is called with a fixed number of arguments (I picked doubles since they are larger and will allocate more space on the called function's stack). The function then calls memcpy to overwrite its variadic args section with the passed buffer, and afterwards can call the stdarg macros to obtain the variadic arguments, or pass them to something like vprintf.
Here's the code:
void accepter(char *fmt, char *ptr, ...);
void forwarder(char *fmt, ...);
void forwarder(char *fmt, ...)
double d = 9.1;
char *buf = (char*) malloc(10*sizeof(double));
memcpy(buf, (void*)((unsigned int)(&fmt)+sizeof(char*)), 80);
FILE *o = fopen("tmp", "wb");
fwrite(buf, 10, sizeof(double), o);
// call function with 10 double arguments to open up stack space
accepter(fmt, buf, d, d, d, d, d, d, d, d, d, d);
void accepter(char *fmt, char *ptr, ...)
memcpy((void*)((unsigned int)(&ptr)+sizeof(char*)), ptr, 10*sizeof(double));
double d = 65.98;
forwarder("%d %d %d ermm %s and more params! %x %f %x %x \n", 1, 2, 3, "hello world", 199, d , 0xdeadbeef, 0xbeefdead);