[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: about "size" from binutils



Jörg Sommer wrote:
> Warum wird der uninitialisierte Zeiger nicht ins data Segment
> gelegt? 

Weil das data-Segment im Executable 1:1 vorhanden ist (alle darin
liegenden Variablen sind wohldefiniert). Wenn eine Variable nicht
initialisiert ist, ist es Verschwendung, sie ins data-Segment zu
packen. Dazu nimmt man das bss-Segment, welches erst beim Start im
Hauptspeicher erzeugt wird.

> Dessen Größe ist doch fest.

Die Größe des bss-Segments im Prinzip auch :)
 
> Malloc, genauer brk, 

Nein.

> verändert doch die Größe des data Segments. 

Habe mal ein bisschen zu brk gelesen. Damit kann man anscheinend die
Größe des data-Segments im Speicher zur Laufzeit verändern,
allerdings ist das ein ziemlich unkomfortabler Eingriff (und AFAIK
keine C-Standardfunktion). Problem ist, dass man das Segment nur
bis zur ggf. dahinter liegenden Grenze eines anderen Segments
benutzen kann (siehe Link unten), also ist es weder eine
universelle noch eine praktikable Lösung.

Man _kann_ es dazu benutzen, händisch einen Heap (wie ihn malloc
verwaltet) zu implementieren. Man kann auch einen Stack oder
sonstwas damit erzeugen. Die Funktion übernimmt aber keinerlei
Verwaltungsaufgaben -- im Gegensatz zu malloc.

Lesestoff:

<http://www.gnu.org/software/libc/manual/html_node/
Resizing-the-Data-Segment.html>

> Welche Funktion erfüllt das bss Segment? 

Beim Kompilieren eines Programms muss man Datensegmente erzeugen,
die den Speicher für zur Compilezeit bekannte Variablen enthalten.
Diese Segmente landen zusammen mit den "text"-Segmenten, die den
Programmcode enthalten, im Executable.

Man könnte jetzt einfach alle Variablen sammeln, einen entsprechend
großen Speicherbereich reservieren, und alle reinpacken (das ist
das data-Segment). Für initialisierte Variablen ist das schön und
gut, denn dann braucht der Rechner keine Inline-Konstanten zu
verarbeiten, sondern findet die Variable fertig vor. Zum Beispiel
muss für einen C-String:

char *test = "das ist ein teststring";

nicht ein Bandwurm an Maschinencodebefehlen erzeugt werden, der die
Bytes einzeln in den Speicher schreibt, sondern die Daten werden
einfach am Stück in das data-Segment gepackt. Das verkürzt die
Startzeit und verringert die Größe des Executables.

Das ist aber sehr ineffizient, wenn man viele uninitialisierte
Variablen hat, da für diese trotzdem der volle Speicherbereich
reserviert würde und das Executable riesig wird. Ein
uninitialisiertes int-Array wie das hier:

int honk[1000000];

würde das Executable z. B. fast ein MB größer machen, weil zur
Compilezeit der komplette Speicherbereich im data-Segment
reserviert würde. Das Array enthält aber keinerlei Nutzdaten,
sondern wird erst später im Programmablauf "gefüllt". Deshalb ist
es sinnlos, es in kompletter Länge im Executable unterzubringen.

Deshalb gibt es das bss-Segment. Dort liegen uninitialisierte
Variablen. Es braucht keinen Platz im Executable, weil dort drin
nur steht, wie groß es sein muss. Beim Laden des Executables
reserviert das Betriebssystem einen Speicherbereich der angegebenen
Größe und packt ihn mit zum Prozess dazu.

(Das führt für gewöhnlich dazu, dass uninitialisierte Variablen
Zufallswerte erhalten, weil das Betriebssystem entgegen der
Empfehlung das bss-Segment vor dem Start des Programms nicht
nullt.)

Grüße,


Björn

-- 
BOFH excuse #141:

disks spinning backwards - toggle the hemisphere jumper.


Reply to: