Dynamische Verknüpfung - Linux Vs. Windows

10

Wenn ich unter Windows C / C ++ - Code in einem DLL-Projekt in MSVC kompiliere, erhalte ich zwei Dateien:

  1. MyDll.dll
  2. MyDll.lib

Soweit ich weiß, MyDll.libenthält es eine Art Zeigertabelle, die die Positionen der Funktionen in der DLL angibt. Bei Verwendung dieser DLL, beispielsweise in einer Exe-Datei, MyDll.libwird sie während der Verknüpfung in die Exe-Datei eingebettet, sodass sie zur Laufzeit "weiß", wo sich die Funktionen befinden, MyDll.dllund sie verwenden kann.

Wenn ich jedoch denselben Code unter Linux kompiliere, erhalte ich nur eine Datei MySo.soohne MySo.a(das entspricht einer libDatei unter Linux). Woher weiß eine ausführbare Datei unter Linux, wo sich die Funktionen befinden, MySo.sowenn während der Verknüpfung nichts darin eingebettet ist?

Benny K.
quelle

Antworten:

1

Unter Linux durchsucht der Linker (nicht der dynamische Linker) die zur Linkzeit angegebenen gemeinsam genutzten Bibliotheken und erstellt in der ausführbaren Datei Verweise darauf. Wenn der dynamische Linker diese ausführbaren Dateien lädt, lädt er die benötigten gemeinsam genutzten Bibliotheken in den Speicher und löst die Symbole auf, wodurch die Binärdateien ausgeführt werden können.

MySo.aWenn erstellt, würden die Symbole, die direkt in die Binärdatei verknüpft werden sollen, anstelle der unter Windows verwendeten "Symbol-Nachschlagetabellen" enthalten sein.

Die Antwort von rustyx erklärt den Prozess unter Windows gründlicher als ich kann. Es ist lange her, dass ich Windows verwendet habe.

SS Anne
quelle
1
"Windows verfolgt einen anderen Ansatz ... geben Sie dem Betriebssystem genau an, wo sich die Symbole in der DLL befinden" - dies widerspricht dem Wiki , das besagt, dass Funktionsnamen auch beim Start oder beim ersten Aufruf der Bibliotheksfunktion noch aufgelöst werden Verwenden Sie Ordnungszahlen (es sei denn, es wird eine direkte Adressbindung verwendet, die niemand tun würde, da Bibliotheksbenutzer gezwungen sind, ihren Code bei jeder Bibliotheksänderung neu zu kompilieren und erneut bereitzustellen).
yugr
@yugr Entfernte diesen Teil, ich griff sowieso nach Strohhalmen.
SS Anne
4

Der MSVC-Linker kann Objektdateien (.obj) und Objektbibliotheken (.lib) miteinander verknüpfen, um eine .EXE- oder eine .DLL-Datei zu erstellen.

Für die Verknüpfung mit einer DLL wird in MSVC eine sogenannte Importbibliothek (.LIB) verwendet, die als Klebstoff zwischen den C-Funktionsnamen und der Exporttabelle der DLL fungiert (in einer DLL kann eine Funktion nach Namen oder exportiert werden per Ordnungszahl - letzteres wurde häufig für undokumentierte APIs verwendet).

In den meisten Fällen enthält die DLL-Exporttabelle jedoch alle Funktionsnamen, und daher enthält die Importbibliothek (.LIB) weitgehend redundante Informationen (" Importfunktion ABC -> exportierte Funktion ABC " usw.).
Es ist sogar möglich, eine .LIB aus einer vorhandenen .DLL zu generieren .

Linker auf anderen Plattformen verfügen nicht über diese "Funktion" und können direkt mit dynamischen Bibliotheken verknüpft werden.

Rustyx
quelle
"Linker auf anderen Plattformen haben diese Funktion nicht" - es ist jedoch einfach zu implementieren (z. B. impliziert Implib.so dies für Linux), um verzögertes Laden und andere Extras zu erzielen.
Yugr
@yugr: Deshalb steht "feature" in Anführungszeichen - es ist nichts, was Sie normalerweise tun möchten, und es ist zusätzliche Arbeit, die Sie unter Windows erledigen müssen.
Chris Dodd
1

Der Unterschied, den Sie sehen, ist eher ein Implementierungsdetail - unter der Haube funktionieren sowohl Linux als auch Windows ähnlich - Sie rufen eine Stub-Funktion auf, die statisch in Ihrer ausführbaren Datei verknüpft ist, und dieser Stub lädt dann bei Bedarf DLL / shlib (im Falle einer Verzögerung) Laden , andernfalls wird die Bibliothek beim Programmstart geladen) und (beim ersten Aufruf) wird das Symbol über GetProcAddress/ aufgelöst dlsym.

Der einzige Unterschied besteht darin, dass diese Stub-Funktionen (die als PLT-Stubs bezeichnet werden) unter Linux dynamisch generiert werden, wenn Sie Ihre App mit einer dynamischen Bibliothek verknüpfen (die Bibliothek enthält genügend Informationen, um sie zu generieren), während sie unter Linux stattdessen generiert werden, wenn die DLL selbst vorhanden ist erstellt, in einer separaten .libDatei.

Die beiden Ansätze sind so ähnlich, dass es tatsächlich möglich ist, Windows-Importbibliotheken unter Linux nachzuahmen (siehe Implib.so- Projekt).

yugr
quelle
0

Unter Linux übergeben Sie MySo.soden Linker und er kann nur das extrahieren, was für die Linkphase benötigt wird, und eine Referenz eingeben, MySo.sodie zur Laufzeit benötigt wird.

Ein Programmierer
quelle
-3

.dlloder .sosind gemeinsam genutzte Bibliotheken (zur Laufzeit verknüpft), während .aund .libeine statische Bibliothek ist (zur Kompilierungszeit verknüpft). Dies ist kein Unterschied zwischen Windows und Linux.

Der Unterschied ist, wie sie behandelt werden. Hinweis: Der Unterschied besteht nur im Zoll, wie werden sie verwendet. Es wäre nicht allzu schwer, Linux-Builds auf Windows-Art und umgekehrt zu erstellen, außer dass dies praktisch niemand tut.

Wenn wir eine DLL verwenden oder eine Funktion sogar aus unserer eigenen Binärdatei aufrufen, gibt es einen einfachen und klaren Weg. In C sehen wir zum Beispiel Folgendes:

int example(int x) {
  ...do_something...
}

int ret = example(42);

Auf asm-Ebene kann es jedoch viele Unterschiede geben. Auf x86 wird beispielsweise ein callOpcode ausgeführt und der 42auf dem Stapel angegeben. Oder in einigen Registern. Oder irgendwo. Niemand weiß, bevor er die DLL schreibt , wie sie verwendet wird. Oder wie die Projekte es verwenden wollen, möglicherweise mit einem Compiler (oder in einer Sprache!) Geschrieben, der noch nicht einmal existiert (oder für die Entwickler der DLL unbekannt ist).

Standardmäßig setzen sowohl C als auch Pascal die Argumente (und erhalten die Rückgabewerte) vom Stapel - aber sie tun dies in einer anderen Reihenfolge . Sie können auch Argumente zwischen Ihren Funktionen in den Registern durch eine vom Compiler abhängige Optimierung austauschen.

Wie Sie richtig sehen, ist der Windows-Brauch, dass beim Erstellen einer DLL auch ein Minimal .a/ .libdamit erstellt wird. Diese minimale statische Bibliothek ist nur ein Wrapper, über den die Symbole (Funktionen) dieser DLL erreicht werden. Dadurch werden die erforderlichen Aufrufkonvertierungen auf ASM-Ebene durchgeführt.

Ihr Vorteil ist die Kompatibilität. Der Nachteil ist, dass es schwierig sein kann, herauszufinden, wie die Funktionen aufgerufen werden sollen, wenn Sie nur eine DLL haben. Dies macht die Verwendung von DLLs zu einer Hacking-Aufgabe, wenn der Entwickler der DLL Ihnen die nicht gibt.a . So dient es hauptsächlich Schließungszwecken, zum Beispiel ist es einfacher, zusätzliches Geld für die SDKs zu erhalten.

Ein weiterer Nachteil ist, dass Sie diesen kleinen Wrapper statisch kompilieren müssen, selbst wenn Sie eine dynamische Bibliothek verwenden.

Unter Linux ist die binäre Schnittstelle der DLLs Standard und folgt der C-Konvention. Daher ist kein .aerforderlich und es besteht eine binäre Kompatibilität zwischen den gemeinsam genutzten Bibliotheken. Im Gegenzug haben wir nicht die Vorteile des Microsoft Custom.

Peter - Setzen Sie Monica wieder ein
quelle
1
Bitte geben Sie einen Prooflink an, damit Stub-Funktionen die Argumentreihenfolge ändern können. Ich habe noch nie davon gehört und es ist kaum zu glauben, wie hoch der Leistungsaufwand sein würde.
yugr
@yugr Eine einfache Neuordnung von Registern / Stapeln ist kein Leistungsaufwand. Wenn Sie msvc-kompilierte DLLs aus msvc-kompilierten Binärdateien verwenden, wird offensichtlich nicht zu viel passieren, aber es könnte sein.
Peterh
1
Wir könnten darüber streiten, aber falls Sie Recht haben, sollte es einfach sein, Prooflinks bereitzustellen, dass Stub-Funktionen eine nicht triviale Verarbeitung von Argumenten ermöglichen (und mehr als nur Dummy-Trampoline sind).
Yugr
@yugr Die Stubs haben Zugriff auf die Funktionssignaturen der DLL, wodurch die nicht triviale Verarbeitung trivial wird.
Peterh - Wiedereinsetzung Monica
1
Ich schlage nur vor, dass Sie Ihre Antwort mit wenigen Korrekturlinks bezüglich der Funktionsweise der Importbibliothek vervollständigen (da einige der Behauptungen fraglich sind).
Yugr