Showing posts with label invocation. Show all posts
Showing posts with label invocation. Show all posts

Monday, July 19, 2010

Forwarding invocation of variadic function in C

I had been brooding over how to do the RPC calls for variadic functions for some time now. Although marshalling any given variadic isn't really possible due to a lack of general method for obtaining argument count and sizes (see my weekly report #9, issues section), for commonly used stdio.h variadics such as printf and scanf, the arguments are well-defined by the format string so it should be possible to manually marshal these.

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:


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

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);
    fclose(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);
    free(buf);
}

void accepter(char *fmt, char *ptr, ...)
{
    memcpy((void*)((unsigned int)(&ptr)+sizeof(char*)), ptr, 10*sizeof(double));
    va_list ap;
    va_start(ap, ptr);
    vprintf(fmt, ap);
    va_end(ap);
}

int main()
{
    printf("Testing...\n");
    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);
    return 0;
}