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?
Gast
#3799904
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.
Gast
#3799905
Samuel J. schrieb: > Also wie setzt der Compiler diesen C-Code in Assembler um? Bei AVR-GCC: Little-Endian
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.
Gast
#3799910
Samuel J. schrieb: > Das sind ja 32bit nein, nur bei einer 32bit CPU. Bei einer 8 oder 16bit CPU sind es nur 16bit.
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
Gast
#3799922
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?
Gast
#3799930
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).
Gast
#3799934
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?
Gast
#3799969
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!
>deim Programm einfach keine CPU zeit mehr zuweisen
Das wäre ja dann der Scheduler, also auch ein Programm im Kernelmode,
oder?
Gast
#3799980
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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
"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
1 | |
2 | |
3 | |
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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
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 | |
2 | |
3 | |
4 | |
5 | |
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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
> 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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
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 :)
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.