lors du chargement d'une bibliothèque partagée dans le système Linux, quelle est la disposition memory de la bibliothèque partagée?
Par exemple, la layout de la memory d'origine est la suivante:
+-----------+ |heap(ori) | +-----------+ |stack(ori) | +-----------+ |.data(ori) | +-----------+ |.text(ori) | +-----------+
Quand je dlopen foo.so
, la disposition de la memory sera A ou B?
A +-----------+ |heap(ori) | +-----------+ |stack(ori) | +-----------+ |.data(ori) | +-----------+ |.text(ori) | +-----------+ |heap(foo) | +-----------+ |stack(foo) | +-----------+ |.data(foo) | +-----------+ |.text(foo) | +-----------+
Ou
B +-----------+ |heap(ori) | +-----------+ |heap(foo) | +-----------+ |stack(foo) | +-----------+ |stack(ori) | +-----------+ |.data(foo) | +-----------+ |.data(ori) | +-----------+ |.text(foo) | +-----------+ |.text(ori) | +-----------+
Ou autre chose que A et B …?
La réponse est "Autre". Vous pouvez avoir un aperçu de la disposition de la memory avec cat /proc/self/maps
. Sur mon ordinateur portable 64 bits Arch ::
00400000-0040c000 r-xp 00000000 08:02 1186758 /usr/bin/cat 0060b000-0060c000 r--p 0000b000 08:02 1186758 /usr/bin/cat 0060c000-0060d000 rw-p 0000c000 08:02 1186758 /usr/bin/cat 02598000-025b9000 rw-p 00000000 00:00 0 [heap] 7fe4b805c000-7fe4b81f5000 r-xp 00000000 08:02 1182914 /usr/lib/libc-2.21.so 7fe4b81f5000-7fe4b83f5000 ---p 00199000 08:02 1182914 /usr/lib/libc-2.21.so 7fe4b83f5000-7fe4b83f9000 r--p 00199000 08:02 1182914 /usr/lib/libc-2.21.so 7fe4b83f9000-7fe4b83fb000 rw-p 0019d000 08:02 1182914 /usr/lib/libc-2.21.so 7fe4b83fb000-7fe4b83ff000 rw-p 00000000 00:00 0 7fe4b83ff000-7fe4b8421000 r-xp 00000000 08:02 1183072 /usr/lib/ld-2.21.so 7fe4b85f9000-7fe4b85fc000 rw-p 00000000 00:00 0 7fe4b85fe000-7fe4b8620000 rw-p 00000000 00:00 0 7fe4b8620000-7fe4b8621000 r--p 00021000 08:02 1183072 /usr/lib/ld-2.21.so 7fe4b8621000-7fe4b8622000 rw-p 00022000 08:02 1183072 /usr/lib/ld-2.21.so 7fe4b8622000-7fe4b8623000 rw-p 00000000 00:00 0 7ffe430c4000-7ffe430e5000 rw-p 00000000 00:00 0 [stack] 7ffe431ed000-7ffe431ef000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Vous pouvez voir que l'exécutable est chargé dans la memory insuffisante, apparemment segment .text, données en lecture seule, et .bss. À peu près tout cela est "tas". Dans une memory beaucoup plus élevée, la bibliothèque C et le "interpréteur de files ELF", "ld-so" sont chargés. Puis vient la stack. Il n'y a qu'une stack et un tas pour un espace d'adressage donné, peu importe le nombre de bibliothèques partagées chargées. cat
semble seulement get la bibliothèque C chargée.
Faire cat /proc/$$/maps
vous donnera les mappages de memory du shell à partir duquel vous avez appelé cat
. Tout shell va avoir un certain nombre de bibliothèques chargées dynamicment, mais zsh
et bash
vont charger un grand nombre. Vous verrez qu'il n'y a qu'un "[tas]" et un "[stack]".
Si vous appelez dlopen()
, le file object partagé sera mappé dans l'espace adresse à une adresse plus haute que /usr/lib/libc-2.21.so
. Il y a un segment de mappage memory "dépendant de l'implémentation", où toutes les adresses renvoyées par mmap()
apparaissent. Voir Anatomie d'un programme en memory pour un joli graphisme.
La source de /usr/lib/ld-2.21.so
est un peu délicate, mais elle partage une bonne partie de ses internes avec dlopen()
. dlopen()
n'est pas un citoyen de deuxième class.
"vdso" et "vsyscall" sont un peu mystérieux, mais cette question Stackoverflow a une bonne explication, tout comme Wikipedia.