Lo que sé es que las variables globales y estáticas se almacenan en el .data
segmento y los datos no inicializados están en el .bss
segmento. Lo que no entiendo es por qué tenemos un segmento dedicado para las variables no inicializadas. Si una variable no inicializada tiene un valor asignado en tiempo de ejecución, ¿existe la variable .bss
solo en el segmento?
En el siguiente programa, a
está en el .data
segmento y b
está en el .bss
segmento; ¿Es eso correcto? Por favor corríjame si mi comprensión es incorrecta.
#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 ()
{
;
}
Además, considere el siguiente 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
Quién soy
fuente
fuente
Respuestas:
La razón es reducir el tamaño del programa. Imagine que su programa C se ejecuta en un sistema integrado, donde el código y todas las constantes se guardan en una ROM real (memoria flash). En tales sistemas, se debe ejecutar una "copia abajo" inicial para establecer todos los objetos de duración de almacenamiento estático, antes de llamar a main (). Normalmente será así pseudo:
Donde .data y .bss se almacenan en RAM, pero init_value se almacena en ROM. Si hubiera sido un segmento, entonces la ROM tenía que llenarse con muchos ceros, aumentando significativamente el tamaño de la ROM.
Los ejecutables basados en RAM funcionan de manera similar, aunque, por supuesto, no tienen una ROM real.
Además, Memset es probablemente un ensamblador en línea muy eficiente, lo que significa que la copia de inicio se puede ejecutar más rápido.
fuente
El
.bss
segmento es una optimización. Todo el.bss
segmento se describe con un solo número, probablemente 4 bytes u 8 bytes, que da su tamaño en el proceso en ejecución, mientras que la.data
sección es tan grande como la suma de tamaños de las variables inicializadas. Por lo tanto,.bss
hace que los ejecutables sean más pequeños y más rápidos de cargar. De lo contrario, las variables podrían estar en el.data
segmento con inicialización explícita a ceros; el programa tendría dificultades para notar la diferencia. (En detalle, la dirección de los objetos en.bss
probablemente sería diferente de la dirección si estuviera en el.data
segmento).En el primer programa,
a
estaría en el.data
segmento yb
estaría en el.bss
segmento del ejecutable. Una vez que se carga el programa, la distinción se vuelve irrelevante. En tiempo de ejecución,b
ocupa20 * sizeof(int)
bytes.En el segundo programa,
var
se asigna espacio y la asignación enmain()
modifica ese espacio. Sucede que el espacio paravar
se describió en el.bss
segmento en lugar del.data
segmento, pero eso no afecta la forma en que el programa se comporta cuando se ejecuta.fuente
edata
). En términos prácticos, el .bss no existe en la memoria una vez que se completa la imagen del proceso; los datos puestos a cero son parte simple de la sección .data. Pero los detalles varían según el sistema operativo, etc.Del lenguaje ensamblador paso a paso: programación con Linux por Jeff Duntemann, con respecto a la sección .data :
y la sección .bss :
fuente
Bueno, primero que nada, esas variables en su ejemplo no están sin inicializar; C especifica que las variables estáticas que no se inicializan de otro modo se inicializan en 0.
Entonces, la razón de .bss es tener ejecutables más pequeños, lo que ahorra espacio y permite una carga más rápida del programa, ya que el cargador puede asignar un montón de ceros en lugar de tener que copiar los datos del disco.
Al ejecutar el programa, el cargador de programas cargará .data y .bss en la memoria. Escribe en objetos que residen en .data o .bss, por lo que solo van a la memoria, no se descargan en el binario del disco en ningún momento.
fuente
El System V ABI 4.1 (1997) (especificación AKA ELF) también contiene la respuesta:
dice que el nombre de la sección
.bss
está reservado y tiene efectos especiales, en particular no ocupa espacio de archivo , de ahí la ventaja.data
.La desventaja es, por supuesto, que todos los bytes deben configurarse
0
cuando el sistema operativo los coloca en la memoria, que es más restrictivo, pero es un caso de uso común, y funciona bien para las variables no inicializadas.La
SHT_NOBITS
documentación tipo sección repite esa afirmación:El estándar C no dice nada sobre las secciones, pero podemos verificar fácilmente dónde se almacena la variable en Linux con
objdump
yreadelf
, y concluir que los globales no inicializados se almacenan de hecho en el archivo.bss
. Vea, por ejemplo, esta respuesta: ¿Qué sucede con una variable declarada y no inicializada en C?fuente
El artículo de wikipedia .bss proporciona una buena explicación histórica, dado que el término es de mediados de la década de 1950 (yippee my birthday ;-).
En el pasado, todo era valioso, por lo que cualquier método para señalar un espacio vacío reservado era útil. Este ( .bss ) es el que se ha atascado.
Las secciones .data son para espacios que no están vacíos, sino que tendrán (sus) valores definidos ingresados en él.
fuente