Построение вызова функции в C - PullRequest
2 голосов
/ 12 мая 2010

Учитывая, что у меня есть указатель на функцию (например, dlsym()) и связанный список типизированных аргументов, как я могу создать вызов функции C с этими аргументами?

Пример:

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;
 }

ОС - Linux.Мне бы хотелось, чтобы решение было переносимым на архитектуру MIPS, PPC и x86 (все 32 бита) с использованием GCC в качестве компилятора.

Спасибо!

Ответы [ 3 ]

6 голосов
/ 12 мая 2010

Возможно, вам понадобится libffi .

2 голосов
/ 12 мая 2010

Поддержка произвольных сигнатур функций невозможна в стандартном C (по крайней мере, я не знаю, как это сделать). Если вам это нужно, я бы выбрал libffi , как Том предложил .

Если существует только ограниченное количество подписей, которые вы хотите поддерживать, вы можете проверить поля типов и соответствующим образом отправить вызов, приведя указатель функции без прототипа к правильному прототипу и предоставив правильные аргументы самостоятельно. Приведение указателя функции необходимо, чтобы избежать продвижения аргументов по умолчанию, но даже без приведения вам все равно придется отправлять подписи вручную для доступа к правильным членам объединения. Процесс может быть автоматизирован с использованием языка сценариев по вашему выбору для генерации кода C из списка подписей.

0 голосов
/ 12 мая 2010

Распакуйте ваши аргументы в переменные, а затем вызовите функцию.

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]);

Вам также необходимо проверить, не переполняется ли массив a.

...