Warum ist das .bss-Segment erforderlich?

Lesezeit: 8 Minuten

Benutzeravatar von Whoami
Wer bin ich

Was ich weiß ist, dass globale und statische Variablen in der gespeichert werden .data Segment und nicht initialisierte Daten befinden sich im .bss Segment. 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 wird, existiert die Variable noch in der .bss nur Segment?

Im folgenden Programm a ist in dem .data Segment und b ist in dem .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 ?** */
}

  • Sie können BSS lesen als Sparen Sie besser Platz.

    – smWikipedia

    30. März 2018 um 1:28 Uhr


Der Grund ist, die Programmgröße zu reduzieren. Stellen Sie sich vor, Ihr C-Programm läuft auf einem eingebetteten System, wo der Code und alle Konstanten im True-ROM (Flash-Speicher) gespeichert sind. In solchen Systemen muss ein anfängliches “Herunterkopieren” ausgeführt werden, um alle statischen Speicherdauer-Objekte zu setzen, bevor main() aufgerufen wird. Es wird normalerweise wie dieses Pseudo aussehen:

for(i=0; i<all_explicitly_initialized_objects; i++)
{
  .data[i] = init_value[i];
}

memset(.bss, 
       0, 
       all_implicitly_initialized_objects);

Wobei .data und .bss im RAM gespeichert werden, aber init_value im ROM gespeichert wird. Wenn es ein Segment gewesen wäre, musste das ROM mit vielen Nullen aufgefüllt werden, was die ROM-Größe erheblich 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 Herunterkopieren beim Start schneller ausgeführt werden kann.

  • Zur Verdeutlichung: Der einzige Unterschied zwischen .data und .bss besteht darin, dass beim Start das “Herunterkopieren” sequentiell und damit schneller ausgeführt werden kann. Wenn es nicht in die beiden Segmente aufgeteilt wäre, müsste die Initialisierung die RAM-Spots überspringen, die zu den nicht initialisierten Variablen gehören, was Zeit verschwendet.

    – CL22

    15. Mai 2013 um 16:29 Uhr

  • Vielen Dank für Ihre Erklärung zum Startvorgang, aber was passiert, wenn eine Variable in .bss wird initialisiert ? Überschreibt es die 0 und bleibt drin .bss ? Wird es aus .bss entfernt und hineingeschrieben .data (wodurch die verkürzt wird .bss Abschnitt) ?

    – Axel B

    16. April 2021 um 11:15 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Das .bss Segment ist eine Optimierung. Das ganze .bss Segment wird durch eine einzelne Zahl beschrieben, wahrscheinlich 4 Bytes oder 8 Bytes, die seine Größe im laufenden Prozess angibt, während das .data Abschnitt ist so groß wie die Summe der Größen der initialisierten Variablen. Und so kam es dass der .bss macht die ausführbaren Dateien kleiner und schneller zu laden. Andernfalls könnten die Variablen in der .data Segment mit expliziter Initialisierung auf Nullen; das Programm würde sich schwer tun, den Unterschied zu erkennen. (Im Detail die Adresse der Objekte in .bss wäre wahrscheinlich anders als die Adresse, wenn es in der wäre .data Segment.)

Im ersten Programm a wäre im .data Segment und b wäre im .bss Segment der ausführbaren Datei. Sobald das Programm geladen ist, wird die Unterscheidung unwesentlich. Zur Laufzeit, b besetzt 20 * sizeof(int) Byte.

Im zweiten Programm var wird Platz zugewiesen und die Zuweisung erfolgt main() modifiziert diesen Raum. Es kommt also vor, dass der Platz für var wurde in beschrieben .bss Segment statt der .data Segment, aber das hat keinen Einfluss darauf, wie sich das Programm beim Ausführen verhält.

  • Stellen Sie sich beispielsweise vor, viele nicht initialisierte Puffer mit einer Länge von 4096 Byte zu haben. Möchten Sie, dass all diese 4k-Puffer zur Größe der Binärdatei beitragen? Das wäre viel Platzverschwendung.

    – Jeff Mercado

    2. März 2012 um 15:02 Uhr

  • @jonathen killer: Warum wird das gesamte BSS-Segment durch eine einzelne Zahl beschrieben?

    – Suraj Jain

    16. August 2016 um 16:46 Uhr

  • @JonathanLeffler Ich meine, alle mit Null initialisierten statischen Variablen gehen in bss . Sollte sein Wert also nicht nur Null sein? Und warum wird ihnen im Abschnitt .data kein Platz gegeben, wie kann dies zu einer Verlangsamung führen?

    – Suraj Jain

    16. August 2016 um 16:58 Uhr

  • @SurajJain: Die gespeicherte Zahl ist die Anzahl der mit Nullen aufzufüllenden Bytes. Solange es keine solchen nicht initialisierten Variablen gibt, ist die Länge des bss-Abschnitts nicht null, obwohl alle Bytes im bss-Abschnitt null sind, sobald das Programm geladen ist.

    – Jonathan Leffler

    16. August 2016 um 17:01 Uhr

  • Der Abschnitt .bss in der ausführbaren Datei ist einfach eine Zahl. Der .bss-Abschnitt im In-Memory-Prozessabbild ist normalerweise Speicher, der an den .data-Abschnitt angrenzt, und häufig wird der Laufzeit-.data-Abschnitt mit dem .bss-Abschnitt kombiniert; im Laufzeitspeicher wird nicht unterschieden. Manchmal finden Sie heraus, wo das bss begann (edata). In der Praxis existiert die .bss nicht mehr im Speicher, sobald das Prozessabbild fertig ist; Die genullten Daten sind ein einfacher Teil des .data-Abschnitts. Aber die Details variieren je nach Betriebssystem usw.

    – Jonathan Leffler

    16. August 2016 um 18:42 Uhr

From Assembler Language Step-by-Step: Programming with Linux von Jeff Duntemann, bezüglich der .Daten Sektion:

Das .Daten Abschnitt enthält Datendefinitionen initialisierter Datenelemente. Initialisierte Daten sind Daten, die einen Wert haben, bevor das Programm zu laufen beginnt. Diese Werte sind Teil der ausführbaren Datei. Sie werden in den Speicher geladen, wenn die ausführbare Datei zur Ausführung in den Speicher geladen wird.

Beachten Sie beim Abschnitt .data unbedingt, dass je mehr initialisierte Datenelemente Sie definieren, desto größer die ausführbare Datei wird und desto länger dauert es, sie von der Festplatte in den Arbeitsspeicher zu laden, wenn Sie sie ausführen.

und die .bss Sektion:

Nicht alle Datenelemente müssen Werte haben, bevor das Programm zu laufen beginnt. Wenn Sie beispielsweise Daten von einer Festplattendatei lesen, müssen Sie einen Ort haben, an den die Daten gehen können, nachdem sie von der Festplatte eintreffen. Solche Datenpuffer sind in der definiert .bss Abschnitt Ihres Programms. Sie reservieren einige Bytes für einen Puffer und geben dem Puffer einen Namen, aber Sie sagen nicht, welche Werte im Puffer vorhanden sein sollen.

Es gibt einen entscheidenden Unterschied zwischen Datenelementen, die im Abschnitt .data definiert sind, und Datenelementen, die im Abschnitt .bss definiert sind: Datenelemente im Abschnitt .data erhöhen die Größe Ihrer ausführbaren Datei. Datenelemente im .bss-Abschnitt nicht. Ein Puffer, der 16.000 Bytes (oder mehr, manchmal viel mehr) belegt, kann in .bss definiert werden und fast nichts (etwa 50 Bytes für die Beschreibung) zur Größe der ausführbaren Datei hinzufügen.

  • TLDR; verwenden .data für ständig und .bss für Zeiger

    – Testen_22

    27. September um 3:13

Nun, zunächst einmal sind diese Variablen in Ihrem Beispiel nicht nicht initialisiert; C gibt an, dass nicht anderweitig initialisierte statische Variablen auf 0 initialisiert werden.

Der Grund für .bss besteht also darin, kleinere ausführbare Dateien zu haben, Platz zu sparen und ein schnelleres Laden des Programms zu ermöglichen, da der Lader einfach ein paar 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 Objekte, die sich in .data oder .bss befinden, gehen daher nur in den Speicher, sie werden zu keinem Zeitpunkt in die Binärdatei auf der Festplatte geleert.

Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

Das System V ABI 4.1 (1997) (AKA ELF-Spezifikation) enthält auch die Antwort:

.bss Dieser Abschnitt enthält nicht initialisierte Daten, die zum Speicherabbild des Programms beitragen. Per Definition initialisiert das System die Daten mit Nullen, wenn das Programm zu laufen beginnt. Der Abschnitt belegt keinen Dateibereich, wie durch den Abschnittstyp angegeben, SHT_NOBITS.

sagt, dass der Abschnittsname .bss vorbehalten ist und besondere Wirkungen hat, insbesondere es belegt keinen Speicherplatzalso der Vorteil gegenüber .data.

Der Nachteil ist natürlich, dass alle Bytes gesetzt werden müssen 0 wenn das Betriebssystem sie in den Speicher legt, was restriktiver, aber ein häufiger Anwendungsfall ist, und funktioniert gut für nicht initialisierte Variablen.

Das SHT_NOBITS Abschnittstyp-Dokumentation wiederholt diese Bestätigung:

sh_size Dieses Mitglied gibt die Größe des Abschnitts in Byte an. Es sei denn, der Abschnittstyp ist SHT_NOBITSbesetzt die Sektion sh_size
Bytes in der Datei. Ein Abschnitt des Typs SHT_NOBITS kann eine Größe ungleich Null haben, belegt aber keinen Platz in der Datei.

Der C-Standard sagt nichts über Abschnitte aus, aber wir können leicht überprüfen, wo die Variable in Linux gespeichert ist objdump und readelfund schlussfolgern, dass nicht initialisierte Globals tatsächlich in der gespeichert sind .bss. Siehe zum Beispiel diese Antwort: Was passiert mit einer deklarierten, nicht initialisierten Variablen in C?

Benutzeravatar von Philip Oakley
Philipp Oakley

Der Wikipedia-Artikel .bss liefert eine schöne historische Erklärung, wenn man bedenkt, dass der Begriff aus der Mitte der 1950er Jahre stammt (yippie, mein Geburtstag;-).

Früher war jedes Bit kostbar, daher war jede Methode zum Signalisieren von reserviertem Leerraum nützlich. Dies (.bss) ist derjenige, der hängen geblieben ist.

.Daten Abschnitte sind für Raum, der nicht leer ist, sondern in den (Ihre) definierten Werte eingegeben werden.

1424680cookie-checkWarum ist das .bss-Segment erforderlich?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy