Compiler une bibliothèque dynamique dans un environnement Linux

Continuez à créer, accélérez la croissance ! C'est le 10ème jour de ma participation au "Nuggets Daily New Plan · June Update Challenge", cliquez pour voir les détails de l'événement

Nous avons précédemment compilé la bibliothèque statique libstar.a pour une utilisation par zeus (Zeus) et poseidon (Poseidon). Étant donné que la bibliothèque statique copiera le contenu dans le programme, cela augmentera l'espace de stockage sur le disque.

S'il y a 100 logiciels qui utilisent une certaine bibliothèque, si cette bibliothèque est liée statiquement à 100 logiciels, la quantité de données sera très importante, donc certaines bibliothèques sous-jacentes du système d'exploitation sont fournies aux appels de programme de niveau supérieur sous la forme de bibliothèques dynamiques.

Et la bibliothèque dynamique a également l'avantage qu'il est facile de mettre à jour une bibliothèque dynamique indépendamment, et vous pouvez utiliser le mécanisme de la bibliothèque dynamique pour créer un système de plug-in.

Comment compilons-nous la bibliothèque dynamique libstar.so ? C'est l'objet de cet article.

Les fichiers associés sun.c , moon.c et earth.c sont toujours dans le répertoire de l'  univers  avant, le code d'extraction : mku9. Utilisez la commande suivante pour compiler la bibliothèque dynamique libstar.so.

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 est une option de compilation, PIC est l'abréviation de Position Independent Code, ce qui signifie générer un code indépendant de la position. Le résultat d'exécution est le suivant :

linux-c-shared-1-1


Utilisez maintenant objdump pour afficher le code assembleur de cette bibliothèque dynamique.

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

linux-c-shared-1-1-1

Comme on peut le voir sur la figure ci-dessus, la bibliothèque dynamique n'est pas la même que la bibliothèque statique précédente, et les adresses des deux appels ont été corrigées. Pourquoi est-ce? Pour ne pas dire de liaison dynamique, il ne sera lié qu'au moment de l'exécution.

Pourquoi l'adresse de l'appel est-elle corrigée à ce moment ?

Notez que  moon_rotate@plt le nom complet du plt derrière est Procedure Linkage Table, nous pouvons voir où le callq 590 suivant sautera, comme suit :

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

Le 590 dans la figure ci-dessus est le décalage dans le fichier du disque dur, et le même contenu binaire peut être vu avec un décalage de 590 octets. Les trois instructions d'assemblage de la figure ci-dessus ne sont pas réellement les instructions de la fonction moon_rate que nous avons définie précédemment.

这个实际上是生成 动态库的时候,给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个目录搜索。

Mais il existe une pratique générale dans l'  /etc/ld.so.conf.d/ ajout d'une configuration personnalisée. Examinons  ld.so.conf le contenu du fichier, comme suit :

linux-c-shared-1-3

Il a été constaté qu'il incluait d'autres fichiers, nous devons donc créer notre propre fichier de configuration  /etc/ld.so.conf.d/star.conf avec le contenu suivant :

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

Créez ensuite un répertoire  /usr/local/star/lib et copiez-y libstar.so  /usr/local/star/lib .

À ce stade, vous devez également recharger la configuration star.conf précédente et exécuter la commande  sudo ldconfig. Il n'y a aucun problème à relancer zeus, même si le libstar.so dans le répertoire courant est supprimé, il peut s'exécuter, car la  /usr/local/star/lib bibliothèque dynamique est recherchée à partir du répertoire lors de l'exécution.

linux-c-shared-1-4

Ci-dessus, j'ai écrit directement le nom complet de la bibliothèque dynamique pour la liaison. En fait, une autre syntaxe plus couramment utilisée pour lier les bibliothèques dynamiques est comme celle-ci. comme suit:

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

-L est le chemin de recherche de la bibliothèque spécifiée. Pour rappel ici, lier et lancer le chargement sont deux opérations différentes . Le chemin à charger a été préalablement  /etc/ld.so.conf.d/star.conf configuré dans le fichier. Vous devez toujours  -L spécifier des paramètres lors de la liaison.


Avant de générer une bibliothèque dynamique libstar-err.so, cette bibliothèque dynamique n'a pas moon.o, et si le projet zeus utilise cette bibliothèque dynamique ? Copiez-y libstar-err.so  /usr/local/star/libet exécutez la commande suivante pour recompiler.

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

On peut voir que l'éditeur de liens signale directement une erreur et ne trouve pas l'implémentation de la fonction moon_rotate.


Lecture connexe :

1. "Bibliothèque statique C++ et bibliothèque dynamique" - Wu Qin

Je suppose que tu aimes

Origine juejin.im/post/7105383802075119647
conseillé
Classement