Kompilieren Sie die dynamische Bibliothek in der Linux-Umgebung

Schaffen Sie weiter, beschleunigen Sie das Wachstum! Dies ist der 10. Tag meiner Teilnahme an der „Nuggets Daily New Plan · June Update Challenge“, klicken Sie hier, um die Details der Veranstaltung anzuzeigen

Wir haben zuvor die statische Bibliothek libstar.a zur Verwendung durch Zeus (Zeus) und Poseidon (Poseidon) kompiliert. Da die statische Bibliothek den Inhalt in das Programm kopiert, erhöht sie den Speicherplatz auf der Festplatte.

Wenn es 100 Software gibt, die eine bestimmte Bibliothek verwendet, wenn diese Bibliothek statisch mit 100 Software verknüpft ist, wird die Datenmenge sehr groß sein, so dass einige zugrunde liegende Bibliotheken des Betriebssystems den Programmaufrufen der oberen Ebene in der Form bereitgestellt werden von dynamischen Bibliotheken .

Und die dynamische Bibliothek hat auch den Vorteil, dass es einfach ist, eine dynamische Bibliothek unabhängig zu aktualisieren, und Sie den Mechanismus der dynamischen Bibliothek verwenden können, um ein Plug-in-System zu erstellen.

Wie kompilieren wir die dynamische Bibliothek libstar.so? Dies ist der Schwerpunkt dieses Artikels.

Die zugehörigen Dateien sun.c , moon.c und earth.c liegen noch im  Universe  -Verzeichnis vor, der Extraktionscode: mku9. Verwenden Sie den folgenden Befehl, um die dynamische Bibliothek libstar.so zu kompilieren.

gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c 
gcc -fPIC -shared -o libstar.so sun.o moon.o earth.o
复制代码

-fPIC ist eine Kompilierungsoption, PIC ist die Abkürzung für Position Independent Code, was bedeutet, positionsunabhängigen Code zu erzeugen. Das Ausführungsergebnis ist wie folgt:

linux-c-shared-1-1


Verwenden Sie nun objdump, um den Assemblercode dieser dynamischen Bibliothek anzuzeigen.

objdump -d libstar.so > star-so-dump.txt
复制代码

linux-c-shared-1-1-1

Wie aus der obigen Abbildung ersichtlich, ist die dynamische Bibliothek nicht dieselbe wie die vorherige statische Bibliothek, und die Adressen der beiden Aufrufe wurden korrigiert. Warum ist das? Um nicht zu sagen dynamisches Linken, es wird nur zur Laufzeit verlinkt.

Warum wird die Adresse des Anrufs in diesem Moment korrigiert?

Beachten Sie, dass  moon_rotate@plt der vollständige Name des plt dahinter Procedure Linkage Table ist. Wir können wie folgt sehen, wohin der folgende callq 590 springt:

linux-c-shared-1-1-1-1

Die 590 in der obigen Abbildung ist der Offset in der Festplattendatei, und derselbe binäre Inhalt ist mit einem Offset von 590 Byte zu sehen. Die drei Assembler-Anweisungen in der obigen Abbildung sind eigentlich nicht die Anweisungen der Funktion moon_rate, die wir zuvor definiert haben.

这个实际上是生成 动态库的时候,给call 00 00 00 的函数引用封装一层。通过 gdb 调试会会发现,程序是先 进入 moon_rate@plt ,然后再通过 jmpq 跳转到 真正的 moon_rate 函数。

这个过程可以理解为, 通过 Procedure Linkage Table 表,跳转到真正的函数。


我们再做一个实验,生成 libstar.so 动态库的时候,把 moon.o 删掉,不加入。看看 sun.o 里面对 moon_rate 的引用会不会被修正。

提醒:注意这个 libstar-err.so,这个漏了 moon.o 的动态库后面会用来显示一个错误的情况。

gcc -fPIC -shared -o libstar-err.so sun.o earth.o
复制代码

linux-c-shared-1-1-1-2

从上图可以看到,即使没有 moon.o 依然会被修正。但是 这个 libstar-err.so 是有问题的,可以使用 ldd 加上 -r 选项进行模拟重定位函数,会发现找不到 moon_rorate 函数的实现。

linux-c-shared-1-1-1-3


因为 sun.o 里面调了 printf 函数,所以用 ldd 查看,可以发现 libstar.so 跟 libc.so 已经建立了链接。

linux-c-shared-1-1-2


现在把 libstar.so 拷贝到 zeus 项目,执行以下命令编译。

gcc -c -o zeus.o zeus.c
gcc -o zeus zeus.o libstar.so
./zeus
复制代码

linux-c-shared-1-2

从上图可以看出,虽然可以顺利链接,生成 zeus 文件,但是运行的时候却报找不到 libstar.so 动态库,这是因为 Linux 环境默认不会从当前路径 加载动态库。而 Windows 环境会从当前路径 加载动态库。

那Linux 的加载器会从哪些目录搜索加载动态库呢?业界制定了一个 FHS (File Hierarchy Standard)标准,这个标准规定了一个系统中的系统文件应该如何存放,大部分Linux系统都遵循这个标准。

共享库的存放方式也在这个 FHS 标准里面,标准定义共享库可以放在 /lib , /usr/lib , /usr/local/lib 这 3个目录。所以运行加载动态库的时候,也会在这 3个目录搜索。

Es gibt jedoch eine allgemeine Vorgehensweise beim  /etc/ld.so.conf.d/ Hinzufügen einer benutzerdefinierten Konfiguration. Schauen wir uns  ld.so.conf den Inhalt der Datei wie folgt an:

linux-c-shared-1-3

Es wurde festgestellt, dass er andere Dateien eingebunden hat, also müssen wir unsere eigene Konfigurationsdatei  /etc/ld.so.conf.d/star.conf mit folgendem Inhalt erstellen:

# star default configuration
/usr/local/star/lib
复制代码

Erstellen Sie dann ein Verzeichnis  /usr/local/star/lib und kopieren Sie libstar.so dorthin  /usr/local/star/lib .

An dieser Stelle müssen Sie auch die vorherige star.conf-Konfiguration neu laden und den Befehl ausführen  sudo ldconfig. Es ist kein Problem, zeus erneut auszuführen, selbst wenn die libstar.so im aktuellen Verzeichnis gelöscht wird, kann es ausgeführt werden, da die  /usr/local/star/lib dynamische Bibliothek beim Ausführen aus dem Verzeichnis durchsucht wird .

linux-c-shared-1-4

Oben habe ich direkt den vollständigen Namen der dynamischen Bibliothek zum Linken geschrieben.Tatsächlich ist eine andere häufiger verwendete Syntax zum Linken dynamischer Bibliotheken so. folgendermaßen:

gcc -o zeus zeus.o -L/usr/local/star/lib -lstar
复制代码

-L ist der Suchpfad für die angegebene Bibliothek. Zur Erinnerung: Das Verknüpfen und Ausführen des Ladevorgangs sind zwei verschiedene Vorgänge . Der zu ladende Pfad wurde zuvor  /etc/ld.so.conf.d/star.conf in der Datei konfiguriert. Sie müssen  -L beim Verknüpfen noch Parameter angeben.


Bevor wir eine dynamische Bibliothek libstar-err.so generiert haben, hat diese dynamische Bibliothek kein moon.o, was ist, wenn das Zeus-Projekt diese dynamische Bibliothek verwendet? Kopieren Sie libstar-err.so dorthin  /usr/local/star/libund führen Sie den folgenden Befehl aus, um erneut zu kompilieren.

mv libstar-err.so /usr/local/star/lib
gcc -o zeus-err zeus.o -L/usr/local/star/lib -lstar-err
复制代码

linux-c-shared-1-4-1

Es ist ersichtlich, dass der Linker direkt einen Fehler meldet und die Funktionsimplementierung von moon_rotate nicht finden kann.


Verwandte Lektüre:

1. „Statische C++-Bibliothek und dynamische Bibliothek“ – Wu Qin

Ich denke du magst

Origin juejin.im/post/7105383802075119647
Empfohlen
Rangfolge