0x6adb015
0x6adb015

Reputation: 7801

Constructing a function call in C

Given that I have a pointer to a function (provided by dlsym() for example) 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;
 }

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

Thanks!

Upvotes: 2

Views: 350

Answers (3)

Christoph
Christoph

Reputation: 169563

Supporting arbitrary function signatures is impossible with standard C (at least I don't know of any way to do so). If you need this, I'd go with libffi as Tom suggested.

If there's only a limited number of signatures you want to support, you can examine the type fields and dispatch the call appropriately by casting the prototype-less function pointer to the correct prototype and supply the correct arguments yourself. Casting the function pointer is necessary to avoid default argument promotion, but even without the cast, you still would have to dispatch manually on the signatures to access the correct union members. The process can be automated by using the scripting language of your choice to generate the C code from a list of signatures.

Upvotes: 2

Didier Trosset
Didier Trosset

Reputation: 37437

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 have to check not to overflow the a array.

Upvotes: 0

Tom Dalling
Tom Dalling

Reputation: 24125

You'll probably need to use libffi.

Upvotes: 6

Related Questions