Domanda

Se ho capito bene, la sezione .bss nei file ELF viene utilizzata per allocare spazio per variabili a zero inizializzazione. La nostra catena di strumenti produce file ELF, quindi la mia domanda: la sezione .bss deve effettivamente contenere tutti quegli zero? Sembra un terribile spreco di spazi che quando, diciamo, allocare un array globale da dieci megabyte, si ottengono dieci megabyte di zero nel file ELF. Cosa vedo di sbagliato qui?

È stato utile?

Soluzione

È da un po 'di tempo che non lavoro con ELF. Ma penso di ricordare ancora questa roba. No, non contiene fisicamente quegli zeri. Se guardi un'intestazione del programma di file ELF, vedrai che ogni intestazione ha due numeri: uno è la dimensione nel file. E un'altra è la dimensione della sezione quando allocata nella memoria virtuale ( 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

Le intestazioni di tipo LOAD sono quelle che vengono copiate nella memoria virtuale quando il file viene caricato per l'esecuzione. Altre intestazioni contengono altre informazioni, come le librerie condivise necessarie. Come vedi, FileSize e MemSiz differiscono in modo significativo per l'intestazione che contiene la sezione bss (la seconda LOAD uno):

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

Per questo codice di esempio:

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

La specifica ELF afferma che la parte di un segmento in cui la dimensione del mem è maggiore della dimensione del file è appena compilata con zeri nella memoria virtuale. La mappatura da segmento a sezione della seconda intestazione LOAD è la seguente:

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

Quindi ci sono anche altre sezioni. Per costruttore / distruttore C ++. La stessa cosa per Java. Quindi contiene una copia della sezione .dynamic e altre cose utili per il collegamento dinamico (credo che questo sia il posto che contiene le librerie condivise necessarie tra le altre cose). Successivamente la sezione .data che contiene i globuli inizializzati e le variabili statiche locali. Alla fine, viene visualizzata la sezione .bss , che viene riempita da zeri al momento del caricamento perché la dimensione del file non lo copre.

A proposito, puoi vedere in quale sezione di output verrà posizionato un particolare simbolo usando l'opzione del linker -M . Per gcc, usi -Wl, -M per passare l'opzione al linker. L'esempio sopra mostra che a è allocato in .bss . Può aiutarti a verificare che i tuoi oggetti non inizializzati finiscano davvero in .bss e non altrove:

.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 i globi non inizializzati in una sezione COMUNE per impostazione predefinita, per compatibilità con i vecchi compilatori, che consentono di definire i globi due volte in un programma senza errori di definizione multipla. Usa -fno-common per fare in modo che GCC usi le sezioni .bss per i file oggetto (non fa differenza per l'eseguibile collegato finale, perché come vedi entrerà comunque in una sezione di output .bss Questo è controllato dallo script linker . Visualizzalo con ld -verbose ). Ma questo non dovrebbe spaventarti, è solo un dettaglio interno. Vedi la manpage di gcc.

Altri suggerimenti

La sezione .bss in un file ELF viene utilizzata per i dati statici che non è inizializzato a livello di codice ma è garantito che sia impostato su zero in fase di esecuzione. Ecco un piccolo esempio che spiegherà la differenza.

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

In questo caso bss_test1 viene inserito nel .bss poiché non è inizializzato. bss_test2 viene tuttavia inserito nel segmento .data insieme a un gruppo di zeri. Il caricatore di runtime sostanzialmente alloca la quantità di spazio riservato per il .bss e lo azzera prima che inizi a eseguire qualsiasi codice userland.

Puoi vedere la differenza usando objdump , nm o utilità simili:

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

Questa è di solito una delle prime sorprese in cui si imbattono gli sviluppatori embedded ... non inizializzano mai la statica a zero in modo esplicito. Il caricatore di runtime (di solito) se ne occupa. Non appena inizializzi qualcosa in modo esplicito, stai dicendo al compilatore / linker di includere i dati nell'immagine eseguibile.

Una sezione .bss non è memorizzata in un file eseguibile. Delle sezioni più comuni ( .text , .data , .bss ), solo .text (codice effettivo ) e .data (dati inizializzati) sono presenti in un file ELF.

È corretto, .bss non è presente fisicamente nel file, ma solo le informazioni sulla sua dimensione sono presenti per il caricatore dinamico per allocare la sezione .bss per il programma applicativo. Poiché la regola del pollice è solo LOAD, il segmento TLS ottiene la memoria per il programma applicativo, gli altri vengono utilizzati per il caricatore dinamico.

Sul file eseguibile statico, anche nelle sezioni bss viene dato spazio nell'eseguibile

Applicazione incorporata in cui non è presente alcun caricatore, questo è comune.

Suman

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top