Der .bss
Abschnitt wird garantiert nur Nullen sein, wenn das Programm in den Speicher geladen wird. Daher werden alle globalen Daten, die nicht initialisiert oder auf Null initialisiert sind, in den Abschnitt .bss
gestellt. Zum Beispiel:.
static int g_myGlobal = 0; // <--- in .bss section
Das schöne daran ist, die .bss
Abschnittsdaten nicht in der ELF-Datei auf der Festplatte aufgenommen werden muss (dh es gibt nicht eine ganze Region von Nullen in der Datei für der .bss
Abschnitt). Stattdessen weiß der Loader aus den Abschnittsüberschriften, wie viel für den Abschnitt .bss
zu reservieren ist, und setzt ihn einfach auf Null, bevor er die Kontrolle an Ihr Programm übergibt.
Beachten Sie die readelf
Ausgabe:
[ 3] .data PROGBITS 00000000 000110 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000110 000000 00 WA 0 0 4
.data
als PROGBITS
markiert. Das heißt, es gibt "Bits" von Programmdaten in der ELF-Datei, die der Lader für Sie in den Speicher einlesen muss..bss
auf der anderen Seite ist markiert NOBITS
, was bedeutet, dass nichts in der Datei, die als Teil der Ladung in den Speicher gelesen werden muss.
Beispiel:
// bss.c
static int g_myGlobal = 0;
int main(int argc, char** argv)
{
return 0;
}
Kompilieren mit $ gcc -m32 -Xlinker -Map=bss.map -o bss bss.c
Schauen Sie sich die Abschnittsüberschriften mit $ readelf -S bss
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
:
[13] .text PROGBITS 080482d0 0002d0 000174 00 AX 0 0 16
:
[24] .data PROGBITS 0804964c 00064c 000004 00 WA 0 0 4
[25] .bss NOBITS 08049650 000650 000008 00 WA 0 0 4
:
Jetzt suchen wir für unsere Variable in der Symboltabelle : $ readelf -s bss | grep g_myGlobal
37: 08049654 4 OBJECT LOCAL DEFAULT 25 g_myGlobal
Beachten Sie, dass g_myGlobal
ein Teil des Abschnitts gezeigt werden, ist 25. Wenn wir in den Abschnittsüberschriften zurückblicken, sehen wir, dass 25 .bss
ist.
Ihre eigentliche Frage zu beantworten:
Hier im obigen Programm, das ich habe keine un-intialised Daten, sondern die BSS 8 Byte belegt haben. Warum belegt es 8 Bytes?
mit meinem Beispiel zu bleiben, suchen wir für jedes Symbol in Abschnitt 25:
$ readelf -s bss | grep 25
9: 0804825c 0 SECTION LOCAL DEFAULT 9
25: 08049650 0 SECTION LOCAL DEFAULT 25
32: 08049650 1 OBJECT LOCAL DEFAULT 25 completed.5745
37: 08049654 4 OBJECT LOCAL DEFAULT 25 g_myGlobal
Die dritte Spalte die Größe ist. Wir sehen unser erwartetes 4-Byte g_myGlobal
, und dieses 1-Byte completed.5745
. Dies ist wahrscheinlich eine Funktion-statische Variable von irgendwo in der C-Laufzeit-Initialisierung - erinnern Sie sich, eine Menge "Zeug" passiert, bevor main()
jemals aufgerufen wird.
4 + 1 = 5 Bytes. Wenn wir uns jedoch die Abschnittsüberschrift .bss
ansehen, sehen wir, dass die letzte Spalte 4 ist. Das ist die Abschnittsausrichtung, was bedeutet, dass dieser Abschnitt beim Laden immer ein Vielfaches von 4 Bytes ist. Das nächste Vielfache von 5 ist 8, und deshalb ist der .bss
Abschnitt 8 Bytes.
Zusätzlich Wir können vom Linker erzeugt auf der Map-Datei, um zu sehen, welche Objektdateien wurden, wo in der endgültigen Ausgabe platziert.
.bss 0x0000000008049650 0x8
*(.dynbss)
.dynbss 0x0000000000000000 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o
*(.bss .bss.* .gnu.linkonce.b.*)
.bss 0x0000000008049650 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o
.bss 0x0000000008049650 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crti.o
.bss 0x0000000008049650 0x1 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtbegin.o
.bss 0x0000000008049654 0x4 /tmp/ccKF6q1g.o
.bss 0x0000000008049658 0x0 /usr/lib/libc_nonshared.a(elf-init.oS)
.bss 0x0000000008049658 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtend.o
.bss 0x0000000008049658 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crtn.o
Auch hier ist die dritte Spalte die Größe.
Wir sehen 4 Bytes .bss
kam von /tmp/ccKF6q1g.o
. In diesem trivialen Beispiel wissen wir, dass die temporäre Objektdatei aus der Kompilierung unserer bss.c-Datei stammt. Das andere 1 Byte kam von crtbegin.o
, die Teil der C-Laufzeit ist.
Schließlich, da wir wissen, dass das 1 Byte Geheimnis bss Variable aus crtbegin.o
ist, und es ist completed.xxxx
genannt, es ist richtiger Name ist completed
und es ist wahrscheinlich eine statische innerhalb irgendeiner Funktion.Mit Blick auf crtstuff.c
finden wir den Schuldigen: a static _Bool completed
innerhalb von __do_global_dtors_aux()
.
In C werden Zeiger mit% p gedruckt und ein Argument in '(void *)' umgewandelt. – Jens
"Ich habe keine uninitialisierten Daten, aber das BSS hat 8 Bytes belegt" - die Bibliotheken, die verlinkt werden, haben auch Daten. In der Tat, da Ihr Programm nur lokale Variablen und Literale hat, erwarte ich, dass alle "data" - und "bss" -Abschnitte aus Bibliotheken stammen. –