web-dev-qa-db-fra.com

Bibliothèques partagées: méthode Windows vs Linux

J'ai une question rapide sur les bibliothèques partagées Windows (DLL) par rapport aux bibliothèques partagées Linux (SO).

Pourquoi est-ce que lorsque vous créez un Windows DLL, il nécessite que le programme client soit également lié à une bibliothèque statique (fichier .lib), mais les applications créées sous Linux ne nécessitent aucune liaison contre une telle statique bibliothèque.

Cela a-t-il quelque chose à voir avec la relocalisation de code et autres? Merci.

23
QAH

Pas vraiment avec la relocalisation de code, c'est un problème totalement différent. Il s'agit d'une différence d'architecture:

  • Sous Windows, un DLL est comme un exécutable (EXE). La principale différence entre un EXE et un DLL est que l'EXE a un point d'entrée ( main/WinMain) et il peut donc être utilisé pour démarrer un processus, tandis que les DLL ne peuvent être chargées que dans un processus préexistant. Mais voir (1)

  • Sous Linux, un .so fonctionne comme une bibliothèque statique (.a). La principale différence est que le fichier .so peut être lié à un programme en cours d'exécution, tandis que le fichier .a ne peut être lié que lors de la compilation du programme.

Une conséquence de cette approche est que sous Linux, le même fichier peut être utilisé pour construire et exécuter le programme. Mais sous Windows, vous avez besoin d'une bibliothèque appropriée (LIB) pour lier le programme. En fait, la bibliothèque qui correspond à un DLL n'a généralement rien de plus que les noms des fonctions, pour satisfaire l'éditeur de liens, et les talons pour effectuer la relocalisation. Mais voir (2)

(1) Eh bien, les DLL ont aussi un point d'entrée, mais il n'est pas utilisé comme fonction principale, tout comme une sorte de hook d'initialisation/finalisation.

(2) Certains éditeurs de liens sont suffisamment intelligents pour pouvoir, dans certains cas simples, se lier à un DLL en utilisant le DLL lui-même, sans avoir besoin de un fichier LIB supplémentaire. Je pense qu'au moins l'éditeur de liens MinGW peut le faire.

24
rodrigo

Pourquoi est-ce que lorsque vous créez un Windows DLL, il nécessite que le programme client soit également lié à une bibliothèque statique (fichier .lib), mais les applications créées sous Linux ne nécessitent aucune liaison contre une telle statique bibliothèque.

Il s'agit d'une décision de conception historique prise par Microsoft afin que l'éditeur de liens puisse ajouter DLL références dans un exécutable sans avoir une version particulière de DLL étant présente au lien) La raison en était qu'il y avait toujours différentes versions de Windows, avec différentes versions de DLL. À cette époque, Microsoft coopérait également avec IBM sur OS/2 et le plan était que les programmes Windows pouvaient être exécutés sur OS/2 également. Eh bien, Microsoft a décidé de "backstab" OS/2, en roulant leur propre OS de qualité professionnelle, basé sur le noyau NT. Mais cela signifiait que pour le développement, vous vouliez que les développeurs puissent se lier aux DLL du système , sans que toutes les différentes variantes de DLL soient disponibles. Au lieu de cela, un "modèle" de liaison dynamique aurait été utilisé pour créer à la fois le DLL et les exécutables ( les deux étant au format PE), qui sont notamment .lib fichiers, qui ne sont pas du tout des bibliothèques, mais simplement des tables de symboles et ordinales (c'est un fait peu connu, mais les symboles binaires PE peuvent être chargés non seulement par un identifiant de chaîne, mais aussi par un nombre entier, ce qu'on appelle l'ordinal ).

Un effet secondaire des ordinaux est qu'ils permettent de masquer les symboles lisibles par l'homme, afin que vous puissiez utiliser la DLL uniquement si vous connaissiez la relation de fonction ordinale ← →.

Sous Unix, la tradition était: "vous le construisez sur le système sur lequel vous allez l'exécuter", ou "vous avez tous les fichiers système cible en place". Il n'y a donc jamais eu d'incitation à séparer les informations de bibliothèque et de liaison. Techniquement, il en irait de même pour les DLL. Les PE peuvent exporter un symbole et une table de relocalisation, ce que font les DLL, et un éditeur de liens pourrait récupérer toutes les informations dont il a besoin, très bien.

Si vous deviez masquer des symboles avec des objets partagés Unix, vous le feriez normalement en utilisant un seul struct avec tous les pointeurs de fonction, et en exportant uniquement une instance constante globale de cette structure par nom, qui contient beaucoup de pointeurs non nommés explicitement. Vous pouvez cependant faire exactement la même chose avec les DLL Windows.

TL; DR: La raison en est non pas technique, mais une décision de marketing et de distribution.

35
datenwolf

Sous Windows, le programme client n'a pas besoin de se lier à une bibliothèque statique pour accéder aux fonctions d'une DLL. La liaison dynamique peut se produire entièrement au moment de l'exécution sans même que le programme client soit conscient de l'existence de la DLL au moment de sa compilation).

Par exemple, si vous souhaitez appeler un nom de fonction "foo" dans un DLL nommé "bar.dll", vous pouvez écrire du code comme ceci:

HINSTANCE hinst = LoadLibrary("bar.dll");
FARPROC foo = GetProcAddress(hinst, "foo");
foo();

Et "foo" et "bar.dll" auraient pu facilement être des valeurs qui n'ont été établies qu'au moment de l'exécution, par exemple via un fichier de configuration ou une autre entrée utilisateur.

Le but de la bibliothèque statique est d'automatiser ce processus de chargement dynamique, en créant des stubs qui semblent être des fonctions normales en ce qui concerne le programme client, mais qui sont liés à DLL lors de l'exécution) . En règle générale, cette liaison se produit au moment du chargement du processus client, mais des bibliothèques peuvent également être générées qui se chargeront et se lieront à la demande, de sorte que la DLL ne sera pas mise en mémoire tant qu'elle ne sera pas C'est la bibliothèque statique qui détermine le moment de la liaison.

Pour la plupart, un compilateur peut générer ces bibliothèques automatiquement, donc techniquement, elles ne sont pas nécessaires lors de la simple liaison avec les fonctions DLL. Cependant, la seule exception à cela (que je connais) ) est lors de la liaison à des variables partagées.

Dans un Windows DLL vous pouvez créer un segment de données partagé avec des variables accessibles par n'importe quel processus qui a chargé cette DLL. Les informations sur la taille et les types de ces variables sont stockées dans le fichier associé bibliothèque statique et ne peut pas être déterminé à partir de la seule DLL. Pour accéder à ces variables, le programme client doit se lier à la bibliothèque statique de cette DLL.

Pour autant que je sache, les bibliothèques partagées Linux ne prennent pas en charge un tel concept.

Mise à jour

Je dois également mentionner que sous Windows, il est possible de créer un DLL où les points d'entrée de fonction ne sont exportés que par ordinal (nombre) plutôt que par nom. Cela peut être considéré comme une forme de masquage des données et sera généralement utilisé lorsqu'un implémenteur souhaite que certaines fonctions restent privées.

Une personne ayant accès à la bibliothèque statique pourrait appeler ces fonctions par leur nom, car la bibliothèque aurait les détails reliant le nom de la fonction à l'ordinal approprié. Toute personne qui ne disposait que de la DLL devra se lier manuellement aux fonctions par ordinal ou générer sa propre bibliothèque statique avec des noms composés.

4
James Holderness