2010-05-12 7 views
2

Étant donné que j'ai un pointeur sur une fonction (fournie par dlsym() par exemple) et une liste chaînée d'arguments typés, comment puis-je construire un appel de fonction C avec ces arguments?Construire un appel de fonction en C

Exemple:

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

Le système d'exploitation est Linux. Je voudrais que la solution soit portable sur l'architecture MIPS, PPC et x86 (tous les 32 bits), en utilisant GCC comme compilateur.

Merci!

+0

... préparez-vous à un piratage d'assemblage, car pour autant que je sache, le pur C ne le fait pas. –

+1

... ou vous pouvez simplement utiliser la bibliothèque pratique. –

Répondre

2

La prise en charge de signatures de fonctions arbitraires est impossible avec la norme C (au moins, je ne connais aucun moyen de le faire). Si vous en avez besoin, j'irais avec libffi comme Tom suggested.

S'il n'y a qu'un nombre limité de signatures que vous souhaitez prendre en charge, vous pouvez examiner les champs de type et répartir l'appel de manière appropriée en transtypant le pointeur de fonction sans prototype sur le prototype correct. Lancer le pointeur de fonction est nécessaire pour éviter la promotion des arguments par défaut, mais même sans la distribution, vous devez toujours distribuer manuellement les signatures pour accéder aux membres de syndicat corrects. Le processus peut être automatisé en utilisant le langage de script de votre choix pour générer le code C à partir d'une liste de signatures.

0

Déballez vos arguments en variables, puis appelez la fonction.

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

Vous devrez également vérifier de ne pas déborder du tableau a.

+0

C'est un (tagged) 'union', pas un' struct'. – kennytm

+0

Cela ne fonctionnera pas puisque 'function' n'a pas le bon type. – interjay

+0

'function' est de type' int (*)() ', qui en C est équivalent' int (*) (...) '. –

6

Vous aurez probablement besoin d'utiliser libffi.

Questions connexes