Wann/wie lädt Linux gemeinsam genutzte Bibliotheken in den Adressraum?
Lesezeit: 5 Minuten
Ryan
Meine Frage ist folgende:
Wann wird die Adresse von Shared Objects in Programmen angegeben? Beim Verlinken? Wird geladen? Wenn ich die Speicheradresse der finden wollte system Befehl innerhalb von libc In meinem Programm konnte ich es leicht finden gdbaber was ist, wenn ich das Programm nicht in einen Debugger bringen möchte?
Könnte sich diese Adresse von Lauf zu Lauf ändern? Gibt es ein anderes statisches Analysetool, mit dem angezeigt werden kann, wo Bibliotheken oder Funktionen beim Ausführen in den Speicherbereich dieses Programms geladen werden?
BEARBEITEN: Ich möchte diese Informationen außerhalb des Programms (dh mit Dienstprogrammen wie objdump Informationen einholen)
und dann gibt es prelinkwodurch sich die Reihenfolge erheblich ändert.
– Ben Voigt
27. Februar 2011 um 1:16 Uhr
osgx
Bibliotheken werden geladen von ld.so (dynamischer Linker oder Laufzeitlinker, auch bekannt als rtld, ld-linux.so.2 oder ld-linux.so.* im Fall von Linux; Teil von glibc). Es wird als “Interpreter” (INTERP; .interp Abschnitt) aller dynamisch verknüpften ELF-Binärdateien. Wenn Sie also das Programm starten, startet Linux eine ld.so (in den Speicher laden und zu seinem Einstiegspunkt springen), dann ld.so lädt Ihr Programm in den Speicher, bereitet es vor und führt es dann aus. Sie können das dynamische Programm auch mit starten
ld.so macht eine tatsächliche open und mmap aller benötigten ELF-Dateien, sowohl die ELF-Datei Ihres Programms als auch die ELF-Dateien aller benötigten Bibliotheken. Außerdem füllt es GOT- und PLT-Tabellen und löst Verschiebungen auf (es schreibt Adressen von Funktionen aus Bibliotheken, um Sites aufzurufen, in vielen Fällen mit indirekten Aufrufen).
Die typische Ladeadresse einiger Bibliotheken, die Sie erhalten können ldd Dienstprogramm. Es ist eigentlich ein Bash-Skript, das eine Debug-Umgebungsvariable von ld.so (eigentlich LD_TRACE_LOADED_OBJECTS=1 im Falle von rtld von glibc) und startet ein Programm. Sie können es sogar auch ohne die Notwendigkeit des Skripts selbst tun, z. B. mit der Verwendung von Bash zum einfachen Ändern von Umgebungsvariablen für einen einzelnen Lauf:
LD_TRACE_LOADED_OBJECTS=1 /bin/echo
Das ld.so sieht diese Variable und löst alle benötigten Bibliotheken auf und gibt die Ladeadressen von ihnen aus. Aber mit diesem Variablensatz ld.so wird ein Programm nicht wirklich starten (nicht sicher über statische Konstruktoren von Programmen oder Bibliotheken). Wenn die ASLR-Funktion deaktiviert ist, ist die Ladeadresse meistens dieselbe. Moderne Linuxe haben oft ASLR aktiviert, um es also zu deaktivieren, verwenden Sie echo 0 | sudo tee /proc/sys/kernel/randomize_va_space.
Sie finden Offset von system Funktion innerhalb der libc.so mit nm Dienstprogramm von binutils. Ich denke, Sie sollten verwenden nm -D /lib/libc.so oder objdump -T /lib/libc.so und grep-Ausgabe.
wunderbare Informationen, danke. Kennen Sie gute Artikel, die erklären, wie dieser Prozess funktioniert (Generieren von GOT / PLT-Tabellen), oder würde Googeln zu ausreichenden Ergebnissen führen?
– Ryan
27. Februar 2011 um 1:07 Uhr
Wenn Sie anrufen möchten system mit absoluter Adresse können Sie dies tun, ohne GOT- und PLT-Tabellen zu verwenden. In meinem Punkt, das beste googeln für ld.so ist Codesuche: google.com/…
– osgx
27. Februar 2011 um 1:14 Uhr
Ja, ich weiß, dass Sie es tun können, ohne GOT und PLT zu verwenden, es war reine Neugier meinerseits! 🙂
– Ryan
27. Februar 2011 um 1:17 Uhr
Das war sehr informativ! Ich wusste nicht viel über ld.so und ldd!
– Matt Tischler
28. Februar 2011 um 2:20 Uhr
Diese Antwort ist darin falsch ld.so tut nicht Laden Sie das Hauptprogramm, der Kernel tut es. Der Kernel sieht sich auch keine an Abschnitte (die vollständig entfernt werden könnte), findet es den Interpreter in PT_INTERPSegment.
Unverzichtbare Dokumentation für Autoren von Linux-Bibliotheken. Erklärt die Mechanik des Ladens im Detail.
Wenn Sie nur die Adresse einer Funktion möchten, ohne den Namen fest zu codieren, können Sie dies tun dlopen() Das Hauptprogramm:
void *self = dlopen(NULL, RTLD_NOW);
dlsym(self, "system"); // returns the pointer to the system() function
Wenn Sie nur die Adresse einer Funktion benötigen, deren Namen Sie zur Kompilierzeit kennen, verwenden Sie einfach void *addr = &system;
siehe Bearbeiten in OP, aber belassen Sie diese Antwort auf jeden Fall, da sie für eine andere Variante des möglicherweise vagen Titels hilfreich ist. (wie du darauf geantwortet hast)
– Ryan
27. Februar 2011 um 0:54 Uhr
Es ist möglich, dass keiner von beiden das tut, was OP will, da system wird wahrscheinlich zu einem PLT-Eintrag im Hauptprogrammbild aufgelöst, das den eigentlichen Sprung in die gemeinsam genutzte Bibliothek durchführt.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
27. Februar 2011 um 0:54 Uhr
Das nm Befehl, verwendet auf libc.sozeigt Ihnen den Standort der system Symbol ein libc.so. Wenn jedoch ASLR aktiviert ist, wird die Adresse libc.so geladen wird, und damit die endgültige Adresse von system ändert sich zufällig jedes Mal, wenn Ihr Programm ausgeführt wird. Auch ohne ASLR müssen Sie die Adresse ermitteln libc.so wird bei geladen und versetzt die Adresse von system um diesen Betrag.
und dann gibt es
prelink
wodurch sich die Reihenfolge erheblich ändert.– Ben Voigt
27. Februar 2011 um 1:16 Uhr