Sous Windows, lorsque je compile du code C / C ++ dans un projet DLL dans MSVC, j'obtiens 2 fichiers:
MyDll.dll
MyDll.lib
où, pour autant que je comprends, MyDll.lib
contient une sorte de tableau de pointeurs indiquant les emplacements des fonctions dans la DLL. Lorsque vous utilisez cette DLL, par exemple dans un fichier exe, elle MyDll.lib
est intégrée dans le fichier exe pendant la liaison, de sorte qu'en cours d'exécution, elle "sait" où se trouvent les fonctions MyDll.dll
et peut les utiliser.
Mais si je compile le même code sous Linux, je ne reçois qu'un seul fichier MySo.so
sans MySo.a
(l'équivalent d'un lib
fichier sous Linux), alors comment un fichier exécutable sous Linux sait-il où se trouvent les fonctions MySo.so
si rien n'y est intégré pendant la liaison?
L'éditeur de liens MSVC peut lier des fichiers d'objets (.obj) et des bibliothèques d'objets (.lib) pour produire un .EXE ou un .DLL.
Pour établir un lien avec une DLL, le processus dans MSVC consiste à utiliser une soi-disant bibliothèque d'importation (.LIB) qui sert de lien entre les noms de fonction C et la table d'exportation de la DLL (dans une DLL, une fonction peut être exportée par nom ou par ordinal - ce dernier était souvent utilisé pour les API non documentées).
Cependant, dans la plupart des cas, la table d'exportation DLL contient tous les noms de fonction et donc la bibliothèque d'importation (.LIB) contient des informations largement redondantes (" fonction d'importation ABC -> fonction exportée ABC ", etc.).
Il est même possible de générer un .LIB à partir d'un .DLL existant.
Les éditeurs de liens sur d'autres plates-formes n'ont pas cette "fonctionnalité" et peuvent se lier directement aux bibliothèques dynamiques.
la source
La différence que vous voyez est davantage un détail d'implémentation - sous le capot, Linux et Windows fonctionnent de la même manière - vous codez appelle une fonction de stub qui est liée statiquement dans votre exécutable et ce stub charge ensuite DLL / shlib si nécessaire (en cas de retard chargement , sinon la bibliothèque est chargée au démarrage du programme) et (au premier appel) résout le symbole via
GetProcAddress
/dlsym
.La seule différence est que sous Linux, ces fonctions de stub (appelées stubs PLT) sont générées dynamiquement lorsque vous liez votre application à une bibliothèque dynamique (la bibliothèque contient suffisamment d'informations pour les générer), tandis que sous Linux, elles sont plutôt générées lorsque la DLL elle-même est créé, dans un
.lib
fichier séparé .Les deux approches sont si similaires qu'il est en fait possible d'imiter les bibliothèques d'importation Windows sur Linux (voir le projet Implib.so ).
la source
Sous Linux, vous passez
MySo.so
à l'éditeur de liens et il est capable d'extraire uniquement ce qui est nécessaire pour la phase de liaison, en mettant une référence quiMySo.so
est nécessaire au moment de l'exécution.la source
.dll
ou.so
sont des bibliothèques partagées (liées au moment de l'exécution), alors que.a
et.lib
est une bibliothèque statique (liée au moment de la compilation). Ce n'est pas une différence entre Windows et Linux.La différence est, comment sont-elles gérées. Remarque: la différence ne concerne que les douanes, comment sont-elles utilisées. Il ne serait pas trop difficile de faire des builds Linux sur Windows et vice versa, sauf que pratiquement personne ne fait ça.
Si nous utilisons une DLL, ou si nous appelons une fonction même à partir de notre propre binaire, il existe un moyen simple et clair. Par exemple, en C, nous voyons que:
Cependant, au niveau asm, il pourrait y avoir de nombreuses différences. Par exemple, sur x86, un
call
opcode est exécuté et42
est donné sur la pile. Ou dans certains registres. Ou n'importe où. Personne ne sait qu'avant d'écrire la DLL , comment elle sera utilisée. Ou comment les projets voudront l'utiliser, possible écrit avec un compilateur (ou dans un langage!) Qui n'existe même pas maintenant (ou est-il inconnu pour les développeurs de la dll).Par exemple, par défaut, C et Pascal placent les arguments (et récupèrent les valeurs de retour) de la pile - mais ils le font dans un ordre différent . Vous pouvez également échanger des arguments entre vos fonctions dans les registres par une optimisation - dépendante du compilateur -.
Comme vous le voyez correctement, la coutume de Windows est que la construction d'une DLL, nous créons également un minimum
.a
/.lib
avec elle. Cette bibliothèque statique minimale n'est qu'un wrapper, les symboles (fonctions) de cette DLL sont atteints à travers elle. Cela permet d'effectuer les conversions d'appels de niveau asm requises.Son avantage est la compatibilité. Son inconvénient est que si vous n'avez qu'un .dll, vous pouvez avoir du mal à comprendre comment ses fonctions doivent être appelées. Cela fait de l'utilisation des DLL une tâche de piratage, si le développeur de la DLL ne vous donne pas le
.a
. Ainsi, il sert principalement à des fins de fermeture, par exemple, il est donc plus facile d'obtenir de l'argent supplémentaire pour les SDK.Son autre inconvénient est que même si vous utilisez une bibliothèque dynamique, vous devez compiler statiquement ce petit wrapper.
Sous Linux, l'interface binaire des DLL est standard et suit la convention C. Ainsi, aucun
.a
n'est requis et il existe une compatibilité binaire entre les bibliothèques partagées, en échange, nous n'avons pas les avantages de Microsoft Custom.la source