Was genau macht `-rdynamic` und wann genau wird es benötigt?
Lesezeit: 8 Minuten
PSkocik
Was genau macht -rdynamic (oder --export-dynamic auf der Linker-Ebene) tun und in welcher Beziehung es zur Sichtbarkeit von Symbolen steht, wie sie von definiert werden -fvisibility* Flaggen oder Sichtbarkeit pragmas und __attribute__s?
… Wenn Sie “dlopen” verwenden, um ein dynamisches Objekt zu laden, das auf die vom Programm definierten Symbole zurückgreifen muss, und nicht auf ein anderes dynamisches Objekt, dann müssen Sie diese Option wahrscheinlich beim Linken des Programms selbst verwenden. …
Ich bin mir nicht sicher, ob ich das vollständig verstehe. Könnten Sie bitte ein Beispiel geben, das ohne nicht funktioniert? -rdynamic aber tut es damit?
BearbeitenHinweis: Ich habe tatsächlich versucht, ein paar Dummy-Bibliotheken zu kompilieren (einzelne Datei, mehrere Dateien, verschiedene -O-Ebenen, einige Interfunktionsaufrufe, einige versteckte Symbole, einige sichtbar), mit und ohne -rdynamicund bisher habe ich bekommen Byte-identisch Ausgänge (wenn alle anderen Flags natürlich konstant gehalten werden), was ziemlich verwirrend ist.
Mike Kinghan
Hier ist ein einfaches Beispielprojekt, um die Verwendung zu veranschaulichen -rdynamic.
Hier, bar.c wird eine gemeinsame Bibliothek libbar.so und main.c wird ein Programm, das dlopens libbar und ruft bar() aus dieser Bibliothek. bar() Anrufe foo()das ist extern in bar.c und definiert in main.c.
Ihr Beispiel macht deutlich, was die Manpage bedeutet. Danke vielmals!
– PSkočik
18. April 2016 um 18:42 Uhr
Ich habe mich gefragt, warum rdynamic auf der ausführbaren Datei und nicht auf dem gemeinsam genutzten Objekt ist. Gemäß dieser Antwort: stackoverflow.com/questions/50418941/… lautet eine kurze Zusammenfassung dieser Antwort: Symbole werden standardmäßig nur aus gemeinsam genutzten Bibliotheken exportiert. -rdynamic weist den Linker an, dasselbe für ausführbare Dateien zu tun.
– thejinx0r
12. November 2018 um 18:54 Uhr
Neben der Verwendung -rdynamicüberprüfen Sie auch, ob Ihr Build-System nicht hinzufügt -fvisibility=hidden Möglichkeit! (da es die Wirkung von vollständig verwirft -rdynamic)
– Dima Litwinow
13. Mai 2020 um 0:44 Uhr
Gutes Beispiel, aber die -L. -lbar ist während der Prog-Kompilierung nicht erforderlich, oder? Sie sind nur für das statische Linken von Bibliotheken erforderlich. Die dynamische Bibliothek wird von LD_LIBRARY_PATH gefunden.
– Chan-Kim
8. Juni 2021 um 8:28 Uhr
Ich stimme @ChanKim zu. -L. -lbar ist nicht notwendig, da wir die Lib von Hand löschen. Es sollte auch gut funktionieren, ohne Änderungen vornehmen zu müssen LD_LIBRARY_PATH da wir die Bibliothek mit einem Pfad öffnen ("./libbar.so" Anstatt von "libbar.so") also ist es in Ordnung zu gehen LD_LIBRARY_PATH allein oder so wie es ist.
– mchiasson
26. Juli 2021 um 22:33 Uhr
-rdynamic exportiert die Symbole einer ausführbaren Datei, dies adressiert hauptsächlich Szenarien, wie in Mike Kinghans Antwort beschrieben, aber es hilft auch zB Glibcs backtrace_symbols() symbolisiert die Rückverfolgung.
Hier ein kleines Experiment (Testprogramm kopiert von hier)
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
void *array[10];
size_t size;
char **strings;
size_t i;
size = backtrace (array, 10);
strings = backtrace_symbols (array, size);
printf ("Obtained %zd stack frames.\n", size);
for (i = 0; i < size; i++)
printf ("%s\n", strings[i]);
free (strings);
}
/* A dummy function to make the backtrace more interesting. */
void
dummy_function (void)
{
print_trace ();
}
int
main (void)
{
dummy_function ();
return 0;
}
Kompilieren Sie das Programm: gcc main.c und führe es aus, die Ausgabe:
Wie Sie sehen können, erhalten wir jetzt einen ordnungsgemäßen Stack-Trace!
Wenn wir nun den Symboltabelleneintrag von ELF untersuchen (readelf --dyn-syms a.out):
ohne -rdynamic
Symbol table '.dynsym' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (3)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
mit -rdynamichaben wir mehr Symbole, einschließlich der ausführbaren:
Symbol table '.dynsym' contains 25 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (3)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
11: 0000000000601060 0 NOTYPE GLOBAL DEFAULT 24 _edata
12: 0000000000601050 0 NOTYPE GLOBAL DEFAULT 24 __data_start
13: 0000000000601068 0 NOTYPE GLOBAL DEFAULT 25 _end
14: 00000000004009d8 12 FUNC GLOBAL DEFAULT 14 dummy_function
15: 0000000000601050 0 NOTYPE WEAK DEFAULT 24 data_start
16: 0000000000400a80 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
17: 0000000000400a00 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
18: 0000000000400850 42 FUNC GLOBAL DEFAULT 14 _start
19: 0000000000601060 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
20: 00000000004009e4 16 FUNC GLOBAL DEFAULT 14 main
21: 00000000004007a0 0 FUNC GLOBAL DEFAULT 11 _init
22: 0000000000400a70 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
23: 0000000000400a74 0 FUNC GLOBAL DEFAULT 15 _fini
24: 0000000000400922 182 FUNC GLOBAL DEFAULT 14 print_trace
Ich hoffe das hilft!
deep_rugs
Ich verwende rdynamic, um Backtraces mit dem auszudrucken backtrace()/backtrace_symbols() von Glibc.
Ohne -rdynamickönnen Sie keine Funktionsnamen erhalten.
Um mehr über die zu erfahren backtrace() überlesen hier.
Eine viel bessere Lösung ist die Verwendung eines normalen Unwinders, der auf Debuginfo zugreifen kann.
– jugr
18. Mai 2018 um 21:15 Uhr
@yugr können Sie einen Hinweis darauf geben, worauf Sie sich beziehen?
– f3xy
26. Juni 2019 um 21:47 Uhr
@f3xy Siehe zB Dies Flameeyes-Post über die Nachteile des Hinzufügens zusätzlicher Symbole zu dynamischen Symtabs. Dedizierte Unwinder wie libbacktrace oder libunwind können Stapel ohne Overhead symbolisieren, indem sie die Debug-Informationen des Programms verwenden.
– jugr
27. Juni 2019 um 1:41 Uhr
@yugr Debug-Info fügt der ausführbaren Datei viel mehr Volumen hinzu (denken Sie an eingebettete Systeme mit kleinen Flash-Partitionen) und ist möglicherweise nicht geeignet, wenn Sie proprietäre Software versenden. Schon -rdynamic Fügt eine Menge Informationen hinzu, die für jemanden hilfreich sind, der die Binärdatei zurückentwickelt. -rdynamic ist ein netter Trick: Die Binärdatei kann immer noch entfernt werden, aber sie respektiert diese Symbole, weil sie dynamisch sind.
– Kas
3. Juni 2020 um 17:44 Uhr
@Kaz “Debug-Informationen fügen der ausführbaren Datei viel mehr Masse hinzu” – Debuginfo-basierte Unwinder müssen nur -gline-tables-only das ist deutlich kleiner als voll -g Debug-Informationen. “eingebettete Systeme mit kleinen Flash-Partitionen” – solche Systeme drucken normalerweise sowieso nur Adressen (die dann auf dem Host symbolisiert werden). “Möglicherweise nicht angemessen, wenn Sie proprietäre Software versenden” – Ich würde keine proprietäre Software empfehlen, symbolisierte Backtraces in Release-Builds zu drucken, sei es mit Debuginfo oder -rdynamic.
– jugr
3. Juni 2020 um 19:44 Uhr
Aus Die Linux-Programmierschnittstelle:
42.1.6
Zugriff auf Symbole im Hauptprogramm
Angenommen, wir verwenden dlopen() zu dynamisch eine gemeinsam genutzte Bibliothek ladenverwenden dlsym() um die Adresse einer Funktion zu erhalten x() aus dieser Bibliothek und rufen Sie dann an x(). Wenn x() wiederum ruft eine Funktion auf y()dann y() normalerweise in einer der vom Programm geladenen gemeinsam genutzten Bibliotheken gesucht werden.
Manchmal ist es wünschenswert, stattdessen zu haben x() Rufen Sie eine Implementierung von auf y() im Hauptprogramm. (Dies ähnelt einem Rückrufmechanismus.) Um dies zu tun, müssen wir die (globalen) Symbole im Hauptprogramm dem dynamischen Linker zur Verfügung stellen, indem wir das Programm mit der verknüpfen --export-dynamic Linker-Option:
$ gcc -Wl,--export-dynamic main.c (plus weitere Optionen und Argumente)
Äquivalent können wir Folgendes schreiben:
$ gcc -export-dynamic main.c
Die Verwendung einer dieser Optionen ermöglicht es einer dynamisch geladenen Bibliothek, auf globale Symbole im Hauptprogramm zuzugreifen.
Das gcc -rdynamic Möglichkeit und die gcc -Wl,-E Option sind weiter
Synonyme für -Wl,--export-dynamic.
Ich denke, das funktioniert nur für dynamisch geladene gemeinsam genutzte Bibliotheken, die mit geöffnet wurden dlopen(). Korrigiere mich, wenn ich falsch liege.
14181400cookie-checkWas genau macht `-rdynamic` und wann genau wird es benötigt?yes