Layout de memória da biblioteca dinâmica carregada / vinculada

4

ao carregar uma biblioteca compartilhada no sistema Linux, qual é o layout da memória da biblioteca compartilhada?

Por exemplo, o layout da memória original é o seguinte:

+-----------+
|heap(ori)  |
+-----------+
|stack(ori) |
+-----------+
|.data(ori) |
+-----------+
|.text(ori) |
+-----------+

Quando eu dlopen foo.so , o layout da memória será 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 algo diferente de A e B ...?

    
por Richard 04.05.2015 / 18:33

1 resposta

4

A resposta é "Outro". Você pode obter um vislumbre do layout de memória com cat /proc/self/maps . No meu laptop Arch de 64 bits ::

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]

Você pode ver que o executável é carregado em pouca memória, aparentemente. segmento de texto, dados somente leitura e .bss. Apenas sobre isso é "heap". Em uma memória muito maior, a biblioteca C e o "interpretador de arquivos ELF", "ld-so" são carregados. Então vem a pilha. Há apenas uma pilha e um heap para qualquer espaço de endereço, não importa quantas bibliotecas compartilhadas sejam carregadas. cat parece apenas obter a biblioteca C carregada.

Fazer cat /proc/$$/maps fornecerá os mapeamentos de memória do shell a partir do qual você chamou cat . Qualquer shell terá várias bibliotecas carregadas dinamicamente, mas zsh e bash serão carregadas em um grande número. Você verá que há apenas um "[heap]" e um "[pilha]".

Se você chamar dlopen() , o arquivo de objeto compartilhado será mapeado no espaço de endereço em um endereço superior a /usr/lib/libc-2.21.so . Há um segmento de mapeamento de memória "dependente da implementação", em que todos os endereços retornados por mmap() são exibidos. Veja Anatomia de um programa na memória para um bom gráfico.

A fonte para /usr/lib/ld-2.21.so é um pouco complicada, mas compartilha uma boa parte de seus internos com dlopen() . dlopen() não é um cidadão de segunda classe.

"vdso" e "vsyscall" são um tanto misteriosos, mas esta questão do Stackoverflow tem uma boa explicação, assim como a Wikipedia.

    
por 04.05.2015 / 21:04