Das Thema dieses Artikels ist wie folgt.
Der Inhalt ist ein tiefer Einblick in diesen Artikel. Ich werde noch einmal zusammenfassen, wo es sich um eine Bibliothek und eine öffentliche API handelt
Das Programm beginnt mit der Hauptfunktion und realisiert die Funktion des Programms unter Verwendung der von main aufgerufenen Funktionen und der verwendeten Daten. Es funktioniert nicht ohne die Funktionen, die von der Hauptfunktion aufgerufen werden sollen, und die verwendeten Daten, sodass es immer irgendwo im Programm eine Entität gibt.
Wenn Sie ein Programm auf diese Weise erstellen, gibt es Fälle, in denen Sie plötzlich Ecken schneiden möchten. Sie müssen jedes Mal genau dieselbe Funktion verwenden. Die Bibliothek ** ist ein Mechanismus, um solche ** genau die gleichen Funktionen zusammenzustellen.
Die Bibliothek wird beim Kompilieren des Programms einer Bibliothek mit dem Namen ** Bibliothekslink ** oder ** Link ** zugeordnet.
Um die Bibliothek zu verknüpfen, muss die Bibliothek Folgendes tun.
Sie müssen Informationen über das in der Abbildung verwendete apllo ()
und die Tassen offenlegen. Dies ist das Hauptthema dieser Zeit, ** Informationen, die für die Öffentlichkeit zugänglich sind **.
Wenn die Funktionsinformationen durch diese Verknüpfung aufgelöst werden, kann das Programm die Bibliothek verwenden. Zu diesem Zeitpunkt unterscheidet sich die Verwendungsmethode je nach Art der Bibliothek.
Es ist eine Bibliothek in einem Format, das das Programm zum Zeitpunkt der Kompilierung importiert. Da es zur Erstellungszeit im Programm enthalten ist, ist die Funktion bereits vorhanden, wenn das Programm ausgeführt wird, sodass Sie das Programm ohne nachzudenken verwenden können **. Da die gesamte halbseitige Bibliothek importiert wird, ** wird die Größe erhöht **.
Das Programm speichert zur Kompilierungszeit nur die Bibliotheksinformationen und ordnet sie zur Laufzeit der Zieldatei zu. (Es heißt ** Verknüpfung von Bibliotheken **)
Im Fall einer gemeinsam genutzten Bibliothek verfügt das Programm nur über die Bibliotheksinformationen. Daher muss die Zielbibliothek bei der Ausführung des Programms verknüpft werden.
Dieser Mechanismus ist [wie folgt](https://qiita.com/developer-kikikaikai/items/f6f87b2d1d7c3e14fb52#%E5%9F%BA%E6%9C%AC%E7%9A%84%E3% 81% AAlinux% E3% 81% AE% E5% 8B% 95% E7% 9A% 84% E3% 83% A9% E3% 82% A4% E3% 83% 96% E3% 83% A9% E3% 83% AA% E3% 83% AA% E3% 83% B3% E3% 82% AF% E3% 81% AB% E9% 96% A2% E3% 81% 99% E3% 82% 8B% E4% BB% 95% E7% B5% 84% E3% 81% BF).
Einfach ausgedrückt ist es in Ordnung, wenn der Pfad der Zielbibliothek vom Befehl ldd ausgegeben wird. Wenn nicht, müssen Sie den Pfad in der Build- oder Umgebungsvariablen für die Bibliothek übergeben. Es ist in Ordnung, wenn die rechte Seite von => wie unten gezeigt irgendwo gebunden ist.
$ ldd /usr/bin/curl
linux-vdso.so.1 (0x00007ffe307ac000)
libcurl.so.4 => /usr/lib/x86_64-linux-gnu/libcurl.so.4 (0x00007f85cce4e000)
...
libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f85cbb4b000)
libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f85cb6d3000)
...
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f85c6c95000)
Nachtrag 2018/05/16
~~ Ich habe den Artikel versehentlich verwendet und ~~ den offiziellen Namen der Bibliothek. Ich möchte diese Gelegenheit nutzen, um zusammenzufassen.
Name | Beispiel | Überblick |
---|---|---|
Statische Bibliothek | Linux xx.a, Windows xxx.lib | Bibliothek in dem im Programm enthaltenen Format |
Gemeinsame Bibliothek | Linux xx.so, Windows xxx.dll | Bibliothek beim Programmstart verknüpft |
Dynamische Bibliothek | Linux dlopen(), Windows LoadLibrary() | Bibliothek zum Verknüpfen, während das Programm ausgeführt wird |
xx.a, Es fühlt sich wie eine dynamische Bibliothek an, weil es fließend in verschiedene Programme integriert ist. Ich mache oft einen Fehler, wenn ich mein Gehirn nicht wie "Dynamisch ... Oh, es ist ein Name, der von einer anderen Art der Aufnahme stammt" organisiere. ... vielleicht nur ich. Ja
Ich machte einen langen Schritt. Ab hier ist die Produktion. Ich habe etwas gesagt, aber welche Informationen werden nach außen weitergegeben? Programmmäßig ist es ** mit externer Verknüpfung **. (Wagen Sie es, den Ausdruck ** öffentliche Informationen in diesem Artikel ** zu verwenden)
Um es grob in C-Sprache auszudrücken: ** Die Grundlagen sind Funktionen und Variablen **, die nicht statisch definiert sind. Beachten Sie, dass sich die Denkweise zwischen C und C ++ geringfügig unterscheidet. ** Wenn die Klasse nicht statisch ist, kann C ++ interne Variablen möglicherweise nicht gut verarbeiten, selbst wenn die Methode statisch ist **. Korrekt. Andere ** Es ist notwendig, den Unterschied zwischen statisch und statisch zu verstehen, was in C ++ keine öffentlichen Informationen sind **. Weitere Informationen zu C ++ finden Sie unter hier. Dieser Artikel konzentriert sich auf C.
Das Problem mit dieser Bedingung allein ist, dass ** alle Funktionen, die für Dateien in der Bibliothek verwendet werden, öffentliche Informationen sind! **. Danach zeigen wir Ihnen, wie Sie öffentliche Informationen überprüfen und einschränken können. Es überschneidet sich teilweise mit diesem Artikel.
Sie können die öffentlichen Informationen mit dem Befehl nm überprüfen.
Zum Beispiel:
Überprüfen Sie zunächst das Programm selbst.
$nm -D test
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main
U memcmp
U __printf_chk
U publisher_free
U publisher_new
U publisher_publish
U publisher_subscribe
U publisher_unsubscribe
U puts
U __stack_chk_fail
Kleinbuchstaben sind eine lokale Funktion, Details werden weggelassen. Das Problem ist das Kapital. ** U ist ungelöst **, dh eine Funktion, die zur Laufzeit als gemeinsam genutzte Bibliothek verknüpft werden muss. Da publisher_XXX usw. selbst erstellte Funktionen sind, können sie nur verwendet werden, wenn sie veröffentlicht werden.
Auf der anderen Seite sieht die verknüpfte Bibliothek so aus
nm .libs/libpublisher.so
...
0000000000000f90 t dputil_list_pop
0000000000000f50 t dputil_list_pull
0000000000000f20 t dputil_list_push
0000000000000ee0 t dputil_lock
0000000000000f00 t dputil_unlock
...
U pthread_mutex_init@@GLIBC_2.2.5
U pthread_mutex_lock@@GLIBC_2.2.5
U pthread_mutex_unlock@@GLIBC_2.2.5
U __pthread_register_cancel@@GLIBC_2.3.3
U __pthread_unregister_cancel@@GLIBC_2.3.3
w __pthread_unwind_next@@GLIBC_2.3.3
...
00000000000009b0 T publisher_free
0000000000202090 b publisher_g
0000000000000a00 T publisher_new
0000000000000b20 T publisher_publish
0000000000000a90 T publisher_subscribe
0000000000000ae0 T publisher_unsubscribe
0000000000000910 t register_tm_clones
U __sigsetjmp@@GLIBC_2.2.5
U __stack_chk_fail@@GLIBC_2.4
0000000000202078 d __TMC_END__
** T ist öffentliche Information **. Es gibt einen publisher_xxx richtig. Mit anderen Worten, es ist in Ordnung, wenn "libpublisher.so.0.0.0" zur Laufzeit verknüpft werden kann. pthread_mutex_init usw. ist ** U **, aber da dies eine Standardfunktion ist, ist sie normal verknüpft.
Übrigens ist es in dputil_xxx und libpublisher.so
in der obigen lokalen Funktion enthalten, aber es ist tatsächlich eine statische Bibliotheksfunktion.
$ nm .libs/libdputil.a
dp_util.o:
00000000000000b0 T dputil_list_pop
0000000000000070 T dputil_list_pull
0000000000000040 T dputil_list_push
0000000000000000 T dputil_lock
0000000000000020 T dputil_unlock
U _GLOBAL_OFFSET_TABLE_
U pthread_mutex_lock
U pthread_mutex_unlock
Die Tatsache, dass dies nicht ** U ** ist, bedeutet auch, dass libpublisher.so es zur Kompilierungszeit aufgenommen hat.
Sie können die vom Programm gespeicherten Informationen auch mit dem Befehl objdump
sichern. Da Sie andere Informationen als Links überprüfen können, scheint es für die Analyse nützlich zu sein, wenn Sie sie beherrschen (= Ich denke, dass es kurz vor dem Lesen des Assemblers steht).
objdump -t libpublisher.so.0.0.0
libpublisher.so.0.0.0: file format elf64-x86-64
SYMBOL TABLE:
...
0000000000000ee0 l F .text 0000000000000012 dputil_lock
...
0000000000000000 F *UND* 0000000000000000 free@@GLIBC_2.2.5
...
0000000000000ae0 g F .text 0000000000000032 publisher_unsubscribe
...
Wenn ** g wie folgt angehängt ist, sind öffentliche Informationen **, ** l lokal **, ** UND ungelöst **. Bitte verwenden Sie die Durchgangsrichtung für die Bedeutung detaillierter Wörter.
Gleich wie im vorherigen Artikel. ** Geben Sie die Funktion an, die in XXX.map veröffentlicht werden soll, und fügen Sie -Wl, --version-script, libtimelog.map zu den Erstellungsoptionen hinzu **.
LDFLAGS+=-Wl,--version-script,libtimelog.map
libtimelog.map
{
global:
timetestlog_init;
timetestlog_store_printf;
timetestlog_exit;
local: *;
};
Es ist einfach und leicht zu verstehen, aber das Erstellen einer Einstellungsdatei ist mühsam.
-fvisibility=hidden
Wenn Sie "-fvisibility = hidden" angeben, werden alle Funktionen zuerst privat gemacht.
Fügen Sie dann __attribute __ ((Sichtbarkeit (" Standard ")))
nur zu dem hinzu, was Sie benötigen, und veröffentlichen Sie es! Es ist eine Technik namens.
Es ist eine perfekte Möglichkeit für diejenigen, die gerne mit Codierungsregeln steuern.
In libpublisher.so wird bei der Einführung von nm verwendet,
-fvisibility = hidden
angegeben,int __attribute__ ((Sichtbarkeit ("Standard"))) publisher_new (size_t content_num)
für jede öffentliche Funktion
Ich habe es so spezifiziert und gebaut.
Daher bin ich neugierig, dass die API von libdputil.a T ist, aber ich kann es auf ein schönes Gefühl beschränken.
nm -D .libs/libpublisher.so.0.0.0
0000000000202098 B __bss_start
U calloc
w __cxa_finalize
0000000000001210 T dputil_list_pop
00000000000011d0 T dputil_list_pull
00000000000011a0 T dputil_list_push
0000000000001160 T dputil_lock
0000000000001180 T dputil_unlock
0000000000202098 D _edata
00000000002020c0 B _end
0000000000001224 T _fini
U free
w __gmon_start__
0000000000000a00 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U pthread_mutex_init
U pthread_mutex_lock
U pthread_mutex_unlock
U __pthread_register_cancel
U __pthread_unregister_cancel
w __pthread_unwind_next
0000000000000c10 T publisher_free
0000000000000c80 T publisher_new
0000000000000da0 T publisher_publish
0000000000000d10 T publisher_subscribe
0000000000000d60 T publisher_unsubscribe
U __sigsetjmp
U __stack_chk_fail
Ich bevorzuge ** - Versionsskript **, weil ich beim Schreiben von Code nicht öffentlich / privat sein muss. Es fällt mir leicht, sie alle zusammen in conf zu schreiben.
20.05.2018 Nachtrag Mir gefällt auch die Tatsache, dass dies mit einem Skript automatisiert werden kann. Ich habe ein Skriptbeispiel erstellt, das das Include-Verzeichnis durchsucht und ein Versionsskript erstellt. Die Reaktion auf das Makro ist nicht gut, aber ich denke, es kann so verwendet werden, wie es ist.
#!/bin/sh
output_conf_map() {
#{
# global:
# function_name;
# ...
# local: *;
#}
#only get function list from header file
HEADER_FUNC_LIST=`grep "[a-zA-Z](" -r $1 | grep -v "@brief" | grep -v "#define" | awk -F"(" '{print $1}' | awk -F " " '{print $NF}'`
#template
echo "{"
echo " global:"
#show all function
for data in $HEADER_FUNC_LIST
do
echo " $data;"
done
#template end
echo " local: *;"
echo "};"
}
INCLUDE_LIST=`find . -name include`
for inc_dir in $INCLUDE_LIST
do
echo $inc_dir
output_conf_map $inc_dir
done
Zuerst von der Entschuldigung. Der Grund für die Erstellung dieses Artikels ist Artikel zu Einschränkungen bei der Veröffentlichung von Bibliotheken ) Wurde eine Zen-Frage und -Antwort wie "Warum gibt es verschiedene Formen der öffentlichen API-Einschränkung für gemeinsam genutzte Bibliotheken? Was ist überhaupt öffentlich? Warum leben Menschen?" Gepostet und kommentiert. Es war der Anfang. Daher wollte ich die Frage zunächst genau in der Sprache des Programmbereichs beantworten.
Es war jedoch unmöglich, über diesen Bereich zu sprechen, ohne tief zu graben, und da die Frage und Antwort des Zen wirklich begann, dachte ich erneut: "Was war die Bibliothek, die ich organisieren wollte?" Dank dessen habe ich das Gefühl, dass der flauschige Teil gelöscht wurde, unabhängig davon, ob er als oberer Middleware-Entwickler verstanden wird oder nicht.
Danach habe ich viele Probleme in der Bibliothek, aber wenn ich weiß, wie ich es überprüfen kann, wird meine Angst nachlassen. Besonders um OSS. ldd, nm super bequem
Eine Site, die erklärt, wie man sehr sorgfältig mit Speicher umgeht. Kane: Oh, das ist der, von dem ich süchtig bin, wenn ich tiefer grabe. Wenn Sie nach der Codegröße gefragt werden|Dinge, die man in der Schule nicht erzählen kann| [Technische Säulensammlung]Eingebautes Tor|Uquest Co., Ltd.
Handhabung von Funktionen vom Assembler aus gesehen Eine Geschichte, in der man leicht vor der neuesten Technologie besiegt werden kann, wenn man versucht, alte Techniken zu zeigen | Mögliche Eria
Definition der externen Verknüpfung https://msdn.microsoft.com/ja-jp/library/k8w8btzz.aspx
So beschränken Sie die Bibliotheksfreigabe in C ++ So schreiben Sie eine gemeinsam genutzte Bibliothek im C ++ - Format (gcc edition) --Qiita
Wie man nm liest Liste der Symbole aus dem Objekt mit dem Befehl nm anzeigen - Qiita
Bibliotheksname [Bibliothek - Grundkenntnisse der Kommunikationsbegriffe](http://www.wdic.org/w/TECH/ Library)