Isso não é verdade para "quase todo o SO". Os tipos de áreas de memória representadas são bastante típicos, mas não há motivo para que eles estejam em uma ordem específica e pode haver mais de uma parte de um determinado tipo.
No Linux, você pode examinar o espaço de endereço de um processo com cat /proc/$pid/maps
onde $pid
está o ID do processo, por exemplo, cat /proc/$$/maps
para ver o shell do qual você está executando cat
ou cat /proc/self/maps
para ver os cat
mapeamentos do próprio processo. O comando pmap
produz uma saída um pouco melhor.
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08054000-08055000 r--p 0000b000 08:01 828061 /bin/cat
08055000-08056000 rw-p 0000c000 08:01 828061 /bin/cat
08c7f000-08ca0000 rw-p 00000000 00:00 0 [heap]
b755a000-b7599000 r--p 00000000 08:01 273200 /usr/lib/locale/en_US.utf8/LC_CTYPE
b7599000-b759a000 rw-p 00000000 00:00 0
b759a000-b76ed000 r-xp 00000000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76ed000-b76ee000 ---p 00153000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76ee000-b76f0000 r--p 00153000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76f0000-b76f1000 rw-p 00155000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76f1000-b76f4000 rw-p 00000000 00:00 0
b770b000-b7712000 r--s 00000000 08:01 271618 /usr/lib/gconv/gconv-modules.cache
b7712000-b7714000 rw-p 00000000 00:00 0
b7714000-b7715000 r-xp 00000000 00:00 0 [vdso]
b7715000-b7730000 r-xp 00000000 08:01 263049 /lib/ld-2.11.1.so
b7730000-b7731000 r--p 0001a000 08:01 263049 /lib/ld-2.11.1.so
b7731000-b7732000 rw-p 0001b000 08:01 263049 /lib/ld-2.11.1.so
bfbec000-bfc01000 rw-p 00000000 00:00 0 [stack]
Você pode ver o código e os dados de leitura e gravação (texto e BSS) do executável, o heap, o arquivo mapeado na memória, um pouco mais de dados de leitura e gravação, código, dados somente leitura e leitura. grave dados de uma biblioteca compartilhada (texto e BSS novamente), mais dados de leitura e gravação, outra biblioteca compartilhada (mais precisamente, o vinculador dinâmico) e, finalmente, a única pilha do encadeamento.
O código do kernel usa seus próprios intervalos de endereços. Em muitas plataformas, o Linux usa a parte superior do espaço de endereço para o kernel, geralmente o superior de 1 GB. Idealmente, esse espaço seria suficiente para mapear o código do kernel, os dados do kernel e a memória do sistema (RAM) e todos os dispositivos mapeados na memória. Nos PCs típicos de 32 bits atuais, isso não é possível, o que requer contorções que são de interesse apenas dos hackers do kernel.
Enquanto o código do kernel está lidando com uma chamada do sistema, idealmente (quando as contorções acima mencionadas não estão no lugar), a memória do processo é mapeada nos mesmos endereços. Isso permite que os processos passem dados para o kernel, e o kernel pode ler diretamente do ponteiro. Porém, não é um grande ganho, já que os ponteiros precisam ser validados de qualquer maneira (para que o processo não consiga induzir o kernel a ler na memória que o processo não deveria ter acesso).
As zonas de memória dentro do espaço do kernel do Linux são bastante complexas. Existem vários conjuntos de memórias diferentes, e as principais distinções não são de onde vem a memória, mas com quem é compartilhada. Se você estiver curioso sobre eles, comece com LDD3 .
where.c
, no Ubuntu 11.04 usandogcc where.c -o where
; relatórios "principal em 0x80483c4". Tenteireadelf -S where
, e relata, dizer "[13] .text PROGBITS 08048310 ...", o que parece certo? Embora eu também receba "ac em 0xbfb035a0" e "local em 0xbfb0358c", e esse intervalo de endereços (0xbf ...) parece não ser relatado porreadelf -S
.ac
eav
a variável automáticalocal
provavelmente terão endereços diferentes em cada chamada. A maioria dos kernels Linux modernos tem "Randomização do Layout do Espaço de Endereço" para dificultar a exploração dos estouros de buffer.