Forum: PC Hard- und Software Adressbereiche unter Linux


von Simon S. (-schumi-)


Lesenswert?

Hallo Zusammen,

ich lese hier gerade ein Linux-Buch und habe ein Verständnisproblem mit 
den Adressbereichen..

Ich habe ein kleines C-Programm:
1
#include <stdio.h>
2
3
int main()
4
{
5
        char* text = "Hello World!\n";
6
        printf("%p: %s\n", text, text);
7
        getchar();  // auf Tastendruck warten, damit ich 2 gleichzeitig laufen lassen kann
8
        return 0;
9
}
Ausgabe:
1
0x40066c: Hello World!

Ich gehe richtig davon aus, dass die Adresse des "Hello World!" auf den 
Anfang des Adressbereiches dieses Prozesses bezogen ist, oder?

(Dafür spricht auch, dass wenn ich das Programm 2x gleichzeitig laufen 
lasse, bei beiden die selbe Adresse angezeigt wird)



Da stellt sich mir folgende Frage:


Warum ist die Adresse 0x40066c? (entspricht ziemlich genau 4MegaByte)

Im Adressraum des Prozesses liegt doch hauptsächlich nur der 
Maschinencode und das "Hello World!" als char-array. Wie kommt der da 
auf 4MB?? Und warum kann ich nicht auf Adresse 0/1/usw. Zugreifen (Dort 
sollte ja dann der Adressraum starten)? (text=0; printf(text); -> 
Speicherzugriffsfehler)



Würde mich freuen, wenn mir das jemand erklären könnte :)

Viele Grüße,
Simon

PS: CPU: x86_64 Intel Pentium(R) Dual-Core CPU T4500

von (prx) A. K. (prx)


Lesenswert?

Ausgabe:
0x40064c: Hello World!

Aus
  objdump -h ...
ergibt sich:
15 .rodata       0000001a  0000000000400648  0000000000400648  00000648
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
Der Kram liegt also da, wo er hingehört, im Bereich konstanter Daten.

Die Adresse 0 wird üblicherweise grosszügig umschifft, damit NULL 
Pointer auf die Nase fallen. Also fängt Linux bei 4MB an. Bei einem 
64-Bit Adressraum kommt es nicht auf das letzte Byte an und zu den 
Adressen unterhalb dieser 4MB existiert kein Speicher, wird also auch 
keiner verschwendet.

von Simon S. (-schumi-)


Lesenswert?

Ah, ok - alles klar

Herzlichen Dank! :)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Simon S. schrieb:

> Ich gehe richtig davon aus, dass die Adresse des "Hello World!" auf den
> Anfang des Adressbereiches dieses Prozesses bezogen ist, oder?

Es ist eine virtuelle Adresse.  Ihr Gültigkeitsbereich ist nur
der Prozess selbst, in dem du sie siehst.  Wenn du das Programm
ein zweites Mal parallel startest, sieht das Programm die gleiche
Adresse, obwohl es im Speicher durchaus unterschiedliche Adressen
sein könnten.

Auf welche physische Adresse sie abgebildet wird, ist dabei völlig
offen.  Wenn das Programm startet, wird sie gar nicht abgebildet.
Sowie das erste Mal auf die Speicherseite zugegriffen wird, in der
diese Adresse liegt, gibt es einen page fault, der zu einem so
genannten trap ins Betriebssystem führt.  Das System analysiert
daraufhin, ob der Zugriff ein gültiger war oder nicht.  Wenn nicht,
bekommt das Programm ein Signal (SIGBUS oder SIGSEGV), welches
normalerweise zur sofortigen Beendigung des Programmes führt.

War der Zugriff gültig, dann gibt es im Grunde zwei Möglichkeiten:

1.) Der zugehörige Speicherbereich bildet auf einen Block auf dem
    Sekundärspeicher (Festplatte) ab; es wird eine freie physische
    Speicherseite gesucht (ggf. muss eine andere dafür freigeschaufelt
    werden) und diese mit der virtuellen Adresse verbunden; danach
    wird der Seiteninhalt vom Sekundärspeicher nachgeladen, und das
    Programm fortgesetzt.

2.) Der zugehörige Speicherbereich ist "anonym", d. h. nicht durch
    Sekundärspeicher abgedeckt; es muss auch eine freie physische
    Speicherseite gefunden und verbunden werden; diese wird
    anschließend aus Sicherheitsgründen (kein Zugriff auf Daten
    fremder Applikationen oder Nutzer!) ausgenullt, und das
    Programm fortgesetzt.

Fall 2 betrifft den Stack oder nicht explizit initialisierte Daten
(.bss-Bereich).  Fall 1 betrifft einerseits Programmcode oder
konstante Daten.  Wenn physischer Speicher knapp wird, müssen diese
Bereiche nicht auf Sekundärspeicher zurückgeschrieben werden, da sie
ja jederzeit von diesem wieder erneut gelesen werden können.  Fall 1
kann aber auch initialisierte Daten betreffen, diese werden anfangs
aus dem Programmabbild selbst geladen.  Wenn physischer Speicher knapp
wird und diese Seiten ausgelagert werden müssen (oder auch Seiten, die
ursprünglich über Fall 2 angelegt worden sind), dann wir deren Inhalt
in den Swap-Bereich ausgelagert.  Von da geht es dann später über Fall
1 weiter, aber diesmal wird nicht aus dem Programmabbild nachgeladen,
sondern aus dem Swap-Bereich.

Ist ein wenig vereinfacht dargestellt ;-), aber ungefähr so arbeiten
alle VM-Systeme (virtual memory), beginnend mit dem legendären VMS von
DEC, die dieses Prinzip mit den Vax-Computern seinerzeit eingeführt
haben.

> Warum ist die Adresse 0x40066c? (entspricht ziemlich genau 4MegaByte)

Den Teil "warum 4 MiB" hat dir A. K. beantwortet.

Der Teil "warum nicht genau 4 MiB" hängt damit zusammen, dass die
gesamte ELF-Datei selbst auf eine "glatte" Adresse abgebildet wird,
einschließlich all ihrer Headerdaten.  Damit ergeben sich dann für
die tatsächlichen Adressen im Programm (Startadresse, Beginn des
Datenbereichs etc.) "unrunde" Adressen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.