Wie funktioniert die virtuelle Addressvergabe bei heutigen Systemen



  • Hallo C++.de Community,
    zuallerest meine Frage ist keine direkte Frage zur Entwicklung von Betriebssystem Funktionen,sondern sie bezieht sich auf die Funktionsweiße von heutigen Betriebssystemen ich dachte mir allerdings hier ist der richtige Platz dafür.

    Ich verstehe leider auch nach X Wikipedia Artikeln zum Speichermanagment eines Betriebssystem nicht wie die Addressen einem Prozess zugeteilt.
    So habe ich es verstanden (kurzfassung):
    Heute ist es ja normal,dass ein Prozess bei jedem Start einen bestimmten virtuellen Addressberreich zugeteilt bekommt (welcher sich auch nach jedem neustart des Prozesses auch ändert).Eine virtuelle Addresse besteht aus der BasisAdresse (Start des Adressraums eines Prozesses)
    und einem Offset welches auch jedes mal anders lautet.In der MMU wird dann eine virtuelle Adresse mittels einer Datenbank(Tabelle) in den physichen Speicherberreich umgewandelt welcher zu, Zugriff auf die Hardware genutzt werden kann.Die logischen(virtuellen) Adressen liegen wie gesagt immer in einem zussammenhängenden Berreich und der Prozess kann deshalb auch nur auf seinen eigenen logischen Adressberreich zugreifen.Der physische Speicherberreich einer logischen Adresse kann dagegen weit von den anderen logischen Adressen entfernt liegen.

    Frage:
    Wenn ich nun aber ein C++ Programm compile müssen doch nach meinem verständniss die virtuellen Adressen für meine Variablen schon feststehen wie sollte mein Programm sonst wissen wohin gesprungen werden soll,oder wo eine Variable liegt.
    Wieso kann das Betriebssystem meinem Prozess dann (immer verschiedene)logische Adressen zuordnen es müssten ja irgendwie die alten Adressen welche zur compile Zeit festgelegt wurden ausgetauscht werden.

    Ich würde mich echt freuen,wenn mir hier jemand eine Antwort darauf geben könnte wahrscheinlich werde ich einfach irgendwo ein grundsätzliches Verständnissproblem haben ,deshalb habe ich oben nochmal extra in der kurzfassung geschrieben wie ich das vorgehen aktueller Betriebssysteme verstanden habe.


  • Mod

    Du kannst Adressen auch relativ angeben. Das dürfte alles beantworten, oder? Programmcode, der erst zur Laufzeit nachgeladen wird (dll, ld) muss schon seit jeher damit zurecht kommen, von beliebiger Stelle aus ausgeführt zu werden.



  • Ist damit gemeint,dass im fertig kompilierten Programm immernoch einfach nur der Name der Variablen steht und das OS ordnet den Namen dann erst beim Start des Programms die logischen Adressen zu,oder was ist mit relativ gemeint?


  • Mod

    MemoryManagment schrieb:

    Ist damit gemeint,dass im fertig kompilierten Programm immernoch einfach nur der Name der Variablen steht und das OS ordnet den Namen dann erst beim Start des Programms die logischen Adressen zu,oder was ist mit relativ gemeint?

    Nein, überhaupt gar nicht. Du scheinst eine völlig falsche Vorstellung zu haben, wie ein Maschinensprachenprogramm funktioniert. Variablen existieren gar nicht mehr und erst recht nicht ihre Namen. Ich denke nicht, dass ich das im Rahmen eines Forenbeitrags erklären kann, außer mit Phrasen wie "alles, an was du glaubst, ist eine Lüge" oder "vergessen du musst, was früher du gelernt hast". Es macht auch nicht viel Sinn, eine Antwort auf deine erste Frage zu versuchen, du würdest sie nicht verstehen.

    Lern mal die Grundlagen von Assembler (ist so nah an der Maschinensprache, dass man von einer 1:1 Übersetzung reden kann, bloß eben für Menschen lesbar), egal für welche Maschine. Dann guck dir vielleicht mal an, was dein Compiler aus einem einfachen Testprogramm macht (viele Compiler können Assembler als Zwischenschritt ausgeben oder zur Not übersetzt man das fertige Programm zurück). Dann bist du so weit, dass du eine Antwort verstehen würdest. Aber höchstwahrscheinlich hat sich die Frage dann ganz von selbst erledigt, denn die Antwort ist (mit diesem Hintergrundwissen) unmittelbar offensichtlich.



  • Hast du denn eine Empfehlung für Assembly Lektüre?
    Das ein Name selbst nichtmehr existiert ist klar der der würde natürlich nach dem Compilen nurnoch aus einer Bitcodierung bestehen,das OS könnte dieses Bitmuster dann aber auch wieder interpretieren das Meinte ich damit,dass in Binärcode keine Namen stehen ist mir bewusst 😃 das war etwas unglücklich formuliert.

    Ich würde das jetzt aber schon gerne verstehen,weil mich diese Frage schon eine ganze weile plagt.
    Was steht im kompilierten Quellcode (in Assembler ausgedrückt) wird einfach jeder Variablen beim Compilen ein Offset vergeben und beim start wird dieses Offset auch die Base des Prozesses addiert um die logische Adresse zu erhalten,oder wie?
    Ich verstehe eben nur nicht was du in diesem Zusammenhang mit relativ meinst.


  • Mod

    MemoryManagment schrieb:

    Hast du denn eine Empfehlung für Assembly Lektüre?

    Leider nein, hab das selber in der Schule gelernt.

    Das ein Name selbst nichtmehr existiert ist klar der der würde natürlich nach dem Compilen nurnoch aus einer Bitcodierung bestehen,das OS könnte dieses Bitmuster dann aber auch wieder interpretieren das Meinte ich damit,dass in Binärcode keine Namen stehen ist mir bewusst 😃 das war etwas unglücklich formuliert.

    Auch das ist eine völlig falsche Vorstellung. Es gibt keine Variablen. Variablen sind Elemente von Hochsprachen, damit Menschen einfacher Programme schreiben können.

    Ich würde das jetzt aber schon gerne verstehen,weil mich diese Frage schon eine ganze weile plagt.

    Ich kann leider nicht den komplizierteren Fall (nicht, dass es wirklich kompliziert wäre, bloß komplizierter) erklären, wenn dir nicht einmal im Ansatz klar ist, was der Normalfall ist.



  • SeppJ schrieb:

    Auch das ist eine völlig falsche Vorstellung. Es gibt keine Variablen. Variablen sind Elemente von Hochsprachen, damit Menschen einfacher Programme schreiben können.

    Ist mir bewusst mit einer Definition einer Variablen gibt man dem Rechner nur an lege X bit/Byte in einen Speicherberreich an und Adressiere mir diesen.
    Wie die Bits/Bytes später interpretiert werden sollen hängt vom Programmierer ab das bestimmt er mit dem Typ einer Variablen....

    Könntest du mir nicht einfach ein kurzes Beispiel geben,oder erläutern was du mit relativer Adressangabe meintest.
    Wenn ich es nicht verstehen sollte Ok dann lass ich das Thema halt erstmal links liegen,aber im moment interessiert mich das schon sehr.



  • Ergänzung des vorigen posts:
    Bei der Definition legt man natürlich nichts an hatte ich wieder blöd ausgedrückt ,sondern man reserviert den Speicherberreich.Bei der Initialisierung wird ein bestimmtes Bitmuster erzeugt welches dann in diesen Speicherberreich geschrieben wird.(Nur damit ich nicht falsch verstanden werde).
    Ich weiß ich drücke mich manchmal sehr unglücklich aus,aber nur zu schreiben alles was du denkst ist falsch ohne jede Erklärung hilft mit leider wenig weiter(No Offense 😃 ).


  • Mod

    MemoryManagment schrieb:

    Ist mir bewusst mit einer Definition einer Variablen gibt man dem Rechner nur an lege X bit/Byte in einen Speicherberreich an und Adressiere mir diesen.
    Wie die Bits/Bytes später interpretiert werden sollen hängt vom Programmierer ab das bestimmt er mit dem Typ einer Variablen....

    Eben auch nicht. Vielleicht in absichtlich unoptimierten Code, damit ein Debugger noch irgendwie einen Zusammenhang zwischen Speicherbereichen und Variablen im Quellcode herstellen kann.

    Könntest du mir nicht einfach ein kurzes Beispiel geben,oder erläutern was du mit relativer Adressangabe meintest.

    Na, relativ eben. Anstatt zu sagen "nimm den Wert an Adresse XYZ", sagt man "nimm den Wert an Stackpointer - 16". Und dieses "Anlegen" von Variablen ist dann das Verschieben des Stackpointers an eine andere Stelle, so dass vor dem Stackpointer genug Platz ist für die Variablen, die eine Funktion braucht. Und wenn die Funktion fertig ist, dann setzt sie den Zeiger wieder da hin, wo er vorher war, so dass die Funktion, aus der die erste Funktion her aufgerufen wurde, von all dem überhaupt gar nichts mitbekommt und ganz normal mit ihren "Variablen" weiter arbeiten kann.

    Obiges ist, wie lokale Variablen funktionieren. Wenn du das verstanden hast, dann bist du schon viel weiter. Guck mal hier:
    http://en.wikipedia.org/wiki/Call_stack



  • Danke für deine Erklärung das war jetzt auch verständlich für mich.
    Wenn der Prozess gestartet wird wird der StackPointer auf die erste Adresse gesetzt. Der Compiler wandelt beim Aufruf einer lokalen Variablen diese einfach um in (Adresse1+X) um.Das geht,weil die logischen Adressen in einem zusammenhängenden Speicherberreich liegen.Die Base wird ja eh immer vom Os bestimmt.Jetzt verstehe ich denke ich auch was mit relativ gemeint war in C++ kann man ja ebenfalls:

    int arr[10];
    int* p_arr=arr;
    *p_arr+5=10;
    

    schreiben.



  • Ach hatte noch was falsch verstanden der Compiler wandelt eine Variable nicht in um (adresse1+offset),sondern der Compiler errechnet wo der Stack Pointer jetzt grade steht und schreibt (Aktueller Stand des StackPointers +/- Offset) um auf die gewollte Adresse zu kommen.Man kann ja immer nur vom aktuellen Stand aus weiter/zurück gehen.


  • Mod

    Der Compiler ist nur bei der Übersetzung des Programmes aktiv.

    Der Stackpointer ist wirklich ein Wert, der irgendwo im Prozessor steht. Der Compiler rechnet, wenn er das Programm erstellt, aus, wie viel Platz eine Funktion braucht und erzeugt dann am Anfang des Codes der Funktion eine Anweisung, die den Stackpointer um eben diesen Betrag weiter setzt. Dann kann er für die Funktion Code erzeugen, der in eben diesem Bereich (zwischen alter Stackgrenze und neuer Stackgrenze) machen kann, was er will. An keiner Stelle müssen konkrete Werte für die Adressen bekannt sein.

    ~(Das ist in Wirklichkeit natürlich alles ein bisschen komplizierter (z.B. wie Rückgabewerte einer Funktion funktionieren), aber mit dieser Vorstellung kommt man schon recht weit.)~


  • Mod

    Für x86 und C habe ich den Mechanismus aufgezeigt: http://henkessoft.de/C/C-Programming Under The Hood.htm


Anmelden zum Antworten