N-PN White-Hat Project
[C] Système de plugins "simpliste" - Version imprimable

+- N-PN White-Hat Project (https://n-pn.fr/forum)
+-- Forum : Programmation (https://n-pn.fr/forum/forumdisplay.php?fid=72)
+--- Forum : Langages compilés (https://n-pn.fr/forum/forumdisplay.php?fid=25)
+--- Sujet : [C] Système de plugins "simpliste" (/showthread.php?tid=2152)



[C] Système de plugins "simpliste" - supersnail - 30-08-2012

Bonjour,

Je partage ici une petit système de "plugins" que j'ai développé en bidouillant un peu avec le C. Cependant avant de balancer directement le code, quelques petites explications s'imposent.

I - Fonctionnement général

Le plugin est ici une bibliothèque "liée dynamiquement", c'est-à-dire une DLL sous Windows, ou un .so sous GNU/Linux, qui sera chargée dynamiquement par le programme (via les fonctions LoadLibrary/GetProcAddress sous Windows, ou dlopen/dlsym sous GNU/Linux).
Ce programme appelle ensuite la fonction plugin_init, qui prend pour argument une structure nommée plugin_interface. Cette structure est comparable à une interface C++, c'est-à-dire des pointeurs vers des fonctions. Pour mon programme de test, ma structure ressemble à ceci:

Code :
typedef struct _plugin_int {
    int (*SumFunction) (int a, int b);
    void (*saySomething) (char *toSay);
} plugin_interface;
, mais libre à vous de rajouter d'autres fonctions (qu'il vous faudra malgré tout implémenter dans votre programme). L'initialisation de la structure devra se faire avant l'appel aux plugins (logique me direz-vous :p).

Maintenant, pourquoi tout ce bazar fonctionne ? La réponse est relativement simple. En réalité, le plugin est chargé dans l'espace mémoire du processus, ainsi il peut accéder à la mémoire de celui-ci (et par le fait, manipuler ses données). Le code (machine) résidant lui aussi en mémoire, notre plugin y a aussi accès, et il peut ainsi exécuter les fonctions de notre programme hôte (qui sera traduit en assembleur par un "call eax", eax contenant l'adresse de la fonction à appeler).

II - Le code

Le fichier "def.h" (à inclure dans chacun des plugins)

Code :
#ifndef _DEF_H
#define _DEF_H

typedef struct _plugin_int {
    int (*SumFunction) (int a, int b);
    void (*saySomething) (char *toSay);
} plugin_interface;

#endif

Le code du programme (program.c)

Code :
#include <stdio.h>
#include <dlfcn.h>

#include "def.h"

int sum (int a, int b) {
    printf ("Sum invoked by plugin : %d\n", (a + b));
    return a+b;
}

void saySomething ( char *something) {
    printf ("Plugin says: %s\n", something);
}

void main() {
    // Initialise les fonctions à emmener dans le plugin
    plugin_interface myFunc;
    myFunc.SumFunction = sum;
    myFunc.saySomething = saySomething;
    
    int handle = (int) dlopen("./wtf.so", RTLD_LAZY);
    printf ("Handle is %x\n", handle);
    int (*initPtr) (plugin_interface plug);
    initPtr = dlsym (handle, "plugin_init");
    if(!initPtr) {
        printf ("Plugin load failed\n");
    }
    else {
        initPtr(myFunc);
    }
}

Le code du plugin de test (wtf.c)

Code :
#include "def.h"

int plugin_init (plugin_interface plug) {
    plug.saySomething ("Hello from the what the fuck !");
    plug.SumFunction (21, 21);
    return 1;
}

Le Makefile

Code :
all: program.o wtf.o
    gcc -o program program.o -ldl
    gcc -o wtf.so -shared wtf.o
    
program.o: program.c
    gcc -c -o program.o program.c
    
wtf.o: wtf.c
    gcc -c -o wtf.o wtf.c

Edit: le code fonctionne juste pour GNU/Linux, pour les windowsiens, renseignez-vous sur les fonctions "LoadLibrary" et "GetProcAddress" Wink (la MSDN est votre amie)


RE: [C] Système de plugins "simpliste" - ark - 30-08-2012

C'est très intéressant tout ça, le fonctionnement est facile a mettre en place, c'est pas mal. Smile
Par contre le "void main()" c'est crade...


RE: [C] Système de plugins "simpliste" - supersnail - 30-08-2012

Je sais, mais c'est juste un PoC que j'ai pondu là :p (le code "en l'état" est dégueulasse et j'en assume l'entière responsabilité ^^)


RE: [C] Système de plugins "simpliste" - ark - 30-08-2012

s'pece de sale porc! :p
Bon, faut vraiment que je code un truc intéressant a poster moi x]


RE: [C] Système de plugins "simpliste" - b0fh - 30-08-2012

Il manque un mécanisme pour permettre au programme principal d'appeler des fonctions du plugin (ce qui est peut-être plus fréquent que l'inverse.)

On pourrait répéter les dlopen() pour obtenir plusieurs symboles, mais autant ajouter un 2e struct pour les appels dans l'autre sens !


RE: [C] Système de plugins "simpliste" - supersnail - 30-08-2012

En effet, mais comme je l'ai dit, c'est plus un bout de code expérimental qu'un gestionnaire de plugin fiable Wink

Enfin, on peut laisser des fonctions dans l'API qui permet d'enregistrer des "hooks" si besoin (ce qui évite de devoir concevoir une deuxième structure de données), que le programme principal appellera Smile