Warum benötigt ld -rpath-link, wenn es eine ausführbare Datei mit einer verknüpft, die eine andere benötigt?

Lesezeit: 12 Minuten

Benutzeravatar von Troels Folke
Troels Folke

Ich bin hier einfach neugierig. Ich habe ein gemeinsames Objekt erstellt:

gcc -o liba.so -fPIC -shared liba.c

Und noch ein gemeinsames Objekt, das mit dem vorherigen verknüpft ist:

gcc -o libb.so -fPIC -shared libb.c liba.so

Wenn Sie nun eine ausführbare Datei erstellen, mit der verknüpft wird libb.somuss ich -rpath-link zu ld angeben, damit es finden kann liba.so wenn man das entdeckt libb.so hängt davon ab:

gcc -o test -Wl,-rpath-link,./ test.c libb.so

andernfalls wird ld sich beschweren.

Warum MUSS ld lokalisieren können? liba.so beim Verlinken test? Denn für mich scheint es nicht so, als würde ld viel anderes tun, als zu bestätigen liba.soExistenz. Laufen zum Beispiel readelf --dynamic ./test nur Listen libb.so nach Bedarf, also denke ich, dass der dynamische Linker das entdecken muss libb.so -> liba.so Abhängigkeit auf seine eigene, und machen Sie seine eigene Suche nach liba.so.

Ich bin auf einer x86-64 GNU/Linux-Plattform und die main()-Routine ist drin test ruft eine Funktion auf libb.so die wiederum eine Funktion aufruft liba.so.

Benutzeravatar von anton_rh
anton_rh

Warum MUSS ld lokalisieren können? liba.so beim Verlinken test? Denn für mich scheint es nicht so, als würde ld viel anderes tun, als zu bestätigen liba.soExistenz. Laufen zum Beispiel readelf --dynamic ./test nur Listen libb.so nach Bedarf, also denke ich, dass der dynamische Linker das entdecken muss libb.so -> liba.so Abhängigkeit auf seine eigene, und machen Sie seine eigene Suche nach liba.so.

Nun, wenn ich den Verknüpfungsprozess richtig verstehe, ld eigentlich muss nicht einmal lokalisieren libb.so. Es könnte einfach alle nicht aufgelösten Referenzen in ignorieren test in der Hoffnung, dass der dynamische Linker sie beim Laden auflöst libb.so zur Laufzeit. Doch wenn ld Auf diese Weise würden viele “undefinierte Referenz”-Fehler nicht zur Verbindungszeit erkannt, sondern beim Ladeversuch gefunden test zur Laufzeit. So ld führt nur eine zusätzliche Überprüfung durch, ob alle Symbole nicht in gefunden werden test selbst kann wirklich in gemeinsam genutzten Bibliotheken gefunden werden test darauf ankommen. Also wenn test Das Programm hat einen “undefinierten Verweis”-Fehler (eine Variable oder Funktion wurde nicht gefunden in test selbst und weder in libb.so), wird dies zur Verbindungszeit deutlich, nicht nur zur Laufzeit. Daher ist ein solches Verhalten nur eine zusätzliche Plausibilitätsprüfung.

Aber ld geht noch weiter. Wenn Sie verlinken test, ld prüft auch, ob alle nicht aufgelösten Referenzen vorhanden sind libb.so finden sich in den gemeinsam genutzten Bibliotheken, die libb.so hängt ab (in unserem Fall libb.so kommt drauf an liba.soalso erfordert es liba.so zur Verbindungszeit zu finden). Naja eigentlich ld hat diese Prüfung bereits beim Verlinken durchgeführt libb.so. Warum überprüft es das zweite Mal … Vielleicht Entwickler von ld fand diese doppelte Überprüfung nützlich, um defekte Abhängigkeiten zu erkennen, wenn Sie versuchen, Ihr Programm mit einer veralteten Bibliothek zu verknüpfen, die zu der Zeit geladen werden konnte, als sie verknüpft wurde, aber jetzt nicht geladen werden kann, weil die Bibliotheken, von denen es abhängt, aktualisiert werden (z , liba.so wurde später überarbeitet und ein Teil der Funktion wurde daraus entfernt).

UPD

Habe gerade ein paar Experimente gemacht. Es scheint meine Vermutung “eigentlich hat ld diese Prüfung bereits beim Verlinken durchgeführt libb.so ist falsch.

Nehmen wir an, die liba.c hat folgenden Inhalt:

int liba_func(int i)
{
    return i + 1;
}

und libb.c hat das nächste:

int liba_func(int i);
int liba_nonexistent_func(int i);

int libb_func(int i)
{
    return liba_func(i + 1) + liba_nonexistent_func(i + 2);
}

und test.c

#include <stdio.h>

int libb_func(int i);

int main(int argc, char *argv[])
{
    fprintf(stdout, "%d\n", libb_func(argc));
    return 0;
}

Beim Verlinken libb.so:

gcc -o libb.so -fPIC -shared libb.c liba.so

Linker generiert keine Fehlermeldungen, die liba_nonexistent_func kann nicht aufgelöst werden, stattdessen wird nur stillschweigend eine defekte gemeinsam genutzte Bibliothek generiert libb.so. Das Verhalten ist dasselbe, als würden Sie eine statische Bibliothek erstellen (libb.a) mit ar was auch keine Symbole der generierten Bibliothek auflöst.

Aber wenn Sie versuchen, zu verlinken test:

gcc -o test -Wl,-rpath-link=./ test.c libb.so

Sie erhalten den Fehler:

libb.so: undefined reference to `liba_nonexistent_func'
collect2: ld returned 1 exit status

Das Erkennen eines solchen Fehlers wäre nicht möglich, wenn ld nicht alle gemeinsam genutzten Bibliotheken rekursiv gescannt. Es scheint also, dass die Antwort auf die Frage die gleiche ist, wie ich sie oben gesagt habe: ld braucht -rpath-link um sicherzustellen, dass die verknüpfte ausführbare Datei später durch dynamisches Laden geladen werden kann. Nur eine Gesundheitsprüfung.

UPD2

Es wäre sinnvoll, so früh wie möglich nach ungelösten Verweisen zu suchen (beim Verlinken libb.so), aber ld tut dies aus irgendwelchen Gründen nicht. Es dient wahrscheinlich dazu, zyklische Abhängigkeiten für gemeinsam genutzte Bibliotheken zu erstellen.

liba.c kann folgende Implementierung haben:

int libb_func(int i);

int liba_func(int i)
{
    int (*func_ptr)(int) = libb_func;
    return i + (int)func_ptr;
}

So liba.so Verwendet libb.so und libb.so Verwendet liba.so (tun Sie so etwas besser nie). Dies wird erfolgreich kompiliert und funktioniert:

$ gcc -o liba.so -fPIC -shared liba.c
$ gcc -o libb.so -fPIC -shared libb.c liba.so
$ gcc -o test test.c -Wl,-rpath=./ libb.so
$ ./test
-1217026998

Obwohl gelesen sagt, dass liba.so braucht nicht libb.so:

$ readelf -d liba.so | grep NEEDED
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
$ readelf -d libb.so | grep NEEDED
 0x00000001 (NEEDED)                     Shared library: [liba.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

Wenn ld beim Linken einer gemeinsam genutzten Bibliothek auf nicht aufgelöste Symbole geprüft, das Linken von liba.so wäre nicht möglich.

Beachten Sie, dass ich verwendet habe -rPfad Schlüssel statt -rpath-link. Der Unterschied ist das -rpath-link wird beim Linken nur verwendet, um zu prüfen, ob alle Symbole in der endgültigen ausführbaren Datei aufgelöst werden können, wohingegen -rPfad bettet den Pfad, den Sie als Parameter angeben, tatsächlich in die ELF ein:

$ readelf -d test | grep RPATH
 0x0000000f (RPATH)                      Library rpath: [./]

Es ist also jetzt möglich zu laufen test wenn die gemeinsam genutzten Bibliotheken (liba.so und libb.so) befinden sich in Ihrem aktuellen Arbeitsverzeichnis (./). Wenn Sie gerade verwendet haben -rpath-link es würde keinen solchen Eintrag geben test ELF, und Sie müssten den Pfad zu den gemeinsam genutzten Bibliotheken zu der hinzufügen /etc/ld.so.conf Datei oder an die LD_LIBRARY_PATH Umgebungsvariable.

UPD3

Es ist tatsächlich möglich, beim Verknüpfen von gemeinsam genutzten Bibliotheken nach nicht aufgelösten Symbolen zu suchen. --no-undefined Option muss dazu verwendet werden:

$ gcc -Wl,--no-undefined -o libb.so -fPIC -shared libb.c liba.so
/tmp/cc1D6uiS.o: In function `libb_func':
libb.c:(.text+0x2d): undefined reference to `liba_nonexistent_func'
collect2: ld returned 1 exit status

Außerdem habe ich einen guten Artikel gefunden, der viele Aspekte der Verknüpfung von gemeinsam genutzten Bibliotheken verdeutlicht, die von anderen gemeinsam genutzten Bibliotheken abhängen:
Besseres Verständnis der sekundären Linux-Abhängigkeiten anhand von Beispielen lösen.

  • Viel gelernt. Vielen Dank. Der Link funktioniert allerdings nicht mehr.

    – Surajeet Bharati

    16. November 2016 um 7:27 Uhr


  • @SurajeetBharati Der Link sollte behoben werden, sobald meine Bearbeitung genehmigt wurde (ersetzen Sie im Grunde den letzten Schrägstrich durch .html)

    – Eduard

    24. November 2016 um 10:48 Uhr

  • Ich kann im Moment nicht auf den Link zugreifen, er ist jedoch auf archive.org verfügbar: web.archive.org/web/20161025105929/http://www.kaizou.org/2015/…

    – Horstinator

    22. April 2017 um 9:57 Uhr

Benutzeravatar von Han XIAO
Han XIAO

Ich denke, Sie müssen wissen, wann Sie es verwenden -rpath Möglichkeit und -rpath-link Möglichkeit. Zuerst zitiere ich was man ld spezifizierten :

  1. Der Unterschied zwischen -rpath und -rpath-link besteht darin, dass Verzeichnisse, die durch -rpath-Optionen angegeben werden, in die ausführbare Datei eingeschlossen und zur Laufzeit verwendet werden, während die Option -rpath-link nur zur Verbindungszeit wirksam ist. Das Durchsuchen von -rpath auf diese Weise wird nur von nativen Linkern und Crosslinkern unterstützt, die mit der Option –with-sysroot konfiguriert wurden.

Sie müssen zwischen Verbindungszeit und Laufzeit unterscheiden. Gemäß Ihrer akzeptierten Antwort von anton_rh ist die Überprüfung auf undefinierte Symbole beim Kompilieren und Verknüpfen von gemeinsam genutzten Bibliotheken oder statischen Bibliotheken nicht aktiviert, sondern beim Kompilieren und Verknüpfen von ausführbaren Dateien aktiviert. (Bitte beachten Sie jedoch, dass es einige Dateien gibt, die gemeinsam genutzte Bibliotheken sowie ausführbare Dateien sind, z. ld.so. Typ man ld.so um dies zu untersuchen, und ich weiß nicht, ob die Überprüfung auf undefinierte Symbole aktiviert ist oder nicht, wenn diese Dateien “dualer” Arten kompiliert werden).

So -rpath-link wird bei der Überprüfung der Verbindungszeit verwendet, und -rpath wird für Link-Zeit und Laufzeit verwendet, weil rpath ist in ELF-Header eingebettet. Aber darauf sollte man achten -rpath-link Option wird überschrieben -rpath Option während der Verbindungszeit, wenn beide angegeben sind.

Aber trotzdem, warum -rpath-option und -rpath Möglichkeit? Ich denke, sie werden verwendet, um “Überverknüpfungen” zu beseitigen. Sieh dir das an Besseres Verständnis der sekundären Linux-Abhängigkeiten anhand von Beispielen lösen.einfach verwenden ctrl + F um zu Inhalten zu navigieren, die sich auf “Überverlinkung” beziehen. Sie sollten sich darauf konzentrieren, warum “overlinking” schlecht ist und aufgrund der Methode, die wir anwenden, um “overlinking” zu vermeiden, die Existenz von ld Optionen -rpath-link und -rpath ist sinnvoll: Wir lassen bewusst einige Bibliotheken in den Befehlen zum Kompilieren und Linken weg, um ein “Überlinken” zu vermeiden, und wegen des Weglassens von ld brauchen -rpath-link oder -rpath um diese ausgelassenen Bibliotheken zu lokalisieren.

Benutzeravatar von David C. Rankin
David C. Rankin

Sie System, durch ld.so.conf, ld.so.conf.dund die Systemumgebung, LD_LIBRARY_PATHusw., bietet die systemweit Bibliothekssuchpfade, die durch installierte Bibliotheken ergänzt werden pkg-config Informationen und dergleichen, wenn Sie mit Standardbibliotheken bauen. Wenn sich eine Bibliothek in einem definierten Suchpfad befindet, werden die standardmäßigen Bibliothekssuchpfade automatisch befolgt, sodass alle erforderlichen Bibliotheken gefunden werden können.

Es gibt keine Norm Suchpfad der Laufzeitbibliothek für benutzerdefinierte gemeinsam genutzte Bibliotheken, die Sie selbst erstellen. Den Suchpfad zu Ihren Bibliotheken legen Sie über fest -L/path/to/lib Bezeichnung beim Kompilieren und Linken. Für Bibliotheken an nicht standardmäßigen Speicherorten kann der Bibliothekssuchpfad optional zur Kompilierzeit in den Header Ihrer ausführbaren Datei (ELF-Header) eingefügt werden, damit Ihre ausführbare Datei die benötigten Bibliotheken finden kann.

rpath bietet eine Möglichkeit, den Suchpfad Ihrer benutzerdefinierten Laufzeitbibliothek in den ELF-Header einzubetten, sodass Ihre benutzerdefinierten Bibliotheken ebenfalls gefunden werden können, ohne den Suchpfad bei jeder Verwendung angeben zu müssen. Dies gilt auch für Bibliotheken, die von Bibliotheken abhängen. Wie Sie festgestellt haben, ist nicht nur die Reihenfolge wichtig, in der Sie die Bibliotheken in der Befehlszeile angeben, sondern Sie müssen auch den Suchpfad der Laufzeitbibliothek oder rpath für jede abhängige Bibliothek angeben, mit der Sie verknüpfen, damit der Header enthält den Standort von alle Bibliotheken zum Ausführen benötigt.

Nachtrag aus den Kommentaren

Meine Frage ist hauptsächlich, warum ld “automatisch versuchen muss, die gemeinsam genutzte Bibliothek zu finden” (liba.so) und “sie in den Link aufnehmen” muss.

Das ist einfach der Weg ld funktioniert. Aus man ld “Die Option -rpath wird auch beim Suchen verwendet gemeinsam genutzte Objekte, die von gemeinsam genutzten Objekten benötigt werden explizit in den Link aufgenommen … Wenn -rpath beim Linken einer ausführbaren ELF-Datei nicht verwendet wird, wird der Inhalt der Umgebungsvariable “LD_RUN_PATH” verwendet, wenn er definiert ist.” In Ihrem Fall liba befindet sich nicht in der LD_RUN_PATH Also ld brauchen einen Weg, um zu finden liba während der Kompilierung Ihrer ausführbaren Datei, entweder mit rpath (oben beschrieben) oder durch Angabe eines expliziten Suchpfads dorthin.

Zweitens, was “in den Link aufnehmen” wirklich bedeutet. Für mich scheint es nur zu bedeuten: “Bestätige seine Existenz” (liba.so’s), da die ELF-Header von libb.so nicht geändert werden (sie hatten bereits ein NEEDED-Tag gegen liba.so) und die Header der Exec nur libb deklarieren. also wie NÖTIG. Warum kümmert sich ld darum, liba.so zu finden, kann es die Aufgabe nicht einfach dem Laufzeitlinker überlassen?

Nein, zurück zur Semantik von ld. Zur Herstellung eines “gute Verbindung”, ld muss man lokalisieren können alle abhängige Bibliotheken. ld kann sonst keine gute Verbindung garantieren. Der Laufzeitlinker muss finden und ladennicht nur zu finden die gemeinsam genutzten Bibliotheken von einem Programm benötigt. ld kann nicht garantieren, dass dies geschieht, es sei denn ld selbst kann Suchen Sie alle benötigten gemeinsam genutzten Bibliotheken zum Zeitpunkt der Verlinkung des Programms.

  • Ja, aber die Option -rpath-link fügt keine RPATH-Tags in eine der Objektdateien ein. In der Dokumentation heißt es: Bei Verwendung von ELF oder SunOS kann eine gemeinsam genutzte Bibliothek eine andere erfordern. Dies geschieht, wenn ein ld -shared-Link eine gemeinsam genutzte Bibliothek als eine der Eingabedateien enthält. Wenn der Linker bei einem nicht gemeinsam genutzten, nicht verschiebbaren Link auf eine solche Abhängigkeit stößt, versucht er automatisch, die erforderliche gemeinsam genutzte Bibliothek zu finden und sie in den Link aufzunehmen, wenn sie nicht explizit enthalten ist. In einem solchen Fall gibt die Option -rpath-link den ersten zu durchsuchenden Satz von Verzeichnissen an

    – Troels Folke

    7. Juli 2014 um 9:26 Uhr


  • Und ich denke, das Verknüpfen einer ausführbaren Datei ist ein “nicht freigegebener, nicht verschiebbarer Link”. Meine Frage ist hauptsächlich, warum ld “automatisch versuchen muss, die gemeinsam genutzte Bibliothek zu finden” (liba.so) und “sie in den Link aufnehmen” muss. Zweitens, was “in den Link aufnehmen” wirklich bedeutet. Für mich scheint es nur zu bedeuten: “Bestätige seine Existenz” (liba.so’s), da die ELF-Header von libb.so nicht geändert werden (sie hatten bereits ein NEEDED-Tag gegen liba.so) und die Header der Exec nur libb deklarieren. also wie NÖTIG. Warum kümmert sich ld darum, liba.so zu finden, kann es die Aufgabe nicht einfach dem Laufzeitlinker überlassen?

    – Troels Folke

    7. Juli 2014 um 9:38 Uhr


Sie sagen ld nicht wirklich (beim Verlinken libb gegen liba) wo liba ist – nur dass es eine Abhängigkeit ist. Eine schnelle ldd libb.so wird Ihnen zeigen, dass es nicht finden kann liba.

Da sich diese Bibliotheken vermutlich nicht in Ihrem Linker-Suchpfad befinden, erhalten Sie einen Linker-Fehler, wenn Sie die ausführbare Datei verknüpfen. Denken Sie daran, dass beim Linken von liba selbst die Funktion in libb lautet still ungelöst, aber ldDas Standardverhalten von ist, sich nicht um nicht aufgelöste Symbole in DSOs zu kümmern, bis Sie die endgültige ausführbare Datei verknüpft haben.

1406560cookie-checkWarum benötigt ld -rpath-link, wenn es eine ausführbare Datei mit einer verknüpft, die eine andere benötigt?

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

Privacy policy