Question

J'entends souvent les termes "lié de manière statique" et "lié de manière dynamique", souvent en référence à du code écrit en C , C ++ ou C # . De quoi parlent-ils exactement et de quoi lient-ils?

Était-ce utile?

La solution

Il existe (dans la plupart des cas, le code interprété actualisé) deux étapes pour passer du code source (ce que vous écrivez) au code exécutable (ce que vous exécutez).

La première est la compilation qui transforme le code source en modules objets.

Le second lien est ce qui combine les modules d’objet pour former un exécutable.

La distinction est faite, entre autres, en permettant aux bibliothèques tierces d'être incluses dans votre exécutable sans que vous ne voyiez leur code source (telles que des bibliothèques pour l'accès à la base de données, les communications réseau et les interfaces utilisateur graphiques), ou pour la compilation de code dans différentes langues (C et code d'assemblage, par exemple), puis les lier ensemble.

Lorsque vous reliez de manière statique à un fichier exécutable, le contenu de ce fichier est inclus au moment de la liaison. En d'autres termes, le contenu du fichier est physiquement inséré dans l'exécutable que vous allez exécuter.

Lorsque vous liez dynamiquement , un pointeur sur le fichier lié (le nom du fichier, par exemple) est inclus dans l'exécutable et le contenu de ce fichier n'est pas inclus dans le lien. temps. Ce n’est que lorsque vous exécuterez ultérieurement le fichier exécutable que ces fichiers liés dynamiquement sont achetés et qu’ils ne le sont que dans la copie en mémoire de l’exécutable, pas celle sur le disque.

Il s’agit essentiellement d’une méthode de liaison différée. Il existe même une méthode différée more (appelée liaison tardive sur certains systèmes) qui n'apporte pas le fichier lié dynamiquement tant que vous n'avez pas réellement essayé d'appeler une fonction à l'intérieur de celui-ci.

Les fichiers liés statiquement sont "verrouillés" sur l'exécutable au moment du lien afin qu'ils ne changent jamais. Un fichier lié dynamiquement référencé par un exécutable peut changer simplement en remplaçant le fichier sur le disque.

Cela permet de mettre à jour les fonctionnalités sans avoir à lier de nouveau le code; le chargeur se reconnecte chaque fois que vous l’exécutez.

C’est à la fois bon et mauvais: d’une part, cela facilite les mises à jour et les corrections de bogues, d’autre part, les programmes peuvent cesser de fonctionner si les mises à jour sont incompatibles - c’est parfois à l’origine du redoutable "enfer des DLL". ; certaines personnes mentionnent que des applications peuvent être endommagées si vous remplacez une bibliothèque liée dynamiquement par une autre non compatible (les développeurs qui le font devraient s’attendre à être traqués et punis sévèrement, en passant).

Comme exemple , examinons le cas d’un utilisateur compilant son fichier main.c pour la liaison statique et dynamique.

Phase     Static                    Dynamic
--------  ----------------------    ------------------------
          +---------+               +---------+
          | main.c  |               | main.c  |
          +---------+               +---------+
Compile........|.........................|...................
          +---------+ +---------+   +---------+ +--------+
          | main.o  | | crtlib  |   | main.o  | | crtimp |
          +---------+ +---------+   +---------+ +--------+
Link...........|..........|..............|...........|.......
               |          |              +-----------+
               |          |              |
          +---------+     |         +---------+ +--------+
          |  main   |-----+         |  main   | | crtdll |
          +---------+               +---------+ +--------+
Load/Run.......|.........................|..........|........
          +---------+               +---------+     |
          | main in |               | main in |-----+
          | memory  |               | memory  |
          +---------+               +---------+

Vous pouvez voir dans le cas statique que le programme principal et la bibliothèque d'exécution C sont liés au moment de la liaison (par les développeurs). Étant donné que l'utilisateur ne peut généralement pas relier l'exécutable, il est bloqué par le comportement de la bibliothèque.

Dans le cas dynamique, le programme principal est lié à la bibliothèque d'importation C runtime (quelque chose qui déclare ce qu'il y a dans la bibliothèque dynamique mais ne le pas défini ). Cela permet à l'éditeur de liens de se lier même si le code actuel est manquant.

Ensuite, au moment de l'exécution, le chargeur du système d'exploitation établit une liaison tardive du programme principal avec la DLL d'exécution C (bibliothèque de liens dynamiques ou bibliothèque partagée ou autre nomenclature).

Le propriétaire du runtime C peut créer une nouvelle DLL à tout moment pour fournir des mises à jour ou des corrections de bugs. Comme indiqué précédemment, cela présente à la fois des avantages et des inconvénients.

Autres conseils

Je pense qu'une bonne réponse à cette question devrait expliquer ce qu'est le lien c'est .

Lorsque vous compilez du code C (par exemple), il est traduit en langage machine. Juste une séquence d'octets qui, lorsqu'elle est exécutée, amène le processeur à ajouter, soustraire, comparer, "goto", lire la mémoire, écrire de la mémoire, ce genre de chose. Ce contenu est stocké dans des fichiers objets (.o).

Maintenant, il y a longtemps, les informaticiens ont inventé ce "sous-programme". chose. Exécutez-ce-morceau-de-code-et-retour-ici. Ils ont vite compris que les sous-programmes les plus utiles pouvaient être stockés dans un emplacement spécial et utilisés par tout programme qui en avait besoin.

À l’origine, les programmeurs devaient entrer l’adresse mémoire dans laquelle se trouvaient ces sous-programmes. Quelque chose comme CALL 0x5A62 . C’était fastidieux et problématique si ces adresses de mémoire devaient être changées.

Le processus a donc été automatisé. Vous écrivez un programme qui appelle printf () et le compilateur ne connaît pas l'adresse mémoire de printf . Ainsi, le compilateur écrit simplement CALL 0x0000 et ajoute une note au fichier objet indiquant que "doit remplacer cette 0x0000 par l'emplacement mémoire de printf ".

Liaison statique signifie que le programme de l'éditeur de liens (le programme GNU s'appelle ld ) ajoute printf directement dans votre fichier exécutable et remplace 0x0000 par l'adresse printf . Cela se produit lorsque votre exécutable est créé.

Le couplage dynamique signifie que l'étape ci-dessus ne se produit pas. Le fichier exécutable still contient une note indiquant que "doit remplacer 0x000 par l'emplacement mémoire de printf". Le chargeur du système d’exploitation doit trouver le code printf, le charger en mémoire et corriger l’adresse CALL, à chaque exécution du programme .

Il est courant que les programmes appellent certaines fonctions qui seront liées statiquement (les fonctions de bibliothèque standard telles que printf sont généralement liées statiquement) et d'autres fonctions liées dynamiquement. Les statiques " deviennent partie " des exécutables et des dynamiques " rejoindre "" lorsque l'exécutable est exécuté.

Les deux méthodes présentent des avantages et des inconvénients, ainsi que des différences entre les systèmes d'exploitation. Mais puisque vous n'avez pas demandé, je vais terminer ici.

Les bibliothèques liées statiquement sont liées lors de la compilation. Les bibliothèques liées dynamiquement sont chargées au moment de l'exécution. La liaison statique coud le bit de bibliothèque dans votre exécutable. La liaison dynamique cuit uniquement dans une référence à la bibliothèque; les bits de la bibliothèque dynamique existent ailleurs et pourraient être échangés ultérieurement.

Parce qu'aucun des messages ci-dessus ne montre en réalité comment lier statiquement quelque chose et voir que vous l'avez fait correctement, je vais donc aborder ce problème:

Un simple programme en C

#include <stdio.h>

int main(void)
{
    printf("This is a string\n");
    return 0;
}

Lier dynamiquement le programme C

gcc simpleprog.c -o simpleprog

Et exécutez fichier sur le binaire:

file simpleprog 

Et cela montrera qu'il est lié dynamiquement quelque chose comme:

"Simpleprog: ELF exécutable LSB 64 bits, x86-64, version 1 (SYSV), lié dynamiquement (utilise des bibliothèques partagées), pour GNU / Linux 2.6.26, BuildID [sha1] = 0xf715572611a8b04f686809d90d1c0d75c6028f0,

Lions plutôt le programme de manière statique cette fois-ci:

gcc simpleprog.c -static -o simpleprog

Le fichier en cours d'exécution sur ce binaire lié de manière statique affichera:

strace ./simpleprog

"Simpleprog: ELF exécutable LSB 64 bits, x86-64, version 1 (GNU / Linux), lié statiquement, pour GNU / Linux 2.6.26, BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b2, non rayé " >

Et vous pouvez voir qu'il est heureusement lié statiquement. Malheureusement, toutefois, toutes les bibliothèques ne sont pas simples à lier statiquement de cette façon et peuvent nécessiter un effort supplémentaire en utilisant libtool ou en liant le code objet et les bibliothèques C à la main.

Heureusement, de nombreuses bibliothèques C intégrées, telles que musl , offrent des options de liaison statique pour presque tous les voire tous de leurs bibliothèques.

Maintenant strace le binaire que vous avez créé et vous pouvez voir qu’aucune bibliothèque n’a été accédée avant le début du programme:

<*>

Comparez maintenant avec la sortie de strace sur le programme lié dynamiquement et vous verrez que la structure de la version liée de manière statique est beaucoup plus courte!

(Je ne connais pas C #, mais il est intéressant d'avoir un concept de liaison statique pour un langage de machine virtuelle)

La liaison dynamique implique de savoir comment trouver une fonctionnalité requise pour laquelle vous n’avez qu’une référence à partir de votre programme. Votre langue d’exécution ou votre système d’exploitation recherche un morceau de code dans le cache de système de fichiers, de réseau ou de code compilé, correspondant à la référence, puis prend plusieurs mesures pour l’intégrer à l’image de votre programme dans la mémoire, comme le déplacement. Ils sont tous terminés au moment de l'exécution. Cela peut être fait manuellement ou par le compilateur. Il est possible de mettre à jour avec un risque de gâchis (à savoir, l'enfer de DLL).

La liaison statique est faite au moment de la compilation, vous indiquez au compilateur où se trouvent toutes les pièces fonctionnelles et vous lui demandez de les intégrer. Il n'y a pas de recherche, pas d'ambiguïté, pas de possibilité de mettre à jour sans recompiler. Toutes vos dépendances ne font qu'un avec votre image de programme.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top