Autor Thema: Globale, Initialisierte Variable in .bss!?  (Gelesen 9876 mal)

RedEagle

  • Beiträge: 244
    • Profil anzeigen
    • RedEagle-OperatingSystem - Projekt
Gespeichert
« am: 19. January 2010, 20:08 »
Hi
Ich habe ein Problem mit Globalen Variable

paging.cpp
//...

namespace paging
{
 DWORD PagingSpinLock = 0x00000000;

//...

Der Linker packt diese Variable in den .bss-Bereich:
mapfile
...
 .bss           0x0000000000a14818        0xc mem/paging.o
                0x0000000000a14818                paging::PagingSpinLock
...

Der Grund dafür: Der Compiler lässt sie in den .bss-Bereich packen:
objdump -x paging.o
...

00000000 g     O .bss   00000004 _ZN6paging14PagingSpinLockE

...

Warum wird diese Variable in den .bss-Teil gepackt?
Alle Globalen Variablen die mit 0 oder false initialisiert wurden befinden sich im .bss-Segment; die mit einem Wert ungleich 0 initialisiert wurde hingegen nicht.


Der Compiler kann doch nicht einfach davon ausgehen das diese Speicherbereiche =0 sind :? - Die Tatsache das sie !=0 sind sorgt nämlich für wirre Abstürze...

Meine Compiler-settings:
COMPILERSETTINGS="-I $HEADERS -DCPU=586 -m32 -c -Os -nostdlib -fno-builtin -fno-rtti -fno-exceptions"Compiler: g++ 4.4.1

Ich arbeite bereist seit einigen Jahren mit diesen Settings - aber bisher sind mir nie solche Probleme aufgefallen...
...erst seit wenigen Tagen

Meine Frage:
Was jetzt? Wie bringe ich den Compiler dazu initialisierte Variablen nicht in den .bss-Block zu packen?
Warum geht der überhaupt davon aus, dass das bss-segment mit Nullen gefüllt ist? Überall wird doch explizit erwähnt dass dieser Speicherbereich keine definierten Werte enthält...

Nochmal die g++-version im detail:
$ g++ -v
Using built-in specs.
Target: i586-suse-linux
Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --libexecdir=/usr/lib
--enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.4
--enable-ssp --disable-libssp --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj
--disable-libmudflap --with-slibdir=/lib --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch
--enable-version-specific-runtime-libs --program-suffix=-4.4 --enable-linux-futex --without-system-libunwind --with-arch-32=i586
--with-tune=generic --build=i586-suse-linux
Thread model: posix
gcc version 4.4.1 [gcc-4_4-branch revision 150839] (SUSE Linux)
« Letzte Änderung: 18. December 2010, 16:44 von RedEagle »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 19. January 2010, 20:25 »
Zitat
Warum geht der überhaupt davon aus, dass das bss-segment mit Nullen gefüllt ist? Überall wird doch explizit erwähnt dass dieser Speicherbereich keine definierten Werte enthält...

Sie enthalt zwar nicht-initialisierte Daten, aber der Bereich wird initialisiert. Siehe ELF-Spezifikation, nach der sich dein Compiler richtet:
Zitat von: System V ABI
This section holds uninitialized data that contribute to the program’s memory image. By definition, the system initializes the data with zeros when the program begins to run.

Zitat
Was jetzt? Wie bringe ich den Compiler dazu initialisierte Variablen nicht in den .bss-Block zu packen?
Ich hab sowas nie ausprobiert, aber gcc --help rät zu -fno-zero-initialized-in-bss

Oder du sagst dem Linker, dass er die .bss-Sektion nach .data schieben soll.

Oder du initialisierst .bss beim Start einfach auf 0, so wie es dein Compiler erwartet.
« Letzte Änderung: 20. January 2010, 12:10 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

RedEagle

  • Beiträge: 244
    • Profil anzeigen
    • RedEagle-OperatingSystem - Projekt
Gespeichert
« Antwort #2 am: 19. January 2010, 20:40 »
.bss nach .data schieben wollte/will ich nicht.
Und das .bss Segment mit Nullen füllen geht nicht, da der Kernel in einer Binärdatei liegt - ich also nicht weiß wie groß das .bss-Segment ist (Wobei es bestimmt ne Möglichkeit gibt an die Größe zu kommen)

Aber das  -fno-zero-initialized-in-bss - flag sieht gut aus
Funktioniert bestens :) - vielen Dank

Bleibt die Frage warum mir das erst nach 5 Jahren aufgefallen ist - ich will nicht wissen wie viel Stunden debuggen ich mir dadurch hätte sparen können  :mrgreen:

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #3 am: 20. January 2010, 11:58 »
Und das .bss Segment mit Nullen füllen geht nicht, da der Kernel in einer Binärdatei liegt - ich also nicht weiß wie groß das .bss-Segment ist (Wobei es bestimmt ne Möglichkeit gibt an die Größe zu kommen)
Zwei Symbole im Linkerskript, dann hast du Beginn & Ende des bss. Das ist wirklich trivial.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

Greenhorn

  • Beiträge: 1
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 17. December 2010, 16:54 »
Zitat
Warum wird diese Variable in den .bss-Teil gepackt?
Die meisten Compiler packen uninitialisierte statische/globale Variablen in die _BSS Sektion, um das erzeugte Image (PE/ELF) auf Größe zu optimieren.
Statische/globale Variablen mit einem Wert müssen in die _DATA Sektion gepackt werden und belegen daher auch Bytes im Image auf der Festplatte oder anderem Speichermedium.
Die _BSS Sektion dagegen wird vom OS Loader im RAM angelegt und benötigt nur die Angabe der Größe der Sektion.
Da die gängigen Betriebssysteme den Speicher vor dem Laden "ausnullen", landen meist auch die mit dem Wert Null initialisierten Variablen in der _BSS Sektion.
Aber das alles ist letztendlich Compilerspezifisch wo was in welcher Sektion landet.

Gruß
Greenhorn

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 17. December 2010, 18:11 »
Hallo,


man ist der Thread schon staubig, tss.....


Da die gängigen Betriebssysteme den Speicher vor dem Laden "ausnullen"
Das steht im C-Standard extra so drin (wurde hier im Thread auch schon angedeutet). Das tun also nicht nur die "gängigen" Betriebssysteme sondern alle Betriebssysteme die mit spezifikationskonformen ELF-Dateien umgehen können (in allen anderen ausführbaren/linkbaren Dateiformaten ist das ähnlich geregelt).

landen meist auch die mit dem Wert Null initialisierten Variablen in der _BSS Sektion. Aber das alles ist letztendlich Compilerspezifisch wo was in welcher Sektion landet.
Eben damit 0-Bytes keinen Platz belegen wurde das wohl im C-Standard so festgeschrieben und daher ist das (zumindest bei C-Compilern) nicht compilerspezifisch. Alle anderen Programmiersprachen haben ähnliche Regeln (zumindest soweit mir bekannt) und nutzen daher die selben Features in den ausführbaren/linkbaren Dateiformaten.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 17. December 2010, 19:32 »
Dass der C-Standard eine .bss-Sektion kennt, wäre mir neu. Er legt halt die Semantik von einer Variablen mit statischer Gültigkeit und ohne Initialisierung fest, aber wie das dann konkret umgesetzt wird, ist ein Implementierungsdetail.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 18. December 2010, 09:10 »
Hallo,


Dass der C-Standard eine .bss-Sektion kennt, wäre mir neu.
Das hast Du natürlich recht.
Das statische Variablen die mit 0 vorbelegt sind (was bei C auch auf die statischen Variablen zutrifft die nicht explizit vorbelegt sind) in .bss kommen und die anderen in .data ist eben eine konkrete Implementierung dieser Vorgabe. Man könnte das mit der Platzersparnis in der ausführbaren Datei sicher auch anders implementieren aber zumindest ich persönlich hab da bis jetzt noch keine Alternativen gesehen. Die Variante mit .data und .bss hat sich einfach so als Defacto-Standard etabliert. Obwohl wimre manche Compiler davon wieder etwas abkommen um zusammengehörige Variablen (die aber unterschiedlich vorbelegt sind) auch in einen gemeinsamen Speicherbereich zu legen, wegen Cache-Lokalität usw.


Grüße
Erik

PS.: Was ist blos in diesem Thread los? Der ist ja mindestens 3 mal so breit wie mein Bildschirm, ich muss ständig den horizontalen Scrollbalken benutzen.
Reality is that which, when you stop believing in it, doesn't go away.

Tommy

  • Gast
Gespeichert
« Antwort #8 am: 18. December 2010, 09:35 »
Hallo

@erik.vikinger: Ich glaube das liegt an dem Code block in dem Post von Redeagle vom 19. Januar 2010, 20:08.


Tommy

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 18. December 2010, 14:00 »
Nur der Vollständigkeit halber:

Dass die .bss Sektion mit Nullen gefüllt wird, steht im ELF-Standard.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

RedEagle

  • Beiträge: 244
    • Profil anzeigen
    • RedEagle-OperatingSystem - Projekt
Gespeichert
« Antwort #10 am: 18. December 2010, 16:50 »
PS.: Was ist blos in diesem Thread los? Der ist ja mindestens 3 mal so breit wie mein Bildschirm, ich muss ständig den horizontalen Scrollbalken benutzen.
Bei mir wird der Text ordentlich umgebrochen :-P . Ich habe dennoch mal den post bearbeitet und ein paar Zeilenumbrüche eingefügt :-)

Dass die .bss Sektion mit Nullen gefüllt wird, steht im ELF-Standard.
Genau das war ja auch damals das Problem - ich habe alles in eine Binärdatei gepackt und die dann in den RAM gelegt. So etwas wie ein bss-segment gab es nicht  :-D
Inzwischen befindet sich aber auch der Kernel in einer elf-Datei.  8-)


 

Einloggen