Les bibliothèques partagées utilisent-elles le même tas que l’application?

Disons que j’ai une application sous Linux qui utilise des bibliothèques partagées (fichiers .so ). Ma question est de savoir si le code dans ces bibliothèques allouera de la mémoire dans le même segment de mémoire que l’application principale ou utilise-t-il leur propre segment de mémoire?

Ainsi, par exemple, certaines fonctions du fichier .so appellent malloc , utiliserait-il le même gestionnaire de segments de mémoire que l’application ou une autre? Aussi, qu’en est-il des données globales dans ces mémoires partagées. Où est-ce que ça ment? Je sais que pour l’application, elle se situe dans le segment bss et le segment de données, mais je ne sais pas où il se trouve pour ces fichiers d’objects partagés.

Ma question est de savoir si le code dans ces bibliothèques allouera de la mémoire dans le même segment de mémoire que l’application principale ou utilise-t-il leur propre segment de mémoire?

Si la bibliothèque utilise le même malloc/free que l’application (par exemple de glibc ) – alors oui, le programme et toutes les bibliothèques utiliseront le tas unique.

Si la bibliothèque utilise directement mmap , elle peut allouer de la mémoire qui n’est pas la mémoire utilisée par le programme lui-même.

Ainsi, par exemple, certaines fonctions du fichier .so appellent malloc, utiliserait-il le même gestionnaire de segments de mémoire que l’application ou une autre?

Si function from .so appelle malloc, ce malloc est le même que malloc appelé depuis le programme. Vous pouvez voir le journal de liaison de symboles dans Linux / glibc (> 2.1) avec

  LD_DEBUG=bindings ./your_program 

Oui, plusieurs instances de gestionnaires de tas (avec la configuration par défaut) ne peuvent pas coexister sans se connaître (le problème est de garder la taille du tas allouée par brk synchronisée entre les instances). Mais il existe une configuration possible lorsque plusieurs instances peuvent coexister.

La plupart des implémentations malloc classiques (ptmalloc *, dlmalloc, etc.) peuvent utiliser deux méthodes pour récupérer de la mémoire du système: brk et mmap . Brk est le tas classique, linéaire et pouvant croître ou diminuer. Mmap permet d’obtenir beaucoup de mémoire partout. et vous pouvez restaurer cette mémoire dans le système (le libérer) dans n’importe quel ordre.

Lorsque malloc est créé, la méthode brk peut être désactivée. Ensuite, malloc émulera le tas linéaire en utilisant seulement mmap s ou même désactivera le tas linéaire classique et toutes les allocations seront faites à partir de fragmens mmaped non contigus.

Ainsi, certaines bibliothèques peuvent avoir leur propre gestionnaire de mémoire, par exemple malloc compilé avec brk disabled ou avec un gestionnaire de mémoire non-malloc. Ce gestionnaire doit avoir des noms de fonctions autres que malloc et free , par exemple malloc1 et free1 ou ne pas afficher / exporter ces noms vers l’éditeur de liens dynamic.

Aussi, qu’en est-il des données globales dans ces mémoires partagées. Où est-ce que ça se trouve? Je sais que pour l’application, elle se situe dans le segment bss et le segment de données, mais je ne sais pas où il se trouve pour ces fichiers d’objects partagés.

Vous devriez penser à la fois au programme et à .so, tout comme aux fichiers ELF. Chaque fichier ELF a “en-têtes de programme” ( readelf -l elf_file ). La manière dont les données sont chargées depuis ELF en mémoire dépend du type d’en-tête de programme. Si le type est ” LOAD “, la partie correspondante du fichier sera en privé mmap ed (Sic!) En mémoire. Généralement, il y a 2 segments LOAD; le premier pour le code avec les indicateurs R + X (read + execute) et le second pour les données avec les indicateurs R + W (read + write). Les .bss et .data (données globales) sont placées dans le segment de type LOAD avec l’indicateur permettant l’écriture.

La bibliothèque exécutable et la bibliothèque partagée ont des segments LOAD. Certains segments ont memory_size> taille_fichier. Cela signifie que ce segment sera développé en mémoire; la première partie sera remplie avec les données du fichier ELF, et la seconde partie (memory_size-file_size) sera remplie avec zéro (pour les sections *bss ), en utilisant mmap(/dev/zero) et memset(0)

Lorsque l’éditeur de liens kernel ou dynamic charge le fichier ELF en mémoire, il ne pense pas au partage. Par exemple, vous souhaitez lancer le même programme deux fois. Le premier processus chargera la partie en lecture seule du fichier ELF avec mmap; le deuxième processus fera le même mmap (si aslr est actif – le second mmap sera dans une adresse virtuelle différente). C’est la tâche du cache de page (sous-système VFS) de conserver une copie unique des données dans la mémoire physique (avec COPY-on-WRITE, ou COW); et mmap configurera simplement les mappages de l’adresse virtuelle dans chaque processus en un seul emplacement physique. Si un processus change une page de mémoire; il sera copié en écriture sur une mémoire physique privée unique.

Le code de chargement se trouve dans glibc/elf/dl-load.c ( _dl_map_object_from_fd ) pour ld.so et linux-kernel/fs/binfmt_elf.c pour le chargeur ELF du kernel ( elf_map , load_elf_binary ). Faites une recherche pour PT_LOAD .

Ainsi, les données globales et les données bss sont toujours regroupées en privé dans chaque processus, et elles sont protégées avec COW.

Le tas et la stack sont alloués en run-time avec brk + mmap (heap) et par le kernel OS automatiquement dans un processus de type brk (pour la stack du thread principal). Les stacks de threads supplémentaires sont allouées avec mmap dans pthread_create .

Les tables de symboles sont partagées sur tout un processus sous Linux. malloc() pour toutes les parties du processus est identique à toutes les autres parties. Alors oui, si toutes les parties d’un processus accèdent au tas via malloc() et d’autres, elles partageront le même tas.