Was ich weiß ist, dass globale und statische Variablen im .data
Segment gespeichert sind und nicht initialisierte Daten im .bss
Segment sind. Was ich nicht verstehe ist, warum wir ein dediziertes Segment für nicht initialisierte Variablen haben? Wenn einer nicht initialisierten Variablen zur Laufzeit ein Wert zugewiesen wurde, ist die Variable dann nur noch im .bss
Segment vorhanden?
Im folgenden Programm a
befindet sich im .data
Segment und b
befindet sich im .bss
Segment; Ist das korrekt? Bitte korrigieren Sie mich, wenn mein Verständnis falsch ist.
#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 ()
{
;
}
Beachten Sie auch das folgende Programm:
#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
Wer bin ich
quelle
quelle
Antworten:
Der Grund ist, die Programmgröße zu reduzieren. Stellen Sie sich vor, Ihr C-Programm läuft auf einem eingebetteten System, auf dem der Code und alle Konstanten in einem echten ROM (Flash-Speicher) gespeichert sind. In solchen Systemen muss ein anfängliches "Kopieren" ausgeführt werden, um alle statischen Speicherdauerobjekte festzulegen, bevor main () aufgerufen wird. Es wird normalerweise wie folgt aussehen:
Wobei .data und .bss im RAM gespeichert sind, init_value jedoch im ROM. Wenn es ein Segment gewesen war, musste das ROM mit vielen Nullen gefüllt werden, was die ROM-Größe signifikant erhöhte.
RAM-basierte ausführbare Dateien funktionieren ähnlich, obwohl sie natürlich kein echtes ROM haben.
Außerdem ist memset wahrscheinlich ein sehr effizienter Inline-Assembler, was bedeutet, dass das Herunterfahren des Starts schneller ausgeführt werden kann.
quelle
Das
.bss
Segment ist eine Optimierung. Das gesamte.bss
Segment wird durch eine einzelne Zahl beschrieben, wahrscheinlich 4 Byte oder 8 Byte, die seine Größe im laufenden Prozess.data
angibt , während der Abschnitt so groß ist wie die Summe der Größen der initialisierten Variablen. Dadurch werden die.bss
ausführbaren Dateien kleiner und können schneller geladen werden. Andernfalls könnten sich die Variablen im.data
Segment mit expliziter Initialisierung auf Nullen befinden. Das Programm würde es schwer haben, den Unterschied zu erkennen. (Im Detail würde sich die Adresse der Objekte in.bss
wahrscheinlich von der Adresse unterscheiden, wenn sie sich im.data
Segment befindet.)Im ersten Programm
a
wäre im.data
Segment undb
wäre im.bss
Segment der ausführbaren Datei. Sobald das Programm geladen ist, spielt die Unterscheidung keine Rolle mehr. Zur Laufzeitb
nimmt20 * sizeof(int)
Bytes.Im zweiten Programm
var
wird Speicherplatz zugewiesen, und die Zuweisung inmain()
ändert diesen Speicherplatz. Es kommt also vor, dass der Speicherplatz fürvar
im.bss
Segment und nicht im.data
Segment beschrieben wurde, dies hat jedoch keinen Einfluss auf das Verhalten des Programms beim Ausführen.quelle
edata
). In der Praxis ist die .bss-Datei nach Abschluss des Prozessabbilds nicht mehr im Speicher vorhanden. Die auf Null gesetzten Daten sind ein einfacher Teil des Abschnitts .data. Aber die Details variieren je nach Betrieb usw.Von Assembly Language Step-by-Step: Programmieren mit Linux von Jeff Duntemanns in Bezug auf dem .data Abschnitt:
und der Abschnitt .bss :
quelle
Zunächst einmal sind diese Variablen in Ihrem Beispiel nicht nicht initialisiert. C gibt an, dass statische Variablen, die nicht anderweitig initialisiert wurden, auf 0 initialisiert werden.
Der Grund für .bss sind kleinere ausführbare Dateien, die Platz sparen und ein schnelleres Laden des Programms ermöglichen, da der Loader nur eine Reihe von Nullen zuweisen kann, anstatt die Daten von der Festplatte kopieren zu müssen.
Beim Ausführen des Programms lädt der Programmlader .data und .bss in den Speicher. Schreibvorgänge in Objekten, die sich in .data oder .bss befinden, werden daher nur in den Speicher verschoben. Sie werden zu keinem Zeitpunkt in die Binärdatei auf der Festplatte geschrieben.
quelle
Das System V ABI 4.1 (1997) (AKA ELF-Spezifikation) enthält auch die Antwort:
sagt, dass der Abschnittsname
.bss
reserviert ist und Spezialeffekte hat, insbesondere belegt er keinen Dateibereich , also den Vorteil gegenüber.data
.Der Nachteil ist natürlich, dass alle Bytes auf gesetzt werden müssen,
0
wenn das Betriebssystem sie in den Speicher stellt. Dies ist restriktiver, aber ein häufiger Anwendungsfall und funktioniert gut für nicht initialisierte Variablen.In der
SHT_NOBITS
Dokumentation zum Abschnittstyp wird diese Bestätigung wiederholt:Der C-Standard sagt nichts über Abschnitte aus, aber wir können leicht überprüfen, wo die Variable unter Linux mit
objdump
und gespeichert istreadelf
, und daraus schließen, dass nicht initialisierte Globals tatsächlich in der Datei gespeichert sind.bss
. Siehe zum Beispiel diese Antwort: Was passiert mit einer deklarierten, nicht initialisierten Variablen in C?quelle
Der Wikipedia-Artikel .bss bietet eine schöne historische Erklärung, da der Begriff aus der Mitte der 1950er Jahre stammt (yippee mein Geburtstag ;-).
Früher war jedes Bit wertvoll, daher war jede Methode zur Signalisierung des reservierten leeren Raums nützlich. Dies ( .bss ) ist derjenige, der stecken geblieben ist.
.data- Abschnitte sind für Leerzeichen gedacht , die nicht leer sind, sondern in die (Ihre) definierten Werte eingegeben wurden.
quelle