O que eu sei é que as variáveis globais e estáticas são armazenadas no .data
segmento e os dados não inicializados estão no .bss
segmento. O que não entendo é por que temos segmento dedicado para variáveis não inicializadas? Se uma variável não inicializada tiver um valor atribuído em tempo de execução, a variável ainda existe .bss
apenas no segmento?
No programa seguinte, a
está no .data
segmento e b
está no .bss
segmento; isso está correto? Por favor, corrija-me se meu entendimento estiver errado.
#include <stdio.h>
#include <stdlib.h>
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */
int main ()
{
;
}
Além disso, considere o seguinte programa,
#include <stdio.h>
#include <stdlib.h>
int var[10]; /* Uninitialized so in .bss */
int main ()
{
var[0] = 20 /* **Initialized, where this 'var' will be ?** */
}
c
linux
compiler-construction
Quem sou eu
fonte
fonte
Respostas:
O motivo é reduzir o tamanho do programa. Imagine que seu programa em C seja executado em um sistema embarcado, onde o código e todas as constantes são salvos em verdadeira ROM (memória flash). Em tais sistemas, um "copy-down" inicial deve ser executado para definir todos os objetos de duração de armazenamento estático, antes que main () seja chamado. Normalmente será assim pseudo:
Onde .data e .bss são armazenados na RAM, mas init_value é armazenado na ROM. Se fosse um segmento, a ROM teria que ser preenchida com muitos zeros, aumentando significativamente o tamanho da ROM.
Os executáveis baseados em RAM funcionam de maneira semelhante, embora, é claro, não tenham uma ROM verdadeira.
Além disso, o memset é provavelmente um montador embutido muito eficiente, o que significa que a cópia de inicialização pode ser executada mais rapidamente.
fonte
O
.bss
segmento é uma otimização. Todo o.bss
segmento é descrito por um único número, provavelmente 4 bytes ou 8 bytes, que dá seu tamanho no processo em execução, enquanto a.data
seção é tão grande quanto a soma dos tamanhos das variáveis inicializadas. Assim,.bss
torna os executáveis menores e mais rápidos de carregar. Caso contrário, as variáveis podem estar no.data
segmento com inicialização explícita para zeros; o programa seria pressionado para dizer a diferença. (Em detalhes, o endereço dos objetos em.bss
provavelmente seria diferente do endereço se estivesse no.data
segmento.)No primeiro programa,
a
estaria no.data
segmento eb
estaria no.bss
segmento do executável. Depois que o programa é carregado, a distinção torna-se irrelevante. Em tempo de execução,b
ocupa20 * sizeof(int)
bytes.No segundo programa,
var
é alocado espaço e a atribuição emmain()
modifica esse espaço. Acontece que o espaço paravar
foi descrito no.bss
segmento e não no.data
segmento, mas isso não afeta a maneira como o programa se comporta durante a execução.fonte
edata
). Em termos práticos, o .bss não existe na memória depois que a imagem do processo é concluída; os dados zerados são parte simples da seção .data. Mas os detalhes variam dependendo do o / s etc.Do passo a passo da linguagem Assembly: Programação com Linux por Jeff Duntemann, sobre a seção .data :
e a seção .bss :
fonte
Bem, em primeiro lugar, essas variáveis em seu exemplo não são inicializadas; C especifica que as variáveis estáticas não inicializadas de outra forma são inicializadas com 0.
Portanto, o motivo do .bss é ter executáveis menores, economizando espaço e permitindo um carregamento mais rápido do programa, já que o carregador pode apenas alocar um monte de zeros em vez de ter que copiar os dados do disco.
Ao executar o programa, o carregador do programa carregará .data e .bss na memória. As gravações em objetos que residem em .data ou .bss vão apenas para a memória, não são enviadas para o binário no disco em nenhum momento.
fonte
O System V ABI 4.1 (1997) (especificação AKA ELF) também contém a resposta:
diz que o nome da seção
.bss
é reservado e tem efeitos especiais, em particular, não ocupa espaço de arquivo , assim a vantagem sobre.data
.A desvantagem é, claro, que todos os bytes devem ser definidos
0
quando o sistema operacional os coloca na memória, o que é mais restritivo, mas é um caso de uso comum, e funciona bem para variáveis não inicializadas.A
SHT_NOBITS
documentação do tipo de seção repete essa afirmação:O padrão C não diz nada sobre as seções, mas podemos verificar facilmente onde a variável está armazenada no Linux com
objdump
ereadelf
, e concluir que os globais não inicializados são de fato armazenados no.bss
. Veja, por exemplo, esta resposta: O que acontece com uma variável declarada e não inicializada em C?fonte
O artigo da Wikipedia .bss fornece uma boa explicação histórica, visto que o termo é de meados da década de 1950 (yippee meu aniversário ;-).
Antigamente, cada bit era precioso, então qualquer método para sinalizar um espaço vazio reservado era útil. Este ( .bss ) é o que travou .
Seções .data são para espaço que não está vazio, em vez disso, terá (seus) valores definidos inseridos nele.
fonte