Hacer.¿las variables inicializadas de la sección cero de bss ocupan espacio en el archivo elf?


Si entiendo correctamente, la sección .bss en archivos ELF se usa para asignar espacio para variables inicializadas cero. Nuestra cadena de herramientas produce archivos ELF, de ahí mi pregunta: ¿la sección .bss realmente tiene que contener todos esos ceros? Parece un desperdicio tan horrible de espacios que cuando, digamos, asignoun array global de diez megabytes, resulta en diez megabytes de ceros en el archivo ELF. ¿Qué estoy viendo mal aquí?

4 answers

Ha pasado algún tiempo desde que trabajé con ELF. Pero creo que todavía recuerdo estas cosas. No, no contiene físicamente esos ceros. Si observa un encabezado de programa de archivo ELF, verá que cada encabezado tiene dos números: Uno es el tamaño del archivo. Y otro es el tamaño que tiene la sección cuando se asigna en memoria virtual(readelf -l ./a.out):

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
  INTERP         0x000114 0x08048114 0x08048114 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00454 0x00454 R E 0x1000
  LOAD           0x000454 0x08049454 0x08049454 0x00104 0x61bac RW  0x1000
  DYNAMIC        0x000468 0x08049468 0x08049468 0x000d0 0x000d0 RW  0x4
  NOTE           0x000128 0x08048128 0x08048128 0x00020 0x00020 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

Los encabezados de tipo LOAD son los que se copian en la memoria virtual cuando se carga el archivo para su ejecución. Otras cabeceras contienen otra información, como las bibliotecas compartidas que se necesitan. Como puedes ver, FileSize y MemSiz difieren significativamente para el encabezado que contiene la sección bss (la segunda LOAD):

0x00104 (file-size) 0x61bac (mem-size)

Para este código de ejemplo:

int a[100000];
int main() { }

La especificación ELF dice que la parte de un segmento que el tamaño del mem es mayor que el tamaño del archivo se rellena con ceros en la memoria virtual. La asignación de segmento a sección de la segunda cabecera LOAD es así:

03     .ctors .dtors .jcr .dynamic .got .got.plt .data .bss

So hay algunas otras secciones allí también. Para C++ constructor / destructores. Lo mismo para Java. Luego contiene una copia de la sección .dynamic y otras cosas útiles para el enlace dinámico (creo que este es el lugar que contiene las bibliotecas compartidas necesarias entre otras cosas). Después de eso, la sección .data que contiene las variables globales inicializadas y las variables estáticas locales. Al final, aparece la sección .bss, que se llena con ceros en el tiempo de carga porque el tamaño del archivo no cubre se.

Por cierto, puede ver en qué sección de salida se colocará un símbolo en particular usando la opción enlazador -M. Para gcc, se usa -Wl,-M para pasar la opción al enlazador. El ejemplo anterior muestra que a se asigna dentro de .bss. Puede ayudarle a verificar que sus objetos no inicializados realmente terminan en .bss y no en otro lugar:

.bss            0x08049560    0x61aa0
 [many input .o files...]
 *(COMMON) 
 *fill*         0x08049568       0x18 00
 COMMON         0x08049580    0x61a80 /tmp/cc2GT6nS.o
                0x08049580                a
                0x080ab000                . = ALIGN ((. != 0x0)?0x4:0x1) 
                0x080ab000                . = ALIGN (0x4) 
                0x080ab000                . = ALIGN (0x4) 
                0x080ab000                _end = .

GCC mantiene las globales no inicializadas en una sección COMÚN por defecto, para compatibilidad con compiladores antiguos, que permiten tener globals definidos dos veces en un programa sin múltiples errores de definición. Use -fno-common para hacer que GCC use el .secciones bss para archivos objeto (no hace una diferencia para el ejecutable enlazado final, porque como ves va a entrar en a .sección de salida bss de todos modos. Esto es controlado por el script enlazador . Mostrar con ld -verbose). Pero eso no debería asustarte, es sólo un detalle interno. Ver la página de manual de gcc.

 66
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-04 14:55:42

La sección .bss en un archivo ELF se usa para datos estáticos que no se inicializan mediante programación, pero se garantiza que se pondrán a cero en tiempo de ejecución. Aquí hay un pequeño ejemplo que explicará la diferencia.

int main() {
    static int bss_test1[100];
    static int bss_test2[100] = {0};
    return 0;
}

En este caso bss_test1 se coloca en el .bss ya que no está inicializado. bss_test2 sin embargo se coloca en el segmento .data junto con un montón de ceros. El cargador de tiempo de ejecución básicamente asigna la cantidad de espacio reservado para el .bss y lo pone a cero antes cualquier código de userland comienza a ejecutarse.

Puedes ver la diferencia usando objdump, nm, o utilidades similares:

moozletoots$ objdump -t a.out | grep bss_test
08049780 l     O .bss   00000190              bss_test1.3
080494c0 l     O .data  00000190              bss_test2.4

Esta suele ser una de las primeras sorpresas con las que se encuentran los desarrolladores embebidos... nunca inicialice la estática a cero explícitamente. El cargador de tiempo de ejecución (por lo general) se encarga de eso. Tan pronto como inicialice algo explícitamente, le está diciendo al compilador/enlazador que incluya los datos en la imagen ejecutable.

 20
Author: D.Shawley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-04 14:28:53

Una sección .bss no se almacena en un archivo ejecutable. De las secciones más comunes(.text, .data, .bss), solo .text (código real) y .data (datos inicializados) están presentes en un archivo ELF.

 2
Author: mouviciel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-04 14:19:26

Eso es correcto, .bss no está presente físicamente en el archivo, más bien solo la información sobre su tamaño está presente para que el cargador dinámico asigne el .sección bss para el programa de aplicación. Como regla de pulgar solo CARGA, Segmento TLS obtiene la memoria para el programa de aplicación, rest se utilizan para cargador dinámico.

Acerca del archivo ejecutable estático, las secciones bss también tienen espacio en el execuatble

Aplicación incrustada donde no hay cargador esto es común.

Suman

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-27 17:38:19