Antes de começarmos, deixo aqui uma imagem ilustrativa do layout de memória. Vamos seguir nosso estudo partindo do endereço mais alto até o mais baixo.
Fonte: Próprio Autor
Kernel
Uma das primeiras coisas que a arquitetura de memória define é o espaço do Sistema Operacional (Kernel Space). Ele ocupa os endereços mais altos para garantir que o 'cérebro' do computador tenha uma área reservada e protegida, permitindo que todos os outros processos funcionem com segurança abaixo dele.
Fonte: Próprio Autor
Ambiente
Com o Kernel já residente na memória, o sistema prepara as variáveis de ambiente. Essas variáveis funcionam como um guia de configuração para os programas, definindo o 'cenário' onde eles serão executados e permitindo que saibam onde encontrar arquivos e recursos do sistema.
Fonte: Próprio Autor
Argumentos
Depois que o sistema inicializa e as variáveis de ambiente são carregadas, a memória organiza os Argumentos, que são as instruções extras que dizem como o programa deve começar.
Fonte: Próprio Autor
A quantidade de argumentos vem logo depois, até porque o sistema precisa saber exatamente quantas instruções ele recebeu, garantindo assim que ele processe cada uma delas na ordem certa para tudo funcionar como deveria.
Fonte: Próprio Autor
Dados das Funções
Agora que entendemos como o sistema se organiza, chegamos aos Dados das Funções. É nesta área que o programa ganha vida, as funções são empilhadas e executadas conforme a necessidade, lembrando que a primeira a ser chamada é a main.
Fonte: Próprio Autor
Stack
Para facilitar nosso entendimento podemos visualizar esse bloco como uma Pilha (Stack), no topo (endereços mais altos), o sistema injeta o Ambiente e os Argumentos com sua Quantidade (argc). Imediatamente abaixo, a execução começa e a pilha continua crescendo para baixo conforme os Dados das Funções e suas variáveis locais são criadas. Logo, uma estrutura única, onde o contexto do sistema e a execução do código convivem.
Fonte: Próprio Autor
Espaço Disponível
Como a alocação de memória ocorre de forma dinâmica, tanto a Stack quanto o Heap podem expandir conforme as necessidades do programa. Por isso, a arquitetura reserva um Espaço Disponível entre ambos: a Stack cresce para baixo e o Heap para cima. Caso a demanda de memória seja excessiva e as duas áreas se encontrem, ocorre uma colisão conhecida como estouro de memória (Memory Overflow).
Fonte: Próprio Autor
Memória Mapeada
Em vez de carregar o arquivo inteiro para a RAM, o sistema operacional estabelece um vínculo lógico entre a memória e o armazenamento. Os dados são carregados em 'páginas' apenas quando acessados, o que otimiza o uso de recursos e acelera a execução, especialmente em arquivos grandes ou bibliotecas compartilhadas.
Fonte: Próprio Autor
Heap
A alocação dinâmica é quando o seu programa pede um pedaço de memória enquanto está rodando, porque ele não sabe de antemão de quanto espaço vai precisar. Alguns problemas bem comuns da programação acontece aqui, pois você pode alocar memória, porém tem que depois lembrar de liberar essa memória alocada.
Fonte: Próprio Autor
.bss
.bss é uma seção específica da memória de um programa que armazena variáveis globais e estáticas que foram declaradas, mas não foram inicializadas com nenhum valor específico.
Fonte: Próprio Autor
.data
Enquanto o .bss cuida do que está "vazio", o .data é responsável por armazenar todas as variáveis globais e estáticas que você já inicializou com um valor específico no seu código.
Fonte: Próprio Autor
.rodata
.rodata é o segmento de memória destinado exclusivamente a dados que o programa pode ler, mas nunca alterar durante a execução.
Fonte: Próprio Autor
.text
É no .text que o seu código realmente vive depois de ser transformado em linguagem de máquina, armazenando as instruções binárias.
Fonte: Próprio Autor
Caso queira continuar estudando e aprender mais sobre outros conteúdos, segue o link. Bons estudos!
"A beleza que vive no ato de compartilhar algo com o outro." — Monja Coen