Création d'un module de système (chargement dynamique) dans C
Comment peut-on aller sur le chargement de code C compilé au moment de l'exécution, et puis l'appel de fonctions en son sein? Pas simplement l'appel exec().
EDIT: Le programme de chargement du module est en C.
- Excellente question. Beaucoup de gens savent comment le faire, mais ceux qui ne feraient bien d'apprendre cette technique précieuse.
Vous devez vous connecter pour publier un commentaire.
Dans Linux/UNIX, vous pouvez utiliser la POSIX
dlopen
/dlsym
/dlerror
/dlclose
fonctions dynamiquement ouvert de partage de bibliothèques et l'accès des symboles (y compris les fonctions) qu'ils fournissent, voir la page de man pour plus de détails.dlopen est le chemin à parcourir. Voici quelques exemples:
Chargement d'un plugin avec dlopen:
La compilation ci-dessus:
Ensuite, en supposant que cette API pour les plugins:
Trouver l'adresse de la fonction init() dans le plugin:
Avec l'autre fonction query(), qui retourne une valeur:
Vous pouvez récupérer l'exemple complet sur la ligne.
Le voir, cette question a été répondu, mais la pensée d'autres personnes intéressées par le sujet peuvent apprécier une plate-forme de l'exemple d'un vieux plugin en fonction de l'application. L'exemple fonctionne sur win32 et linux, et seaches et appelle une fonction appelée 'constructeur' dans l'chargé dynamiquement .donc ou .dll spécifiée dans le fichier argument. L'exemple est en c++, mais la procédure devrait être la même pour les c.
Pourrait aussi être mentionné que si le module qui est des fonctions que vous souhaitez appeler, est écrit en c++, il faut déclarer la fonction avec extern "C" comme:
pour les utilisateurs de GNU/Linux
dynamique de chargement de la bibliothèque est un mécanisme qui, avec l'aide de cela, nous pouvons lancer notre programme, et au moment de l'exécution, décider quelle fonction, nous voulons utiliser. Je pense que dans certains cas
static
variable est également possible.D'abord commencer par voir
man 3 dlopen
ou consultez-le en ligneLe fichier d'en-tête qui est nécessaire est:
dlfcn
et depuis cela ne fait pas partie de la norme que vous devrait comme à votre fichier objet avec cette bibliothèque:libdl.(so/a)
et, par conséquent, vous avez besoin de quelque chose comme:alors vous avez un nom de fichier
a.out
et vous pouvez l'exécuter MAIS il ne fonctionne pas correctement et je vais vous expliquer pourquoi.Un exemple complet:
première caisse 2 fichiers
func1.c
etfunc2.c
respectivement. Nous voulons appeler ces fonctions au moment de l'exécution.la touche func.c
func2.c
Maintenant, nous avons 2 fonctions, nous allons faire nos modules:
pour l'esprit curieux à propos de
-fPIC
=> PICMaintenant, vous avez un
dynamic library
noms:libfunc.so
Nous allons créer le programme principal (=
temp.c
) qui souhaite utiliser ces fonctions.fichiers d'en-tête
et le programme principal
Maintenant nous avons juste besoin de compiler ce code (=
temp.c
), donc essayer:Il ne fonctionne pas! POURQUOI facile; parce que notre
a.out
programme ne sais pas où trouver la bibliothèque connexe:libfunc.so
et, par conséquent, il nous ditcannot not open ...
comment dire le programme (=
a.out
) pour trouver sa bibliothèque?ld
de l'éditeur de liensLD_LIBRARY_PATH
première manière, avec l'aide de
ld
utilisation
-Wl,-rpath,
etpwd
et mettre le chemin comme un argumentdeuxième façon
et troisième voie
vous avez
libfunc.so
en vous chemin d'accès actuel, donc vous pouvez le copier dans un chemin d'accès standard pour les bibliothèques.vous pouvez le supprimer de
/usr/lib
et de l'utiliser. C'est à vous.NOTE
comment savoir que notre
a.out
connaît son chemin?facile:
comment nous pouvons l'utiliser dans c++?
Aussi longtemps que je sais que vous ne pouvez pas parce que
g++
mangles les noms de fonction alors quegcc
n'est pas ainsi que vous devez utiliser:extern "C" int func1();
par exemple.Pour plus de détails, voir les pages de manuel Linux et la programmation de livres.
Également vous pouvez regarder cpluff. C'est un plugin de gestion de la bibliothèque de la pure c.
Si vous êtes prêt à envisager le cadre, Qt fournit QPluginLoader: Qt 5 docs (ou pour les vieux Qt 4.8 docs voir ici)
Si vous avez besoin de plus de précision, de contrôle, Qt fournit également un moyen de charger des bibliothèques à la volée avec QLibrary: Qt 5 docs (ou pour les vieux Qt 4.8 docs voir ici)
Encore mieux, ce sont portable sur l'ensemble des plates-formes.
Dynamique des langages comme Perl faire cela tout le temps. L'interpréteur Perl est écrit en C, et de nombreux modules Perl sont partiellement écrit en C. Lorsque ces modules sont nécessaires, la compilation C composants sont chargés dynamiquement à la volée. Comme indiqué dans une autre réponse, le mécanisme de stockage de ces modules est Dll sur windows, et des bibliothèques partagées (.donc les fichiers) sur UNIX. Je crois que l'appel pour le chargement d'une bibliothèque partagée pour UNIX dlopen(). Vous pouvez probablement trouver des conseils pour accomplir cette sur UNIX en commençant avec la documentation de l'appel. Pour Windows, vous avez besoin à la recherche des Dll et apprendre à les charger dynamiquement à l'exécution. [Ou peut-être passer par Cygwin UNIX couche d'émulation, qui serait probablement vous permettre d'utiliser les mêmes appels sur Windows comme sur UNIX, mais je ne le recommande pas sauf si vous utilisez déjà et la compilation de contre Cygwin.]
Notez que ceci est différent de la simple liaison à l'encontre d'une bibliothèque partagée. Si vous savez à l'avance exactement ce code vous permettra d'appel, vous pouvez construire contre une bibliothèque partagée et de la construction sera "lié de façon dynamique" à la bibliothèque; sans aucune manipulation spéciale de vous les routines de la bibliothèque sera chargé en mémoire, que si votre programme fait appelle. Mais vous ne pouvez pas faire cela si vous avez l'intention d'écrire quelque chose capable de chargement de tous les arbitraire code objet, le code que vous ne pouvez pas identifier maintenant, au moment de la construction, mais sont plutôt en attente d'être sélectionné en quelque sorte, au moment de l'exécution. Pour cela, vous devrez utiliser dlopen() et ses Fenêtres cousins.
Vous pourriez regarder la façon dont Perl ou autres langages dynamiques le faire pour voir des exemples concrets. La bibliothèque Perl responsables de ce type de chargement dynamique est DynaLoader; il a à la fois un Perl et C composant, je crois. Je suis certain que d'autres langages dynamiques comme Python ont quelque chose de similaire qui vous pourriez plutôt regarder; et le Perroquet, la machine virtuelle pour les inedits de Perl 6, sûrement a un mécanisme pour le faire aussi bien (ou le seront dans le futur).
Pour cette question, Java accomplit par son JNI (Java Native Interface), de sorte que vous pourriez probablement regarder le code source pour OpenJDK pour voir comment Java accomplit cette sur UNIX et Windows.
Il y a une approche de DIY. Bien que la méthode (et la possibilité) de le faire varie d'un système à l'autre, l'idée générale est d'ouvrir un fichier, lire le contenu du fichier dans la mémoire, faire dit mémoire exécutable, l'initialisation d'un pointeur de fonction à une position valide au sein de ce mémoire, et vous y êtes.
Bien sûr, c'est en supposant que c'est juste le code de l'exécutable - très peu probable. Le code exige probablement les données à charger dans la RAM aussi, et peut exiger de l'espace mondial/variables statiques. Vous pouvez charger tout cela vous-même, mais vous auriez besoin d'aller dans le code exécutable et de régler toutes les références de mémoire en elle.
La plupart des systèmes d'exploitation permettent la liaison dynamique, qui fait tout pour vous.
Sous Windows, c'est comment je le fais:
Générer/compiler/lien étapes prennent généralement moins d'une seconde.