2012-04-03 5 views
0

Freunde, ich habe zwei Dateien, a.c und b.c. Ich habe eine Funktion foo in a.c definiert, die von b.c.Auflösen von Referenzen zu Verbindungszeit oder Laufzeit?

Von dem, was ich verstehe, wenn der Compiler versucht, bc zu kompilieren, wird es sehen, dass die Implementierung von foo nicht in b ist, so wird es einen Eintrag für foo in der Symboltabelle hinzufügen, die bei der Verknüpfung aufgelöst werden soll Zeit. Ich habe dieses Konzept richtig verstanden.

Jetzt habe ich eine andere Funktion printf in b.c, die in glibc implemented ist. Soweit ich weiß, kann printf zur Ladezeit oder zur Laufzeit verknüpft werden. Wenn printf zur Laufzeit verknüpft wird, muss für jeden Aufruf von printf ein Stub vorhanden sein, der zur Laufzeit mit einem Systemaufruf aufgelöst wird.

meine Frage ist "Ist mein Verständnis richtig ??? + wie bestimmt der Compiler, dass eine Funktion foo würde durch Linker und nicht zur Laufzeit aufgelöst werden?"

Ich bemerkte einige ähnliche Fragen, konnte aber ihre Bedeutung hier nicht verstehen ???

Antwort

3

Ich finde deine Frage etwas schwer zu lesen, also bin ich mir nicht ganz sicher, wie du das verstehst, also beschreibe ich einfach, wie es funktioniert.

  1. Wenn das Symbol in der gleichen Datei (B.c) ist, bezieht sich der Compiler direkt darauf. Der Linker wird nicht verwendet, um irgendetwas zu lösen.

  2. Wenn das Symbol nicht in der gleichen Datei ist, und -fPICnicht ist angegeben, dann gibt der Compiler einfach einen Anruf auf ein nicht definiertes Symbol. In diesem Fall sucht der Linker nach dem Symbol in anderen .o-Dateien oder in Bibliotheken und fügt die direkte Referenz zur Verbindungszeit ein, indem er sie im Grunde in das leere Feld einfügt.

    Genau so würden Sie normalerweise ein Programm erstellen (im Gegensatz zu einer Bibliothek). Wenn das Programm dynamische Bibliotheken verwendet, können einige Symbole vorhanden sein, die nicht zur Verbindungszeit repariert werden können. Wenn dies der Fall ist, überprüft der Linker, ob die Bibliothek diese enthält, und es wird dem dynamischen Linker überlassen, den Job zur Laufzeit zu beenden.

    Es wäre möglich, dies genau in Shared Libraries auch, nur mit dem dynamischen Linker immer die Adressen in das Programm zur Laufzeit einfügen, aber dazu würde bedeuten, dass die gemeinsame Bibliothek konnte nicht freigegeben werden : Jedes Programm müsste eine eigene Kopie mit eigenen Korrekturen haben. Deshalb passiert das nicht.

  3. Wenn das Symbol nicht in der gleichen Datei ist, und -fPICist angegeben, dann wird die Compiler Namen nicht mit dem Symbol direkt nicht verwendet. Stattdessen ruft es Funktionen über eine PLT (Procedure Linkage Table) auf und erhält über eine GOT (Global Offset Table) die Adresse anderer Symbole.

    Die GOT ist eine spezielle Tabelle, die vom Linker erstellt wurde. Sie ist im Grunde nur eine Liste von undefinierten Symbolreferenzen, die denen in einem normalen Nicht-PIC-Programm ähneln (mit Ausnahme von Offsets) die Basis des GOT). Der dynamische Linker füllt die Leerzeichen zur Laufzeit aus. Der Compiler sorgt dafür, dass sich die Adresse des GOT immer in einem bestimmten CPU-Register befindet, so dass die Tabelle immer gefunden werden kann.

    Der PLT ist ein Satz von Trampolinen, die vom Linker erzeugt werden. Der Compiler erzeugt Sprünge in den PLT, und der dynamische Linker richtet den PLT so ein, dass er auf den tatsächlichen Ort der Funktion springt.Tatsächlich wird der PLT in vielen Fällen nicht vom dynamischen Linker beim Laden der Bibliothek ausgefüllt: Der PLT füllt sich selbst beim ersten Aufruf mit dem GOT (es ist selbst modifizierender Code).

    Aus diesem Grund werden dynamische Bibliotheken normalerweise mit -fPIC erstellt: Die GOTs und PLTs können für jedes Programm geändert werden, während der Text der Bibliotheken unverändert bleibt und sie somit freigegeben bleiben können.

So, jetzt die Antworten auf Ihre Fragen:

Ich denke, die ‚Stummel‘, die Sie darüber gesprochen, könnte die PLT sein?

Der Compiler tut nicht wissen, wenn eine Funktion gelöst wird. Es weiß nur, dass es es selbst nicht lösen kann. In der Tat, wenn Sie dynamische Bibliotheken verwenden, versucht der Linker nicht einmal, Symbole vollständig aufzulösen (obwohl ich denke, dass es überprüft, ob sie in der Bibliothek definiert sind); Dies bedeutet, dass eine bestimmte Funktion in einer Bibliothek überschrieben werden kann, indem eine andere Funktion mit demselben Namen bereitgestellt wird. Werkzeuge wie tsocks verwenden dies mit LD_PRELOAD, um Bibliotheksaufrufe abzufangen.

Verwandte Themen