Constructing a function call in C

Given that I have a function pointer (for example dlsym()

) and a linked list of typed arguments, how can I construct a C function call with those arguments?

Example:

struct param {
   enum type { INT32, INT64, STRING, BOOL } type;
   union { int i32; long long i64; char *str; bool b; } value;
   struct param *next;
 };
 int call_this(int (*function)(), struct param *args)
 { 
     int result;
     /* magic here  that calls function(), which has a prototype of
     f(int, long long, char *, bool); , when args consist of a linked list of
     INT32, INT64, STRING, BOOL types. */
     return result;
 }

      

OS is Linux. I would like the solution to be portable across MIPS, PPC and x86 architecture (all 32 bits) using GCC as the compiler.

Thanks!

+2


a source to share


3 answers


Support for arbitrary function signatures is not possible with the C standard (at least I don't know how to do it). If you need this, I would go with libffi as Tom suggested .



If there is a limited number of signatures you want to support, you can examine the type fields and dispatch the call appropriately by hovering over the prototype function without specifying the correct prototype and supplying the correct arguments yourself. Function pointer coercion is necessary to avoid promoting default arguments, but even without coercion, you still have to manually submit signatures to access the correct union members. The process can be automated using a scripting language of your choice to generate C code from a list of signatures.

+2


a source


You may have to use libffi .



+6


a source


Unpack your arguments into variables and then call the function.

int a[10];
int n = 0;
while (args != NULL) {
    if (args->type == INT64) {
#if __BIG_ENDIAN__
        a[n++] = args->value.i64 >> 32;
        a[n++] = args->value.i64 & 0xffffffff;
#else
        a[n++] = args->value.i64 & 0xffffffff;
        a[n++] = args->value.i64 >> 32;
#endif
    } else { /* all other types are pushed as 32 bits parameters */
        a[n++] = args->value.i32;
    }
}
result = (*function)(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);

      

You will also need to check not to overflow the array a

.

0


a source







All Articles