Von der Frage her sieht es so aus, als ob Sie eine Bibliotheksfunktion profilieren.
Um zu wissen, welche Funktionen gemessen werden, haben Sie 2 Optionen:
1 Führen Sie das Programm aus, das die Bibliothek unter gdb
verwendet und stoppen Sie bei main
. Zu diesem Zeitpunkt erhalten Sie die PID
des Programms PID=...
und führen Sie `cat /proc/$PID/maps' aus. Dort sollten Sie etwas Ähnliches wie dies sehen:
~ ps
PID TTY TIME CMD
18533 pts/4 00:00:00 zsh
18664 pts/4 00:00:00 ps
~ PID=18533
~ cat /proc/$PID/maps
00400000-004a2000 r-xp 00000000 08:01 3670052 /bin/zsh5
006a1000-006a2000 r--p 000a1000 08:01 3670052 /bin/zsh5
006a2000-006a8000 rw-p 000a2000 08:01 3670052 /bin/zsh5
006a8000-006bc000 rw-p 00000000 00:00 0
...
7fa174cc9000-7fa174ccd000 r-xp 00000000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ccd000-7fa174ecc000 ---p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecc000-7fa174ecd000 r--p 00003000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecd000-7fa174ece000 rw-p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
...
Hier ist 7fa174cc9000
die Basisadresse der Bibliothek /lib/x86_64-linux-gnu/libcap.so.2.22
. Alle Adressen, die Sie durch readelf -s
erhalten, werden um diesen Wert verschoben sein. Wenn Sie die Basisadresse kennen, können Sie zurückrechnen, was ursprünglich die Verschiebung in der Datei war.
Zum Beispiel, wenn Sie den Wert 7fa174206370
erhalten haben und die Basisadresse der Bibliothek 7fa1741cf000
ist, dann beträgt die Verschiebung 7fa174206370 - 7fa1741cf000 = 37370
. In meinem Beispiel handelt es sich um sigsuspend
aus GLIBC:
94: 0000000000037370 132 FUNC WEAK DEFAULT 12 sigsuspend@@GLIBC_2.2.5
2 Führen Sie gdb
auf dem Programm aus, das diese Bibliotheken verwendet. Es wird entweder sofort die geladene Bibliothek im Speicher finden oder auf den .text
-Abschnitt der Bibliothek hingewiesen werden müssen.
> gdb
(gdb) attach IHRE_PID
(viele Ausgaben zu Symbolen)
(gdb) x/i 0x00007fa174206386
=> 0x7fa174206386 : cmp $0xfffffffffffff000,%rax
Auf diese Weise wissen Sie, dass 0x7fa174206386
sich innerhalb von sigsuspend
befindet.
Falls gdb
keine Symbole von selbst lädt (keine Ausgabe wie Reading symbols from ... Loading symbols for ...
nach dem Anhängen), können Sie die Basisadresse der Bibliothek wie in Option 1 suchen und dann die Verschiebung des .text
-Abschnitts hinzufügen
~ readelf -S /lib/x86_64-linux-gnu/libcap.so.2.22 | grep '.text.'
[11] .text PROGBITS 0000000000001620 00001620
7fa174cc9000 + 0000000000001620
in hexadezimal ergibt 7FA174CCA620
, und dann fügen Sie diese wie oben mit gdb
hinzu und führen aus
(gdb) add-symbol-file /lib/x86_64-linux-gnu/libcap.so.2.22 7FA174CCA620
Dann sollten Sie Symbole finden können (über x/i ADRESSE
wie in Option 1), selbst wenn gdb
diese nicht von selbst lädt.
Fragen Sie bitte, wenn etwas unklar ist, ich werde versuchen zu erklären.
Klärung, warum das so ist:
Das beobachtete Verhalten ist auf die Kompilierung der Bibliotheken als Position-Independent Code zurückzuführen. Dies ermöglicht eine einfache Unterstützung von dynamischen Bibliotheken. PIC bedeutet im Wesentlichen, dass die ELF der Bibliothek .plt
und .got
Abschnitte enthält und an jeder Basisadresse geladen werden kann. PLT ist die Prozedur-Verknüpfungstabelle und sie enthält Fallen für Funktionsaufrufe, die sich in anderen Modulen befinden, die zunächst zum Programm-Interpreter gehen, um ihm zu ermöglichen, die aufgerufene Funktion neu zu lokalisieren und dann einfach zur Funktion nach dem ersten Aufruf zu springen. Es funktioniert, weil der Programm-Interpreter das GOT (Global Offset Table) aktualisiert, das Adressen von Funktionen zum Aufruf enthält. Anfangs wird das GOT so initialisiert, dass bei einem ersten Funktionsaufruf der Sprung zur Funktion des Programminterpreters erfolgt, der die Auflösung der aktuell aufgerufenen Funktion durchführt.
Auf x86-64 sehen PLT-Einträge typischerweise so aus:
0000000000001430 :
1430: ff 25 e2 2b 20 00 jmpq *0x202be2(%rip) # 204018 <_fini+0x201264>
1436: 68 00 00 00 00 pushq $0x0
143b: e9 e0 ff ff ff jmpq 1420 <_init+0x28>
Der erste jmpq
ist ein Sprung zu der Adresse, die im GOT an der Position %rip + 0x202be2
gespeichert ist:
[20] .got PROGBITS 0000000000203fd0 00003fd0
0000000000000030 0000000000000008 WA 0 0 8
%rip + 0x202be2
wird 0x204012
sein, und das wird zur Basisadresse der Bibliothek hinzugefügt, um die absolute Adresse zu erzeugen, die relevant für den Ort ist, an dem die Bibliothek tatsächlich geladen ist. Wenn sie also bei 0x7f66dfc03000
geladen ist, dann wird die resultierende Adresse des entsprechenden GOT-Eintrags 0x7F66DFE07012
sein. Die Adresse, die an dieser Stelle gespeichert ist, ist die Adresse der (in diesem Beispiel) free
-Funktion. Sie wird vom Programm-Interpreter verwaltet, um auf das eigentliche free
in libc
zu verweisen.
Weitere Informationen dazu finden Sie hier.