¿Dónde se almacenan las variables estáticas (en C / C ++)?

¿En qué segmento (.BSS, .DATA, otro) de un archivo ejecutable se almacenan variables estáticas para que no tengan colisión de nombres? Por ejemplo:

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); } } 

Si compilo ambos archivos y lo vinculo a un main que llama a fooTest () y barTest repetidamente, las instrucciones de printf se incrementan de manera independiente. Tiene sentido ya que las variables foo y bar son locales a la unidad de traducción.

Pero, ¿dónde se asigna el almacenamiento?

Para ser claros, la suposición es que tienes una cadena de herramientas que daría salida a un archivo en formato ELF. Por lo tanto, creo que debe haber un espacio reservado en el archivo ejecutable para esas variables estáticas.
Para fines de discusión, supongamos que usamos la cadena de herramientas GCC.

Su estado estático depende de si están 0 inicializados o no. 0 los datos estáticos inicializados entran en .BSS (Bloque iniciado por el símbolo) , los datos inicializados no 0 entran en .DATA

Cuando un progtwig se carga en la memoria, se organiza en diferentes segmentos. Uno de los segmentos es el segmento de DATOS . El segmento de datos se subdivide en dos partes:

Segmento de datos inicializado: todos los datos globales, estáticos y constantes se almacenan aquí.
Segmento de datos no inicializados (BSS): todos los datos no inicializados se almacenan en este segmento.

Aquí hay un diagtwig para explicar este concepto:

enter image description here

Aquí hay un enlace muy bueno que explica estos conceptos:

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

De hecho, una variable es tupla (almacenamiento, scope, tipo, dirección, 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 

El scope local podría significar local para la unidad de traducción (archivo de origen), la función o el bloque dependiendo de dónde esté definido. Para que la variable sea visible para más de una función, definitivamente tiene que estar en DATA o en el área BSS (dependiendo de si se inicializó explícitamente o no, respectivamente). Entonces se delimita de acuerdo con todas las funciones o funciones dentro del archivo fuente.

La ubicación de almacenamiento de los datos dependerá de la implementación.

Sin embargo, el significado de estática es “vinculación interna”. Por lo tanto, el símbolo es interno a la unidad de comstackción (foo.c, bar.c) y no se puede hacer referencia fuera de esa unidad de comstackción. Entonces, no puede haber colisiones de nombres.

No creo que haya una colisión. El uso de estática en el nivel de archivo (funciones externas) marca la variable como local en la unidad de comstackción actual (archivo). Nunca es visible fuera del archivo actual, por lo que nunca debe tener un nombre.

El uso de estática dentro de una función es diferente: la variable solo es visible para la función, solo se conserva su valor en llamadas a esa función.

En efecto, la estática hace dos cosas diferentes dependiendo de dónde se encuentre. En otros casos, sin embargo, limita la visibilidad de la variable para evitar conflictos entre espacios de nombres,

Una vez dicho esto, creo que se almacenará en DATA, que tiende a tener una variable inicializada. El BSS originalmente significaba byte-set- que contenía variables que no se habían inicializado.

Cómo encontrarlo tú mismo con objdump -Sr

Para comprender realmente lo que está sucediendo, debe comprender la reubicación del vinculador. Si nunca has tocado eso, considera leer esta publicación primero .

Analicemos un ejemplo de ELF Linux x86-64 para verlo nosotros mismos:

 #include  int f() { static int i = 1; i++; return i; } int main() { printf("%d\n", f()); printf("%d\n", f()); return 0; } 

Comstackr con:

 gcc -ggdb -c main.c 

Descompile el código con:

 objdump -Sr main.o 
  • -S descomstack el código con la fuente original entremezclada
  • -r muestra información de reubicación

Dentro de la descomstackción de f vemos:

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

y el .data-0x4 dice que irá al primer byte del segmento .data .

El -0x4 está ahí porque estamos usando el direccionamiento relativo RIP, por lo tanto, el %rip en la instrucción y R_X86_64_PC32 .

Es necesario porque RIP apunta a la siguiente instrucción, que comienza en 4 bytes después de 00 00 00 00 que es lo que se reubicará. Lo he explicado con más detalle en: https://stackoverflow.com/a/30515926/895245

Entonces, si modificamos la fuente a i = 1 y hacemos el mismo análisis, concluimos que:

  • static int i = 0 continúa .bss
  • static int i = 1 continúa .data

Depende de la plataforma y el comstackdor que esté utilizando. Algunos comstackdores almacenan directamente en el segmento de código. Las variables estáticas siempre son accesibles solo para la unidad de traducción actual y los nombres no se exportan, por lo que las colisiones de nombres de razón nunca se producen.

Los datos declarados en una unidad de comstackción entrarán en .BSS o en .Data de esa salida de archivos. Datos inicializados en BSS, no inicializados en DATA.

La diferencia entre los datos estáticos y globales viene en la inclusión de información de símbolos en el archivo. Los comstackdores tienden a incluir la información del símbolo, pero solo marcan la información global como tal.

El enlazador respeta esta información. La información de símbolos para las variables estáticas se descarta o se destruye, de modo que las variables estáticas todavía se pueden referenciar de alguna manera (con opciones de depuración o símbolo). En ninguno de los casos, las unidades de comstackción se ven afectadas ya que el enlazador resuelve primero las referencias locales.

en el área “global y estática” 🙂

hay varias áreas de memoria en C ++

  • montón
  • tienda gratis
  • astackr
  • global y estático
  • const

mira aquí para una respuesta detallada a tu pregunta

variable estática almacenada en segmento de datos o segmento de código como se mencionó anteriormente.
Puede estar seguro de que no se asignará en stack o heap.
No hay riesgo de colisión, ya que static palabra clave static define el scope de la variable como un archivo o función, en caso de colisión existe un comstackdor / vinculador para advertirle.
Un buen ejemplo

Bueno, esta pregunta es demasiado antigua, pero como nadie señala ninguna información útil: revise la publicación por ‘mohit12379’ explicando la tienda de variables estáticas con el mismo nombre en la tabla de símbolos: http://www.geekinterview.com/question_details/ 24745

Lo intenté con objdump y gdb, aquí está el resultado que obtengo:

 (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  0x0000000000400537 <+10>: add $0x1,%eax 0x000000000040053a <+13>: mov %eax,0x200b00(%rip) # 0x601040  0x0000000000400540 <+19>: mov 0x200afe(%rip),%eax # 0x601044  0x0000000000400546 <+25>: add $0x1,%eax 0x0000000000400549 <+28>: mov %eax,0x200af5(%rip) # 0x601044  0x000000000040054f <+34>: mov 0x200aef(%rip),%edx # 0x601044  0x0000000000400555 <+40>: mov 0x200ae5(%rip),%eax # 0x601040  0x000000000040055b <+46>: mov %eax,%esi 0x000000000040055d <+48>: mov $0x400654,%edi 0x0000000000400562 <+53>: mov $0x0,%eax 0x0000000000400567 <+58>: callq 0x400410  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  0x0000000000400578 <+10>: add $0x1,%eax 0x000000000040057b <+13>: mov %eax,0x200ac7(%rip) # 0x601048  0x0000000000400581 <+19>: mov 0x200ac5(%rip),%eax # 0x60104c  0x0000000000400587 <+25>: add $0x1,%eax 0x000000000040058a <+28>: mov %eax,0x200abc(%rip) # 0x60104c  0x0000000000400590 <+34>: mov 0x200ab6(%rip),%edx # 0x60104c  0x0000000000400596 <+40>: mov 0x200aac(%rip),%eax # 0x601048  0x000000000040059c <+46>: mov %eax,%esi 0x000000000040059e <+48>: mov $0x40065c,%edi 0x00000000004005a3 <+53>: mov $0x0,%eax 0x00000000004005a8 <+58>: callq 0x400410  0x00000000004005ad <+63>: pop %rbp 0x00000000004005ae <+64>: retq End of assembler dump. 

aquí está el resultado objdump

 Disassembly of section .data: 0000000000601030 <__data_start>: ... 0000000000601038 <__dso_handle>: ... 0000000000601040 : 601040: 01 00 add %eax,(%rax) ... 0000000000601044 : 601044: 02 00 add (%rax),%al ... 0000000000601048 : 601048: 0a 00 or (%rax),%al ... 000000000060104c : 60104c: 14 00 adc $0x0,%al 

Entonces, es decir, sus cuatro variables están ubicadas en el evento de sección de datos con el mismo nombre, pero con diferente desplazamiento.

La respuesta puede muy bien depender del comstackdor, por lo que probablemente desee editar su pregunta (es decir, incluso la noción de segmentos no es un mandato de ISO C ni ISO C ++). Por ejemplo, en Windows, un ejecutable no tiene nombres de símbolos. Un ‘foo’ se compensaría 0x100, el otro quizás 0x2B0, y el código de ambas unidades de traducción se comstackrá conociendo las compensaciones para “su” foo.

ambos se almacenarán de forma independiente, sin embargo, si quieres dejar en claro a otros desarrolladores, es posible que quieras envolverlos en espacios de nombres.

Así es como (fácil de entender):

pila, montón y datos estáticos

ya sabes que almacena en bss (inicio de bloque por símbolo) también denominado segmento de datos no inicializados o en segmento de datos inicializados.

vamos a tomar un ejemplo simple

 void main(void) { static int i; } 

la variable estática anterior no se inicializa, por lo que va al segmento de datos no inicializados (bss).

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

y, por supuesto, se inicializó por 10 para que vaya al segmento de datos inicializados.