Hallo
Ich habe mich heute gefragt, wie der C-Compiler Variablen adressiert
(vll etwas komisch ausgedrückt).
Ich meine das so:
Wenn ich für den AVR ein Programm in Assembler schreibe, dann muss ich
mir überlegen, wo ich Variablen im RAM ablege (wenn ich z.B. den Wert
von R16 an die Adresse xyz speichern will). Da gibt es ja dann auch
keine Variablen.
Aber in C deklariere ich z.B.
int i;
Das sind ja 32bit. Bei der Deklaration müsste doch eigentlich schon
Speicher reserviert werden, oder? Aber wo speichere ich die Adresse ab?
Und wie rufe ich diese wieder auf (...also an welcher Adresse hole ich
mir die Adresse?! :D).
Wenn ich jetzt diese Variable mit etwas beschrieben will, z.B
i = 10;
dann müsste ja zuerst die Zahl 00000000|00000000|00000000|00001010 in 4
Arbeitsregister geschrieben werden, und den Inhalt dieser vier Register
dann an die Adresse des vorher reservierten Speichers geschoben werden.
Also wie setzt der Compiler diesen C-Code in Assembler um?
Samuel J. schrieb:> Also wie setzt der Compiler diesen C-Code in Assembler um?
schau es dir doch einfach an, im ASM listing sieht man es.
Ja der Compiler ordnet jede globale Variable einen Speicherplatz zu
(genauer gesagt macht das er der Linker). Und überall wo die Variable
verwendet wird, wird dann einfach die Adresse verwendet.
Samuel J. schrieb:> (vll etwas komisch ausgedrückt).
Ja.
> Aber in C deklariere ich z.B.> int i;> Das sind ja 32bit.
Nein. Es sind mindestens 16 Bits.
> Bei der Deklaration müsste doch eigentlich schon> Speicher reserviert werden, oder?
Bei Speicherklasse "auto" nicht, also den lokalen Variablen ohne
expliziter Speicherklasse. Die liegen in aller Regel auf dem Stack und
werden damit dynamisch reserviert.
> Aber wo speichere ich die Adresse ab?
Bei statischer Adresse (extern/static) im Befehl. Bei "auto" im Befehl
als Distanz zum Stack- oder Frame-Pointer.
> Und wie rufe ich diese wieder auf (...also an welcher Adresse hole ich> mir die Adresse?! :D).
Kling nach endloser Rekursion, zumindest in der Frage.
Volgo: Hä?
> Also wie setzt der Compiler diesen C-Code in Assembler um?
Jeder ein wenig anders.
Samuel J. schrieb:> Hallo>> Ich habe mich heute gefragt, wie der C-Compiler Variablen adressiert> (vll etwas komisch ausgedrückt).>> Ich meine das so:> Wenn ich für den AVR ein Programm in Assembler schreibe, dann muss ich> mir überlegen, wo ich Variablen im RAM ablege
bei den meisten Assemblern brauchst du das nicht. Du teilst dem
Assembler einfach nur mit, dass du zb 2 Bytes unter einem Namen
reserviert haben willst, und der Assembler macht das. Er merkt sich die
Adresse in Tabellen während eines Assembler Laufes und setzt die Adresse
überall dort ein wo du den Namen verwendest. Den exakte Zahlenwert, wo
genau das Teil im Speicher liegt, brauchst du nie wirklich.
> Aber in C deklariere ich z.B.> int i;>> Das sind ja 32bit. Bei der Deklaration müsste doch eigentlich schon> Speicher reserviert werden, oder?
Auch wenn es technisch etwas komplizierter ist (weil da auch noch ein
Linker im Spiel ist): Bei der Definition einer Variablen wird Speicher
zugeteilt und Compiler (bzw. Linker) merken sich, an welcher Adresse das
ist.
> Aber wo speichere ich die Adresse ab?
Gar nicht.
Die geht dich nichts an.
> Und wie rufe ich diese wieder auf (...also an welcher Adresse hole ich> mir die Adresse?! :D).
Du kannst immer den Adress of OPerator benutzen, wenn du die Adresse
haben willst.
> Wenn ich jetzt diese Variable mit etwas beschrieben will, z.B> i = 10;> dann müsste ja zuerst die Zahl 00000000|00000000|00000000|00001010 in 4> Arbeitsregister geschrieben werden, und den Inhalt dieser vier Register> dann an die Adresse des vorher reservierten Speichers geschoben werden.
Ja.
Aber wieder: das geht dich nicht an. Das erledigen Compiler/Linker für
dich. Genau dazu hat man ja COmpiler, damit man sich um solche
"Kleinigkeiten" nicht kümmern muss.
Peter schrieb:
> Ja der Compiler ordnet jede globale Variable einen Speicherplatz zu
Ok, bei einem AVR, bei dem immer nur 1 Programm läuft verstehe ich das,
aber wie geht das bei x86 Prozessoren?
Da ist ja nicht immer die gleiche Speicheradresse frei?
Der Datentyp int hat üblicherweise, insbesondere beim 8 Bit AVR nur 16
Bit Größe.
Wie der Compiler die variablen im Speicher ablegt hängt vom Compiler und
der Art der Variable (Global, lokal, static). Die Adresse zu der
variable muss vor allem der Compiler kennen und beim Zugriff einsetzten.
Im µC speichern muss er das oft nicht.
Was der Compiler daraus macht, schaut man sich am besten direkt an, etwa
bei GCC im .lst File.
Samuel J. schrieb:> Da ist ja nicht immer die gleiche Speicheradresse frei?
Aus Sicht von Compiler, Linker und Programm schon. Aus Sicht des
Betriebssystems und der Speicherchips nicht. Den Unterschied dazwischen
nennt man Speicherverwaltungseinheit, oder MMU.
https://de.wikipedia.org/wiki/Memory_Management_Unit
Samuel J. schrieb:> Ok, bei einem AVR, bei dem immer nur 1 Programm läuft verstehe ich das,> aber wie geht das bei x86 Prozessoren?> Da ist ja nicht immer die gleiche Speicheradresse frei?
geht dort genauso, jeder Prozess hat seinen eigenen Virtuellen Speicher.
Bei Systemen wo das nicht so ist, kann das Betriebssystem beim laden
einfach einen Offset vorgeben.
Ok ich verstehe.
Also wenn ich mal eure 2 Antworten zusammenfasse, wäre das dann so
gemeint:
Jedes Programm hat einen Speicherbereich im RAM zugewiesen (kurze
Zwischenfrage: statisch oder dynamisch?). Sagen wir mal jedes Programm
hat 1MB platz. Wenn jetzt das Programm auf die Adresse 0x01 zugreifen
will, addiert die MMU den Offset, also die Anfangsadresse des Programms,
um auf die tatsächliche Adresse des Chips zu kommen.
Ist das so richtig?
Samuel J. schrieb:> Wenn jetzt das Programm auf die Adresse 0x01 zugreifen> will, addiert die MMU den Offset, also die Anfangsadresse des Programms,> um auf die tatsächliche Adresse des Chips zu kommen.> Ist das so richtig?
in etwa. Es wird eine Tabelle sein. Also eine Übersetzung von
Virtueller-Programm Adresse zu Physikalischer-Ram Adresse.
Samuel J. schrieb:> Jedes Programm hat einen Speicherbereich im RAM zugewiesen (kurze> Zwischenfrage: statisch oder dynamisch?).
Windows/Linux: dynamisch. Bare Metal, wie AVR: statisch.
> Ist das so richtig?
So ungefähr. Nur verwendet man jenseits 8086/286 keine Addition, sondern
macht das seitenweise (paging). Weshalb es virtuellen Programmspeicher
geben kann, für den kein physikalischer Speicher reserviert ist. Das
scheppert dann beim Zugriff und der Speicher wird beschafft (oder das
Programm fliegt weg).
Samuel J. schrieb:> Jedes Programm hat einen Speicherbereich im RAM zugewiesen (kurze> Zwischenfrage: statisch oder dynamisch?).
wie soll es dann statisch sein, wenn man das Programm jederzeit starten
und beenden kann?
Du musst schon etwas unterscheiden, zwischen eine Programm was innerhalb
einen Betriebssysteme läuft und einen Programm was direkt von einer CPU
ausgeführt wird.
Peter schrieb:
> wie soll es dann statisch sein, wenn man das Programm jederzeit starten> und beenden kann?
Ich meinte damit ob der zugewiesene Speicher immer gleich groß ist und
ein Programm, wenn es mehr Speicher braucht, mehrere davon bekommt, oder
ob es gleich dynamisch angepasst wird.
> Du musst schon etwas unterscheiden, zwischen eine Programm was innerhalb> einen Betriebssysteme läuft und einen Programm was direkt von einer CPU> ausgeführt wird.
Das verstehe ich jetzt nicht so ganz. Ein Programm wird doch im
Endeffekt immer von der CPU ausgeführt. Und ein OS ist doch eigentlich
auch nur eine Lib mit Syscalls. So Sachen wie Shell oder Grafische
Oberfläche sind doch auch nur Programme in einem anderen Systemmode.
Oder täusche ich mich da?
Samuel J. schrieb:> Ich meinte damit ob der zugewiesene Speicher immer gleich groß ist
Nein. Auf den realen Speicher bezogen.
> oder ob es gleich dynamisch angepasst wird.
Ja.
> Das verstehe ich jetzt nicht so ganz. Ein Programm wird doch im> Endeffekt immer von der CPU ausgeführt.
Es können auch mehrere CPUs sein. Und es kann auch eine einzelne CPU
gleichzeitig mit mehreren Programmen beschäftigt sein, auch mehrfach dem
gleichen.
> Und ein OS ist doch eigentlich auch nur eine Lib mit Syscalls.
Nein. Das hat ein Eigenleben.
> So Sachen wie Shell oder Grafische> Oberfläche sind doch auch nur Programme in einem anderen Systemmode.
Shell ja. Bei der GUI hängt das vom System ab.
Filesysteme können beispielsweise eine Kombination aus Kernel-Code und
Hintergrundprozessen sein.
Samuel J. schrieb:> Peter schrieb:>> wie soll es dann statisch sein, wenn man das Programm jederzeit starten>> und beenden kann?>> Ich meinte damit ob der zugewiesene Speicher immer gleich groß ist und> ein Programm, wenn es mehr Speicher braucht, mehrere davon bekommt, oder> ob es gleich dynamisch angepasst wird.
Das spielen jetzt mehrere Komponenten zusammen.
Wenn eine MMU im Spiel ist, die mit Paging funktioniert, dann muss nicht
zu jedem Zeitpunkt jede vrituelle Adresse auch auf tatsächlich physisch
vorhandenem Speicher abgebildet sein.
Wenn ein Programm in so einem System loslegt, dann spricht es den
Speicher (über die virtuelle Adresse ) einfach an. Die MMU kriegt diese
Adresse und sieht nach, zu welchem physikalisch vorhandenem Speicher
diese Adresse gehört. Gibt es physikalischen Speicher dafür, dann geht
die Adresse an den Adressbus raus und der zuständige Speicherbaustein
liefert die Daten (oder verinnahmt sich die Daten vom Datenbus). Ist
aber der virtuellen Adresse kein physischer Speicher zugeordnet, dann
löst die MMU eine Ausnahmebehandlung aus. Der Ball geht zum
betriebssystem, welches dafür zuständig ist, einen entsprechenden
Speicherbereich freizuschaufeln (falls gerade nichts frei ist) und in
der MMU eine Verknüpfung von der virtuellen Adresse in diesen (ev. erst
freigeräumten) Speicher herzustellen.
NOrmalerweise geschehen derartige Reservierungen in Form von
Speicherblöcken, die man auch Pages nennt. Denn wenn man das für jede
Adresse einzeln machen müsste, würde das ausufern. Die MMU verwaltet zb
jeweils 4K grosse Speicherblöcke. Aus der virtuellen Adresse wird die
Blocknummer ermittelt, in der diese Adresse liegt und mit der wird dann
in den Tabellen nachgesehen, welcher physikalisch tatsächlich vorhandene
Speicher (der dann ebenfalls in 4K großen Blöcken eingeteilt ist) da
dazugehört.
Das heißt aber auch: Das Programm kann beim Starten über den kompletten
Adressraum verfügen. Verfügen in dem Sinne, das es einfach den Speicher
(aus seiner Sicht) anspricht, obwohl ihm dafür noch gar kein physischer
Speicher zugeordnet wurde. Das geschieht erst nach und nach, je nachdem
wie und wo das Programm mittels seiner virtuellen Adressen zugreift.
>> Du musst schon etwas unterscheiden, zwischen eine Programm was innerhalb>> einen Betriebssysteme läuft und einen Programm was direkt von einer CPU>> ausgeführt wird.>> Das verstehe ich jetzt nicht so ganz. Ein Programm wird doch im> Endeffekt immer von der CPU ausgeführt. Und ein OS ist doch eigentlich> auch nur eine Lib mit Syscalls.
So einfach ist die Sache nicht. Ein Betriebssytem hat sich auch um die
Verwaltung der Resourcen zu kümmern. Zum Beispiel um die Zuteilung von
real existierendem Speicher zu virtuellen Adressen.
Ok danke für eure Antworten! :)
A.K
>Nein. Das hat ein Eigenleben.
Was meinst du genau mit Eigenleben?
Meinst du damit so Sachen wie TCP/IP Stack und solche Anwendungen?
Samuel J. schrieb:>>Nein. Das hat ein Eigenleben.>> Was meinst du genau mit Eigenleben?
es kann z.b. deim Programm einfach keine CPU zeit mehr zuweisen, es kann
dein Programm komplett aus dem Speicher löschen. Es kann halt dinge
mache die das Programm nicht kontrollieren kann.
Samuel J. schrieb:> Ok danke für eure Antworten! :)>> A.K>>Nein. Das hat ein Eigenleben.>> Was meinst du genau mit Eigenleben?
Du hast anscheinend noch nie erlebt, wenn Windows zwischendurch mal den
Speicher aufräumt. Plötzlich fängt deine Festplatte an zu laufen, weil
Windows anfängt zu voll gewordenen Speicher auf die Festplatte
auszulagern bzw. frei gewordenen Speicher wieder aus der Festplatte mit
den Bytes zu beschreiben.
Auf heutigen Systemen ist das Betriebssystem nicht einfach nur eine Lib.
Genau anders rum. Das Betriebssystem ist das Hauptprogramm das die
Kontrolle über alles hat und es teilt deinem Programm Dinge zur
Benutzung zu. Das BS ist der Boss!
Samuel J. schrieb:> Das wäre ja dann der Scheduler, also auch ein Programm im Kernelmode,> oder?
Es ist ein Teil von BS, ob das ganze im Kernelmode läuft ist von der CPU
anhängig, nicht jede CPU hat so etwas.
Samuel J. schrieb:> Was meinst du genau mit Eigenleben?> Meinst du damit so Sachen wie TCP/IP Stack und solche Anwendungen?
Auch. Aber wie erwähnt kann beispielsweise die Implenmentierung eines
Filesystems sowohl aus Kernelkomponenten im Sinne deiner Library
bestehen, als auch aus Hintergrundprozessen für weitergehende
Verwaltung.
Das kann auch bei Speicherverwaltung so sein. Der Kernel reagiert auf
die Speicheranforderung, sei es per Syscall oder per Paging-Exception
wie von KHB beschrieben. Und ein Verwaltungsprozess/thread sorgt
vielleicht für ausgewogene Zuordnung und passendem Freiraum.
> Es ist ein Teil von BS
OK
> ob das ganze im Kernelmode läuft ist von der CPU> anhängig, nicht jede CPU hat so etwas.
Ok, dann meinte ich etwas anderes. Aber mir ist klar auf was ihr hinaus
wollt. :)
Samuel J. schrieb:> Wenn ich für den AVR ein Programm in Assembler schreibe, dann muss ich> mir überlegen, wo ich Variablen im RAM ablege (wenn ich z.B. den Wert> von R16 an die Adresse xyz speichern will). Da gibt es ja dann auch> keine Variablen.
In Assembler kann man es aber auch fast so machen wie der Compiler --
zumindest mit dem GNU-Assembler, etwa:
1
;; Program Code
2
.text
3
4
;; The Startup-Code from crt*.o calls main
5
.global main
6
.type main,@function ;; just for debugger, objdump etc.
7
8
main:
9
;; Load address of var to R20/R21
10
ldi r20, lo8(var)
11
ldi r21, hi8(var)
12
;; Store &var in var
13
sts var, r20
14
sts var+1, r21
15
;; Epilogue
16
ret
17
.size main, .-main ;; Just for book keeping
18
19
;; .data Section: Static data initialized at Load-Time
20
.data
21
22
.global var
23
.type var,@object ;; just for debugger, objdump etc.
24
var:
25
.word 1000
26
27
;; Section .data must be initialized at Load-Time.
28
;; Refer to the respective Bit of Startup-Code to drag it in
29
.global __do_copy_data
30
31
;; Similar for Data in .bss, i.e. initialized to 0 at Load-Time
32
; .global __do_clear_bss
"var" liegt hier im Static Storage, d.h. der Platz für die Variable wird
vom Linker/Lokator vergeben. Das Symbol "var" wird dann, wenn lokatiert
wird, durch die konkrete Adresse ersetzt; bis dahin ist es lediglich
sowas wie ein eindeutig vergebener Platzhalter.
Das Programm kann übersetzt werden mit
Das liefert erstma die Dröhnung... Was passiert ist folgendes
1) Der Compiler-Treiber (avr-gcc) erkennt an der Endung .sx, daß es sich
um eine Assembler-Quelle handelt, die durch den C-Präprozessor soll.
2) Der Treiber ruft den Präprozessor auf und speichert das Ergebnis als
bar.s, eine reine Assemler-Datei (hier kein Unterschied).
3) Der Treiber ruft den Assembler auf, dieser assembliert bar.s zu bar.o
und dumpt seine Arbeit als bar.lss. bar.o enthält Platzhalter für "var",
die als 0 disassembliert werden weil dem Symbol noch kein Wert
zugewiesen ist. Mehr sieht man an dem von objdump erzeugten .lso: Hier
sieht man die Relocs und deren Adressen. Für den High-Teil von "var"
wird ein anderer Reloc benötogt als für den low-Teil, und wieder ein
anderer für die 16-Bit Adresse des low-Teils bzw. 16-Bit Adresse des
high-Teils von "var".
4) Der Treiber ruft collect2 und den Linker mit zahlreichen Optionen und
Dateien auf, darunter alle Objekte und Bibliotheken, die zum fertigen
Programm benötogt werden: crt*.o (Startup-Code), bar.o (Hauptprogramm),
libgcc.a (statische Bibliothek mit Basis-Arithmetik und weiteren Teilen
des Startup-Codes), etc.
5) Der Linker durchsucht die Symboltabellen nach undefinierten Symbolen,
z.B. "var". Wenn er keine Definition finden kann dann gibt er ein Fehler
aus. Ansonsten zieht sich der Linker benötigte Sections aus den
Bibliotheken (hier z.B. __do_copy_data aus der libgcc.a) um Symbole
aufzulösen, und der Locator ordnet dann den Symbolen Werte zu. Diese
Zuordnung passiert anhand des Symboltyps, seiner Größe, seinem
Alignment, seinen Flags und seiner Section (.data für "bar", .text für
"main", .init4 für "__do_copy_data"). Wie und wo die einzelnen
Input-Sections, Objects und Objekte abzulegen und auf Outpt-Sections
abzubilden sind, erfährt der Linker aus der Linker-Description
(avr/lib/ldscripts) und Kommandzeilen-Optionen. Was wohin lokatiert
wurde siehst du in der Memory-Map bar.map sowie im Dump bar.lst des
fertigen bar.elf:
1
0000004e <main>:
2
4e: 40 e6 ldi r20, 0x60 ; 96
3
50: 50 e0 ldi r21, 0x00 ; 0
4
52: 40 93 60 00 sts 0x0060, r20
5
56: 50 93 61 00 sts 0x0061, r21
6
5a: 08 95 ret
var liegt also an Adresse 0x60, dem Start des RAMs beim ATmega8.
> Aber in C deklariere ich z.B.> int i;
Der Compiler erzeugt den Assembler-Code nach den gleichen Prinzipien wie
oben. Das Beispiel entspricht ca.
1
void*var;
2
3
voidmain(void)
4
{
5
var=&var;
6
}
wenn im Compileraufruf bar.sx durch bar.c ersetzt wird. Zusätzlich mit
-Os -fno-common -fverbose-asm kommt bar.i als Dump-Datei hinzu
(präprozessierte C-Quelle), und bar.s wird zu:
1
.file "bar.c"
2
__SP_H__ = 0x3e
3
__SP_L__ = 0x3d
4
__SREG__ = 0x3f
5
__tmp_reg__ = 0
6
__zero_reg__ = 1
7
8
...
9
.section .text.startup,"ax",@progbits
10
.global main
11
.type main, @function
12
main:
13
/* prologue: function */
14
/* frame size = 0 */
15
/* stack size = 0 */
16
.L__stack_usage = 0
17
ldi r24,lo8(var) ; tmp42,
18
ldi r25,hi8(var) ; ,
19
sts var+1,r25 ; var, tmp42
20
sts var,r24 ; var, tmp42
21
ret
22
.size main, .-main
23
.global var
24
.section .bss
25
.type var, @object
26
.size var, 2
27
var:
28
.zero 2
29
.ident "GCC: (GNU) 5.0.0 20140907 (experimental)"
30
.global __do_clear_bss
> Das sind ja 32bit. Bei der Deklaration müsste doch eigentlich schon> Speicher reserviert werden, oder?
Nö, eine Deklaration legt kein Speicher an, sondern eine Definition.
Was oben steht ist eine Definition.
> Aber wo speichere ich die Adresse ab?> Und wie rufe ich diese wieder auf (...also an welcher Adresse hole ich> mir die Adresse?! :D).
I.d.R brauchst du die Adresse nicht, zumindest nicht den exakten
Zahlenwert. Verfolge einfach mal, was aus folgenden Code wird und
verstehe die Fehlermeldung, die er erzeugt und wie man sie behebt:
1
externinti;
2
3
int__attribute__((noinline,noclone))
4
get_int(int*address)
5
{
6
return*address;
7
}
8
9
intmain(void)
10
{
11
returnget_int(&i);
12
}
Dat Attribut-Gedöns dient nur dazu, daß der Code nicht bis zur
Unkenntlichkeit optimiert wird.
> Wenn ich jetzt diese Variable mit etwas beschrieben will, z.B> i = 10;> dann müsste ja zuerst die Zahl 00000000|00000000|00000000|00001010 in 4> Arbeitsregister geschrieben werden, und den Inhalt dieser vier Register> dann an die Adresse des vorher reservierten Speichers geschoben werden.
Ja. Es sei denn, es kann wegoptimiert werden (z.B. weil der Wert nicht
verwendet wird).
> Also wie setzt der Compiler diesen C-Code in Assembler um?
-save-temps -fverbose-asm -g0 ist hier dein Freund.
Samuel J. schrieb:>> Du musst schon etwas unterscheiden, zwischen eine Programm was innerhalb>> einen Betriebssysteme läuft und einen Programm was direkt von einer CPU>> ausgeführt wird.>> Das verstehe ich jetzt nicht so ganz. Ein Programm wird doch im> Endeffekt immer von der CPU ausgeführt. Und ein OS ist doch eigentlich> auch nur eine Lib mit Syscalls.
So war das bis (MS-)DOS.
Seit dem hat sich eine Menge getan. PC haben seit dem 386 eine MMU und
damit die Möglichkeit, mehrere (viele) Tasks mit jeweils ihrem eigenen
virtuellen Adreßraum zu haben. Das Betriebssystem ist (wenn es diese
Funktion nutzen will) dann u.A. beauftragt, beim Wechsel zwischen Taks
nicht nur den CPU-Kontext (Registerbelegung) sondern auch den
MMU-Kontext (Mapping von virtuellem zu physischem Speicher)
umzuschalten. Die Speicherwerwaltung ist bei allen nennenswerten
Betriebssystemen komplett dynamisch. Das geht so weit, daß Teile des
Maschinencodes eines Programms, die (noch) nicht ausgeführt wurden, auch
gar nicht im Speicher liegen. Das Mapping hat dann an dieser Stelle ein
"Loch", das erst dann gefüllt wird, wenn der entsprechende Code auch mal
zur Ausführung kommt. Genauso kann Speicher der in den Adreßraum eines
gerade nicht ausgeführten Programms gemappt ist, freigemacht werden
(ausgelagert, ausgeswapt) und kurzfristig einem anderen Programm gegeben
werden.
Ja, das ist faszinierend. Eben deswegen hat ein finnischer Student
namens Linus Torvalds sich auch kurz nachdem er seinen ersten 386er
hatte, mal eine Polarnacht lang hingesetzt und ein Betriebssystem
gehackt das die Möglichkeiten des neuen Prozessors auch ausnutzte. Das
war vor 23 Jahren. Der Rest ist Geschichte.
Die Konzepte hat Linus natürlich nicht neu entwickelt. Die waren in der
Welt der Mini- und Großrechner schon damals etabliert. Ein wichtiger
Begriff in diesem Zusammenhang wäre Paging.
XL
>Axel Schwenke (a-za-z0-9)>> Das verstehe ich jetzt nicht so ganz. Ein Programm wird doch im>> Endeffekt immer von der CPU ausgeführt. Und ein OS ist doch eigentlich>> auch nur eine Lib mit Syscalls.>So war das bis (MS-)DOS.
So ist das auch jetzt noch. Oder was sonst führt denn sonst das Program
aus.
Der große Unterschieht ist nur, daß unter DOS das Programm alles machen
konnte, was es so wollte (hatte volle Kontrolle auf die Hardware (DOS
selbst war eigentlich eher nur ein Programmstarter mit ein paar
nützlichen Routinen), während unter moderneren OS das Programm eben
nicht mehr alles mit der HW machen darf, was es will.
Dabei ist es eigentlich noch nichtmal das OS, welches dies ermöglicht,
sondern der Prozessor, der die entprechende Architektur dafür bietet.
Z.B. unterschiedliche Privilegienlevel bei Intel (Ring 0 - 3).
Das OS (dessen Kernel) läuft auf Ring 0 (höchste Privilegien - kann also
alles machen), und Programme laufen auf 3 (niedrigste Privilegstufe -
darf z.B. keine direkten HW-Zugriffe machen).
Damit der Prozessor weis, was er wie machen soll, muß das OS ihn
sozusagen konfigurieren (Prozessormodus, Pagetables, ...)
Für alles, was das Priogram richting HW (CPU Settings (Register),
Peripherie) machen will, muß es das OS fragen, indem es die Syscalls
benutzt. Damit bleiben sämtliche Zugriffe anch ausen wie auch
Memorymanagment (mit hilfe des virt. Memorykonzepts) unter Kontoll des
OS.
Peter II schrieb:> Samuel J. schrieb:>> Das wäre ja dann der Scheduler, also auch ein Programm im Kernelmode,>> oder?>> Es ist ein Teil von BS, ob das ganze im Kernelmode läuft ist von der CPU> anhängig, nicht jede CPU hat so etwas.
Der CPU ist es eigentlich ziemlich wurscht, ob der Scheduler im Kernel
läuft oder nicht. Es ist vielmehr vom Betriebssystem abhängig.
Axel Schwenke schrieb:> PC haben seit dem 386 eine MMU und damit die Möglichkeit, mehrere (viele)> Tasks mit jeweils ihrem eigenen virtuellen Adreßraum zu haben.
Eigentlich schon seit dem 286. Da wurde das nur noch nicht so intensiv
benutzt, und es gab noch kein Paging.
> Die Speicherwerwaltung ist bei allen nennenswerten Betriebssystemen> komplett dynamisch. Das geht so weit, daß Teile des Maschinencodes eines> Programms, die (noch) nicht ausgeführt wurden, auch gar nicht im Speicher> liegen. Das Mapping hat dann an dieser Stelle ein "Loch", das erst dann> gefüllt wird, wenn der entsprechende Code auch mal zur Ausführung kommt.
Oder z.B. wie beim Unix-Systemcall fork(), mit dem sich ein Prozess
duplizieren kann. Tatsächlich wird erstmal vom Speicher her nur die
Seitentabelle kopiert. Der eigentliche Programmspeicher ist bei beiden
physikalisch der selbe. Erst wenn eine der beiden Programm-Instanzen
einen Schreibzugriff im Speicher macht, wird die entsprechende
Speicherseite (und nur die) kopiert, damit die Programme unabhängig von
einander weiterlaufen können.
> Genauso kann Speicher > der in den Adreßraum eines gerade nicht> ausgeführten Programms gemappt ist, freigemacht werden (ausgelagert,> ausgeswapt) und kurzfristig einem anderen Programm gegeben werden.
Und später, wenn der ausgelagerte Speicher wieder zurückgelesen wird,
muß das im realen Speicher nicht mehr an der selben Stelle sein, wie
vorher. Für das Progamm ist es aber an der selben Adresse. Das hat nicht
mal mitbekommen, daß ein Teil seines Speichers zwischendurch ausgelagert
wurde.
Danke an Alle für die hilfreichen Antworten!
Ich habe mir jetzt ein Buch über Betriebssysteme gekauft, da ich mich
jetzt intensiver damit beschäftigen will.
Aber wenn es wieder Fragen gubt wende ich mich wieder an euch :)