Pergunta

Em qual segmento (.BSS, .De DADOS, outros) de um arquivo executável são variáveis estáticas armazenadas de modo a que eles não têm nome colisão?Por exemplo:


foo.c:                         bar.c:
static int foo = 1;            static int foo = 10;
void fooTest() {               void barTest() {
  static int bar = 2;            static int bar = 20;
  foo++;                         foo++;
  bar++;                         bar++;
  printf("%d,%d", foo, bar);     printf("%d, %d", foo, bar);
}                              }

Se eu compilar os arquivos e vinculá-lo a um principal que chama fooTest() e barTest repetidamente, o printf demonstrações incrementar de forma independente.Faz sentido, já que o foo e bar variáveis são locais para a unidade de tradução.

Mas onde está o armazenamento alocado?

Para ser claro, o pressuposto é que você tem um conjunto de ferramentas que seria um arquivo de saída no formato ELF.Assim, Eu acreditar que não tem para ser algum espaço reservado no arquivo executável para essas variáveis estáticas.
Para fins de discussão, vamos supor que usar o GCC toolchain.

Foi útil?

Solução

Onde seus estática ir depende se eles são zero inicializado ou não. zero inicializado de dados estáticos vai em .bss (Bloco Iniciado por Symbol) , não zero inicializado de dados vai em .DATA

Outras dicas

Quando um programa é carregado na memória, é organizado em diferentes segmentos.Um segmento é Segmento de DADOS.O segmento de Dados é sub-dividido em duas partes:

Inicializado segmento de dados: Todas global, a estática e a constante de dados são armazenados aqui.
Não inicializada segmento de dados(BSS): Todos os dados não inicializados são armazenados neste segmento.

Aqui está um diagrama para explicar esse conceito:

enter image description here


aqui é muito bom link a explicar esses conceitos:

http://www.inf.udec.cl/~leo/teoX.pdf

De facto, uma variável é tuplo (armazenamento, alcance, tipo, endereço, valor):

storage     :   where is it stored, for example data, stack, heap...
scope       :   who can see us, for example global, local...
type        :   what is our type, for example int, int*...
address     :   where are we located
value       :   what is our value

âmbito local poderia significar local ou a unidade de translação (arquivo de origem), a função ou o bloco, dependendo de onde a sua definido. Para tornar a variável visível a mais de uma função, ele definitivamente tem que ser em dados ou área de BSS (dependendo se a sua inicializada explicitamente ou não, respectivamente). Seu então escopo de acordo com qualquer toda a função (s) ou função (s) dentro do arquivo de origem.

O local de armazenamento dos dados será dependente de implementação.

No entanto, o significado de estática é "ligação interna". Assim, o símbolo é interno para a unidade de compilação (foo.c, bar.c) e não pode ser referenciado no exterior dessa unidade de compilação. Assim, não pode haver colisões de nomes.

Eu não acredito que haverá uma colisão. Usando estática no nível de arquivo (funções fora) marca a variável como local para a unidade de compilação atual (arquivo). É fora nunca mais visível o arquivo atual por isso nunca tem que ter um nome.

Usando estática dentro de uma função é diferente -. A variável é visível somente para a função, que é apenas o seu valor é preservada através de chamadas para essa função

Com efeito, estática faz duas coisas diferentes dependendo de onde ele é. Em OTH casos, no entanto, limita a visibilidade da variável para evitar confrontos de nomes,

Dito isto, creio que seria armazenado em dados, que tende a ter inicializado variável. O BSS originalmente significava byte-set- que realizou variáveis ??que não foram inicializados.

Como encontrá-la-se com objdump -Sr

Para realmente entender o que está acontecendo, você deve entender vinculador deslocalização. Se você nunca tocou que, considere lendo este post primeiro .

Vamos analisar um exemplo Linux x86-64 ELF para vê-lo nós mesmos:

#include <stdio.h>

int f() {
    static int i = 1;
    i++;
    return i;
}

int main() {
    printf("%d\n", f());
    printf("%d\n", f());
    return 0;
}

Compilar com:

gcc -ggdb -c main.c

Decompile o código com:

objdump -Sr main.o
  • -S decompiles o código com a fonte original entrelaçar
  • mostra -r informações de relocação

Dentro do decompilation de f vemos:

 static int i = 1;
 i++;
4:  8b 05 00 00 00 00       mov    0x0(%rip),%eax        # a <f+0xa>
        6: R_X86_64_PC32    .data-0x4

eo .data-0x4 diz que ele vai para o primeiro byte do segmento .data.

O -0x4 está lá porque nós estamos usando RIP endereçamento relativo, assim, a %rip na instrução e R_X86_64_PC32.

Ela é necessária porque RIP aponta para o seguinte instrução, que começa 4 bytes após 00 00 00 00 que é o que vai ser realocados. Tenho explicado isso com mais detalhes em: https://stackoverflow.com/a/30515926/895245

Então, se nós modificar a fonte para i = 1 e fazer a mesma análise, concluímos que:

  • static int i = 0 continua .bss
  • static int i = 1 continua .data

na área de "global e estática":)

existem vários área de memória em C ++

  • pilha
  • loja livre
  • pilha
  • Global & estática
  • const

aqui para resposta detalhada à sua pergunta

Depende da plataforma e compilador que você está usando. Alguns compiladores armazenar diretamente no segmento de código. Variáveis ??estáticas são sempre acessíveis apenas para a unidade de tradução atual e os nomes não são exportados Assim, o nome colisões razão nunca ocorrem.

Os dados declarados em uma unidade de compilação vai para o .bss ou o .Data de que a saída de arquivos. dados inicializado em BSS, uninitalised em dados.

A diferença entre estática e dados globais vem na inclusão de informações símbolo no arquivo. Compiladores tendem a incluir as informações de símbolos, mas apenas marcar a informação global como tal.

O vinculador respeita esta informação. As informações símbolo para as variáveis ??estáticas é descartado ou mutilado para que variáveis ??estáticas ainda pode ser referenciado de alguma maneira (com opções de depuração ou símbolo). Em nenhum dos casos pode as unidades de compilação fica afectada como o vinculador resolve referências locais em primeiro lugar.

variável estática armazenada no segmento de dados ou segmento de código como mencionado antes.
Você pode ter certeza de que não serão alocados na pilha ou heap.
Não há risco de colisão desde static palavra-chave definir o escopo da variável a ser um arquivo ou função, em caso de colisão não é um compilador / vinculador para avisá-lo sobre.
Um bom exemplo

Bem, esta pergunta é pouco velho demais, mas desde pontos ninguém out qualquer informação útil: Verifique a mensagem por 'mohit12379' explicando a loja de variáveis ??estáticas com o mesmo nome na tabela de símbolos: http://www.geekinterview.com/question_details/24745

Eu tentei com objdump e gdb, aqui está o resultado que eu recebo:

(gdb) disas fooTest
Dump of assembler code for function fooTest:
   0x000000000040052d <+0>: push   %rbp
   0x000000000040052e <+1>: mov    %rsp,%rbp
   0x0000000000400531 <+4>: mov    0x200b09(%rip),%eax        # 0x601040 <foo>
   0x0000000000400537 <+10>:    add    $0x1,%eax
   0x000000000040053a <+13>:    mov    %eax,0x200b00(%rip)        # 0x601040 <foo>
   0x0000000000400540 <+19>:    mov    0x200afe(%rip),%eax        # 0x601044 <bar.2180>
   0x0000000000400546 <+25>:    add    $0x1,%eax
   0x0000000000400549 <+28>:    mov    %eax,0x200af5(%rip)        # 0x601044 <bar.2180>
   0x000000000040054f <+34>:    mov    0x200aef(%rip),%edx        # 0x601044 <bar.2180>
   0x0000000000400555 <+40>:    mov    0x200ae5(%rip),%eax        # 0x601040 <foo>
   0x000000000040055b <+46>:    mov    %eax,%esi
   0x000000000040055d <+48>:    mov    $0x400654,%edi
   0x0000000000400562 <+53>:    mov    $0x0,%eax
   0x0000000000400567 <+58>:    callq  0x400410 <printf@plt>
   0x000000000040056c <+63>:    pop    %rbp
   0x000000000040056d <+64>:    retq   
End of assembler dump.

(gdb) disas barTest
Dump of assembler code for function barTest:
   0x000000000040056e <+0>: push   %rbp
   0x000000000040056f <+1>: mov    %rsp,%rbp
   0x0000000000400572 <+4>: mov    0x200ad0(%rip),%eax        # 0x601048 <foo>
   0x0000000000400578 <+10>:    add    $0x1,%eax
   0x000000000040057b <+13>:    mov    %eax,0x200ac7(%rip)        # 0x601048 <foo>
   0x0000000000400581 <+19>:    mov    0x200ac5(%rip),%eax        # 0x60104c <bar.2180>
   0x0000000000400587 <+25>:    add    $0x1,%eax
   0x000000000040058a <+28>:    mov    %eax,0x200abc(%rip)        # 0x60104c <bar.2180>
   0x0000000000400590 <+34>:    mov    0x200ab6(%rip),%edx        # 0x60104c <bar.2180>
   0x0000000000400596 <+40>:    mov    0x200aac(%rip),%eax        # 0x601048 <foo>
   0x000000000040059c <+46>:    mov    %eax,%esi
   0x000000000040059e <+48>:    mov    $0x40065c,%edi
   0x00000000004005a3 <+53>:    mov    $0x0,%eax
   0x00000000004005a8 <+58>:    callq  0x400410 <printf@plt>
   0x00000000004005ad <+63>:    pop    %rbp
   0x00000000004005ae <+64>:    retq   
End of assembler dump.

aqui é o resultado objdump

Disassembly of section .data:

0000000000601030 <__data_start>:
    ...

0000000000601038 <__dso_handle>:
    ...

0000000000601040 <foo>:
  601040:   01 00                   add    %eax,(%rax)
    ...

0000000000601044 <bar.2180>:
  601044:   02 00                   add    (%rax),%al
    ...

0000000000601048 <foo>:
  601048:   0a 00                   or     (%rax),%al
    ...

000000000060104c <bar.2180>:
  60104c:   14 00                   adc    $0x0,%al

Então, isso é para dizer, seus quatro variáveis ??estão localizados na seção de dados do evento o mesmo nome, mas com diferente offset.

Esta é a forma como (fácil de entender):

pilha, pilha e dados estáticos

A resposta pode muito bem depender do compilador, então você provavelmente vai querer editar a sua pergunta (quero dizer, mesmo a noção de segmentos não é exigida pelo ISO C nem ISO C ++). Por exemplo, no Windows um executável não carrega nomes de símbolo. Um 'foo' seria compensado 0x100, o outro talvez 0x2B0 e código de ambas as unidades de tradução é compilado saber os deslocamentos para o "seu" foo.

ambos estão indo para ser armazenada de forma independente, no entanto, se você quer deixar claro para outros desenvolvedores que você pode querer envolvê-los em namespaces.

você já sabe ou ele armazenar em BSS (bloco inicial pelo símbolo) também conhecida como segmento de dados não inicializada ou no segmento de dados inicializado.

Vamos dar um exemplo simples

void main(void)
{
static int i;
}

a variável estática acima não é inicializado, assim vai para o segmento de dados não inicializada (BSS).

void main(void)
{
static int i=10;
}

e é claro que inicializado por 10 por isso vai para segmento de dados inicializado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top