2013-05-15 7 views
12

Wenn ich die Disassemblierung der Objektdatei durch den Leser überprüfe, sehe ich, dass die Daten und die BSS-Segmente die gleiche Offset-Adresse enthalten. Der Datenbereich enthält die initialisierten globalen und statischen Variablen. BSS enthält nicht-initialisierte globale und statische Variablen.Unterschied zwischen dem Datenabschnitt und dem BSS-Abschnitt in C

1 #include<stdio.h> 
    2 
    3 static void display(int i, int* ptr); 
    4 
    5 int main(){ 
    6 int x = 5; 
    7 int* xptr = &x; 
    8 printf("\n In main() program! \n"); 
    9 printf("\n x address : 0x%x x value : %d \n",(unsigned int)&x,x); 
10 printf("\n xptr points to : 0x%x xptr value : %d \n",(unsigned int)xptr,*xptr); 
11 display(x,xptr); 
12 return 0; 
13 } 
14 
15 void display(int y,int* yptr){ 
16 char var[7] = "ABCDEF"; 
17 printf("\n In display() function \n"); 
18 printf("\n y value : %d y address : 0x%x \n",y,(unsigned int)&y); 
19 printf("\n yptr points to : 0x%x yptr value : %d \n",(unsigned int)yptr,*yptr); 
20 } 

Ausgang:

SSS:~$ size a.out 
    text data  bss  dec  hex filename 
    1311  260  8 1579  62b a.out 

Hier im obigen Programm, das ich habe keine un-intialised Daten, sondern die BSS 8 Byte belegt hat. Warum belegt es 8 Bytes? Auch , wenn ich die Objektdatei zerlegen,

EDITED:

[ 3] .data    PROGBITS  00000000 000110 000000 00 WA 0 0 4 
    [ 4] .bss    NOBITS   00000000 000110 000000 00 WA 0 0 4 
    [ 5] .rodata   PROGBITS  00000000 000110 0000cf 00 A 0 0 4 

Daten, Rodata und bss die gleiche Adresse versetzt hat. Bedeutet das, dass sich die Rodata, Daten und Bss auf die gleiche Adresse beziehen? Enthalten der Datenabschnitt, der Rodata-Abschnitt und der BSS-Abschnitt die Datenwerte an derselben Adresse, wenn ja, wie unterscheidet man den Datenabschnitt, den BSS-Abschnitt und den Rodata-Abschnitt?

+3

In C werden Zeiger mit% p gedruckt und ein Argument in '(void *)' umgewandelt. – Jens

+1

"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. –

Antwort

31

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().

+0

Ich würde das Beispiel 'static int g_myGlobal;' nicht initialisieren, um sicherzustellen, dass es auf '.bss' geht - und es sollte im Code verwendet werden, da der Compiler sonst optimieren könnte, indem er es komplett entfernt. –

+0

@BasileStarynkevitch Firing meine Linux-VM gerade jetzt .... –

+0

Wahrscheinlicher, die .bss kommt von einigen internen Variablen in den enthaltenen Standard-Bibliotheken, wahrscheinlich von printf. Deshalb sind printf et al nicht threadsicher. – Lundin

1

Per Definition nimmt das Segment bss Speicherplatz ein (wenn das Programm startet), benötigt aber keinen Speicherplatz. Sie müssen einige Variablen zu definieren, um sie gefüllt zu bekommen, so versuchen

int bigvar_in_bss[16300]; 
int var_in_data[5] = {1,2,3,4,5}; 

Ihr einfaches Programm, keine Daten in .bss haben konnten und gemeinsam genutzte Bibliotheken (wie libc.so) können „ihre eigenen .bss

Dateioffsets und Speicheradressen sind nicht leicht miteinander zu verknüpfen.

mehr über die ELF Spezifikation lesen, auch (die Adresse angezeigt werden würde zB cat /proc/self/maps Raum der laufenden cat Prozess, den Befehl) /proc/ verwenden. Lesen Sie auch proc(5)

Verwandte Themen