Was bedeuten „statisch verknüpft“ und „dynamisch verknüpft“?

Lesezeit: 10 Minuten

Benutzer-Avatar
UnkwnTech

Ich höre oft die Begriffe „statisch verknüpft“ und „dynamisch verknüpft“, oft in Bezug auf geschriebenen Code C, C++ oder C#. Was sind sie, wovon sprechen sie genau und was verbinden sie?

Benutzer-Avatar
paxdiablo

Es gibt (in den meisten Fällen, wenn man den interpretierten Code außer Acht lässt) zwei Phasen, um vom Quellcode (was Sie schreiben) zum ausführbaren Code (was Sie ausführen) zu gelangen.

Die erste ist die Kompilierung, die den Quellcode in Objektmodule umwandelt.

Das zweite, das Verknüpfen, ist das, was Objektmodule miteinander kombiniert, um eine ausführbare Datei zu bilden.

Die Unterscheidung wird unter anderem vorgenommen, um Bibliotheken von Drittanbietern in Ihre ausführbare Datei einzubinden, ohne dass Sie deren Quellcode sehen (z. B. Bibliotheken für Datenbankzugriff, Netzwerkkommunikation und grafische Benutzeroberflächen), oder um Code in verschiedenen Sprachen zu kompilieren ( C und Assembler-Code zum Beispiel) und dann alle miteinander verknüpfen.

Wenn du statisch eine Datei in eine ausführbare Datei verlinken, wird der Inhalt dieser Datei zum Zeitpunkt der Verknüpfung eingeschlossen. Mit anderen Worten, der Inhalt der Datei wird physisch in die ausführbare Datei eingefügt, die Sie ausführen werden.

Wenn Sie verlinken dynamisch, ein Zeiger auf die verlinkte Datei (z. B. der Dateiname der Datei) ist in der ausführbaren Datei enthalten, und der Inhalt dieser Datei ist zum Zeitpunkt der Verknüpfung nicht enthalten. Es ist nur, wenn Sie später Lauf die ausführbare Datei, in die diese dynamisch verknüpften Dateien eingekauft werden, und sie werden nur in die In-Memory-Kopie der ausführbaren Datei eingekauft, nicht in die auf der Festplatte.

Es ist im Grunde eine Methode der verzögerten Verlinkung. Es gibt sogar mehr verzögerte Methode (auf einigen Systemen als späte Bindung bezeichnet), die die dynamisch verknüpfte Datei erst einbringt, wenn Sie tatsächlich versuchen, eine darin enthaltene Funktion aufzurufen.

Statisch verknüpfte Dateien sind zum Zeitpunkt der Verknüpfung an die ausführbare Datei „gesperrt“, sodass sie sich nie ändern. Eine dynamisch verknüpfte Datei, auf die von einer ausführbaren Datei verwiesen wird, kann sich ändern, indem einfach die Datei auf der Festplatte ersetzt wird.

Dies ermöglicht Aktualisierungen der Funktionalität, ohne den Code neu verknüpfen zu müssen; Der Loader verbindet sich jedes Mal neu, wenn Sie ihn ausführen.

Das ist sowohl gut als auch schlecht – einerseits ermöglicht es einfachere Updates und Bugfixes, andererseits kann es dazu führen, dass Programme nicht mehr funktionieren, wenn die Updates nicht kompatibel sind – das ist mitunter für die von manchen gefürchtete „DLL-Hölle“ verantwortlich Erwähnen Sie, dass Anwendungen beschädigt werden können, wenn Sie eine dynamisch gelinkte Bibliothek durch eine nicht kompatible ersetzen (Entwickler, die dies tun, sollten übrigens damit rechnen, gejagt und hart bestraft zu werden).


Als ein Beispielschauen wir uns den Fall eines Benutzers an, der seine kompiliert main.c Datei für statisches und dynamisches Linken.

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  |
          +---------+               +---------+

Sie können im statischen Fall sehen, dass das Hauptprogramm und die C-Laufzeitbibliothek zur Verbindungszeit (von den Entwicklern) miteinander verbunden werden. Da der Benutzer die ausführbare Datei normalerweise nicht erneut verknüpfen kann, bleibt er beim Verhalten der Bibliothek hängen.

Im dynamischen Fall ist das Hauptprogramm mit der Importbibliothek der C-Laufzeit verknüpft (etwas, das deklariert, was sich in der dynamischen Bibliothek befindet, dies jedoch nicht tut definieren es). Dadurch kann der Linker verlinken, obwohl der eigentliche Code fehlt.

Dann führt der Betriebssystemlader zur Laufzeit eine späte Verknüpfung des Hauptprogramms mit der C-Laufzeit-DLL (Dynamic Link Library oder Shared Library oder andere Nomenklatur) durch.

Der Eigentümer der C-Laufzeitumgebung kann jederzeit eine neue DLL einfügen, um Updates oder Fehlerbehebungen bereitzustellen. Wie bereits erwähnt, hat dies sowohl Vor- als auch Nachteile.

  • Bitte korrigieren Sie mich, wenn ich falsch liege, aber unter Windows neigt Software dazu, ihre eigenen Bibliotheken in die Installation aufzunehmen, selbst wenn sie dynamisch verknüpft sind. Auf vielen Linux-Systemen mit einem Paketmanager werden viele dynamisch verknüpfte Bibliotheken (“gemeinsam genutzte Objekte”) tatsächlich von Software gemeinsam genutzt.

    – Paul Fischer

    23. November 2008 um 4:57 Uhr

  • @PaulF: Dinge wie die allgemeinen Windows-Steuerelemente, DirectX, .NET usw. werden häufig mit den Anwendungen geliefert, während Sie unter Linux dazu neigen, apt oder yum oder ähnliches zu verwenden, um Abhängigkeiten zu verwalten – also haben Sie in diesem Sinne Recht . Gewinnen Sie Apps, die ihre versenden besitzen Code, da DLLs sie in der Regel nicht teilen.

    – paxdiablo

    23. November 2008 um 6:57 Uhr

  • Es gibt einen besonderen Platz im neunten Kreis der Hölle für diejenigen, die ihre DLLs aktualisieren und die Abwärtskompatibilität brechen. Ja, wenn Interfaces verschwinden oder modifiziert werden, dann fällt die dynamische Verlinkung ins Wasser. Deshalb sollte man es nicht machen. Fügen Sie auf jeden Fall eine function2() zu Ihrer DLL hinzu, aber ändern Sie function() nicht, wenn Leute sie verwenden. Der beste Weg, damit umzugehen, besteht darin, function() so umzucodieren, dass es function2() aufruft, aber nicht Ändern Sie die Signatur von function().

    – paxdiablo

    12. Mai 2010 um 8:26 Uhr

  • @Paul Fisher, ich weiß, das ist spät, aber … die Bibliothek, die mit einer Windows-DLL geliefert wird, ist nicht die vollständige Bibliothek, sondern nur eine Reihe von Stubs, die dem Linker mitteilen, was die DLL enthält. Der Linker kann die Informationen dann automatisch in die EXE-Datei einfügen, um die DLL zu laden, und die Symbole werden nicht als undefiniert angezeigt.

    – Markieren Sie Lösegeld

    23. März 2011 um 22:35 Uhr

  • @Santropedro, Sie haben in jeder Hinsicht Recht, was die Bedeutung der Namen lib, import und DLL betrifft. Das Suffix ist nur eine Konvention, lesen Sie also nicht zu viel hinein (zum Beispiel kann die DLL eine .dll oder .so Erweiterung) – denken Sie an die Antwort als Erklärung der Konzepte anstatt eine genaue Beschreibung zu sein. Und wie im Text steht, ist dies ein Beispiel, das statisches und dynamisches Linken nur für die C-Laufzeitdateien zeigt, also ja, das ist es, was `crt in allen angibt.

    – paxdiablo

    9. Juli 2019 um 20:38 Uhr


Benutzer-Avatar
Artelius

Ich denke, eine gute Antwort auf diese Frage sollte erklären, was das Verlinken ist ist.

Wenn Sie beispielsweise C-Code kompilieren, wird er in Maschinensprache übersetzt. Nur eine Folge von Bytes, die, wenn sie ausgeführt werden, den Prozessor dazu bringen, zu addieren, zu subtrahieren, zu vergleichen, “zu gehen”, Speicher zu lesen, Speicher zu schreiben und so etwas. Dieses Zeug wird in Objektdateien (.o) gespeichert.

Nun, vor langer Zeit haben Informatiker dieses “Unterprogramm”-Ding erfunden. Führen Sie diesen Codeabschnitt aus und kehren Sie hierher zurück. Es dauerte nicht lange, bis sie erkannten, dass die nützlichsten Subroutinen an einem speziellen Ort gespeichert und von jedem Programm verwendet werden konnten, das sie benötigte.

In den frühen Tagen mussten Programmierer die Speicheradresse eingeben, an der sich diese Unterroutinen befanden. Etwas wie CALL 0x5A62. Dies war mühsam und problematisch, sollten diese Speicheradressen jemals geändert werden müssen.

Der Prozess wurde also automatisiert. Sie schreiben ein Programm, das aufruft printf()und der Compiler kennt die Speicheradresse von nicht printf. Der Compiler schreibt also nur CALL 0x0000und fügt der Objektdatei einen Hinweis hinzu, der besagt: „Diese 0x0000 muss durch den Speicherort von ersetzt werden Druckf“.

Statische Verknüpfung bedeutet, dass das Linker-Programm (das GNU-Programm heißt ld) fügt hinzu printf‘s Maschinencode direkt in Ihre ausführbare Datei und ändert 0x0000 in die Adresse von printf. Dies geschieht, wenn Ihre ausführbare Datei erstellt wird.

Dynamische Verknüpfung bedeutet, dass der obige Schritt nicht stattfindet. Die ausführbare Datei still hat eine Notiz, die besagt, dass “0x000 durch den Speicherort von printf ersetzt werden muss”. Der Loader des Betriebssystems muss den printf-Code finden, ihn in den Speicher laden und die CALL-Adresse korrigieren. jedes Mal, wenn das Programm ausgeführt wird.

Es ist üblich, dass Programme einige Funktionen aufrufen, die statisch verknüpft werden (Standardbibliotheksfunktionen wie printf sind normalerweise statisch gelinkt) und andere Funktionen, die dynamisch gelinkt sind. Die statischen “werden Teil” der ausführbaren Datei und die dynamischen “machen mit”, wenn die ausführbare Datei ausgeführt wird.

Beide Methoden haben Vor- und Nachteile, und es gibt Unterschiede zwischen den Betriebssystemen. Aber da Sie nicht gefragt haben, werde ich das hier beenden.

  • Ich auch, aber ich kann nur 1 Antwort auswählen.

    – UnkwnTech

    23. November 2008 um 11:36 Uhr

  • Artelius, ich suche eingehend nach Ihrer Erklärung, wie diese verrückten Dinge auf niedriger Ebene funktionieren. Bitte antworten Sie mit, welche Bücher wir lesen müssen, um fundierte Kenntnisse über die oben genannten Dinge zu erlangen. Danke.

    – Mahesh

    17. Dezember 2008 um 14:38 Uhr

  • Tut mir leid, ich kann keine Bücher vorschlagen. Sie sollten zuerst die Assemblersprache lernen. Dann kann Wikipedia einen guten Überblick über solche Themen geben. Vielleicht möchten Sie sich die GNU ansehen ld Dokumentation.

    – Artelios

    14. April 2009 um 4:49 Uhr

Statisch gelinkte Bibliotheken werden zur Kompilierzeit gelinkt. Dynamisch verknüpfte Bibliotheken werden zur Laufzeit geladen. Statisches Linken backt das Bibliotheksbit in Ihre ausführbare Datei. Dynamisches Linken backt nur einen Verweis auf die Bibliothek ein; Die Bits für die dynamische Bibliothek sind an anderer Stelle vorhanden und könnten später ausgetauscht werden.

Weil keiner der obigen Beiträge tatsächlich zeigen, wie um etwas statisch zu verknüpfen und zu sehen, dass Sie es richtig gemacht haben, also werde ich dieses Problem ansprechen:

Ein einfaches C-Programm

#include <stdio.h>

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

Linken Sie das C-Programm dynamisch

gcc simpleprog.c -o simpleprog

Und Renn file auf der Binärdatei:

file simpleprog 

Und das wird zeigen, dass es etwas wie folgt dynamisch verknüpft ist:

„simpleprog: ELF 64-Bit LSB ausführbar, x86-64, Version 1 (SYSV), dynamisch gelinkt (verwendet Shared Libs), für GNU/Linux 2.6.26, BuildID[sha1]=0xf715572611a8b04f686809d90d1c0d75c6028f0f, nicht abisoliert”

Lassen Sie uns stattdessen das Programm dieses Mal statisch verknüpfen:

gcc simpleprog.c -static -o simpleprog

Das Ausführen einer Datei auf dieser statisch verknüpften Binärdatei zeigt Folgendes:

file simpleprog 

“simpleprog: ELF 64-Bit LSB ausführbar, x86-64, Version 1 (GNU/Linux), statisch gelinkt, für GNU/Linux 2.6.26, BuildID[sha1]=0x8c0b12250801c5a7c7434647b7dc65a644d6132b, nicht gestrippt”

Und Sie können sehen, dass es glücklicherweise statisch verknüpft ist. Leider sind jedoch nicht alle Bibliotheken auf diese Weise einfach statisch zu verknüpfen, und die Verwendung kann einen längeren Aufwand erfordern libtool oder den Objektcode und die C-Bibliotheken von Hand verknüpfen.

Glücklicherweise mögen viele eingebettete C-Bibliotheken musl bieten statische Verlinkungsmöglichkeiten für fast alle wenn nicht alle ihrer Bibliotheken.

Jetzt strace die Binärdatei, die Sie erstellt haben, und Sie können sehen, dass auf keine Bibliotheken zugegriffen wird, bevor das Programm beginnt:

strace ./simpleprog

Vergleichen Sie nun mit der Ausgabe von strace auf dem dynamisch gelinkten Programm und Sie werden sehen, dass die Strace der statisch gelinkten Version viel kürzer ist!

(Ich kenne C# nicht, aber es ist interessant, ein statisches Verknüpfungskonzept für eine VM-Sprache zu haben.)

Beim dynamischen Linken müssen Sie wissen, wie Sie eine erforderliche Funktionalität finden, auf die Sie nur eine Referenz aus Ihrem Programm haben. Ihre Sprachlaufzeit oder Ihr Betriebssystem sucht im Dateisystem, im Netzwerk oder im Cache für kompilierten Code nach einem Codestück, das mit der Referenz übereinstimmt, und ergreift dann mehrere Maßnahmen, um es in Ihr Programmabbild im Speicher zu integrieren, z. B. eine Verschiebung. Sie werden alle zur Laufzeit ausgeführt. Dies kann entweder manuell oder durch den Compiler erfolgen. Es besteht die Möglichkeit, mit dem Risiko eines Durcheinanders zu aktualisieren (nämlich DLL-Hölle).

Das statische Linken erfolgt zur Kompilierzeit, dh Sie teilen dem Compiler mit, wo sich alle funktionalen Teile befinden, und weisen ihn an, sie zu integrieren. Es gibt kein Suchen, keine Mehrdeutigkeit, keine Möglichkeit zum Aktualisieren ohne Neukompilierung. Alle Ihre Abhängigkeiten sind physisch eins mit Ihrem Programm-Image.

1013490cookie-checkWas bedeuten „statisch verknüpft“ und „dynamisch verknüpft“?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy