2012-06-17 14 views
15

Ich verstehe es einfach nicht. Jedes Handbuch ist zu technisch. Was sind flache und segmentierte Speicher? Wege zum Adressieren eines Gedächtnisses, Wege zum Organisieren von Bytes im Speicher? Welche davon ist am besten für 32-Bit-Computer geeignet? Kann es jemand erklären? Was haben Real-Mode und Protected-Mode mit flachem oder segmentiertem Speicher zu tun? Vielen Dank!Segmentierter Speicher vs flacher Speicher

+3

Segmentierter Speicher ist (in 32 und 64 Bit Land) ein Übergriff von einer Zeit, als Speicheranforderungen die Größe überschritten des Adressbusses. Solche Überlegungen sind längst vorbei und jeder benutzt jetzt das flache Modell. Die Entwickler des Motorola 68K (ein weit überlegener Prozessor (mit einem viel eleganteren Befehlssatz) für den 286 und seine Vorgänger) wussten das und kümmerten sich nicht um segmentierte Adressierung. Aber Geschichte interessiert sich nicht für Ästhetik und Intel hat gewonnen und jetzt benutzen wir alle die Nachkommen der 386. –

Antwort

18

Wenn Sie nur an Anwendungen interessiert sind, die auf vorhandenen 32/64-Bit-Betriebssystemen ausgeführt werden, können Sie den segmentierten Speicher einfach vergessen. Unter 32-Bit-Betriebssystemen können Sie davon ausgehen, dass Sie 4 GB "flachen" Speicherplatz haben. Flat bedeutet, dass Sie Adressen mit 32-Bit-Werten und Registern bearbeiten können, wie Sie es erwarten würden.

Auf 16-Bit-Prozessoren glaube ich, dass eine Adresse 20 Bits breit war, und Sie konnten das nicht in einem Register speichern, also mussten Sie eine Basis in einem Register speichern, und um eine tatsächliche Adresse anzugeben, mussten Sie Fügen Sie dieser Basis einen Versatz hinzu. (Wenn ich mich richtig erinnere, wurde die Basis mit 16 multipliziert, dann wurde der Offset hinzugefügt, um die tatsächliche Adresse zu erhalten.) Dies bedeutet, dass Sie nur 64 KB gleichzeitig adressieren konnten; Speicher musste in 64 KB Blöcken "segmentiert" werden.

Um ehrlich zu sein, denke ich, der einzige Grund, warum Anfänger immer noch davon hören, ist, dass viele alte 16-Bit-Tutorials und Bücher noch da sind. Es ist wirklich nicht nötig zu verstehen, wie ein Programm auf Assembly-Ebene funktioniert. Wenn Sie nun die Betriebssystementwicklung lernen wollen, ist das eine andere Geschichte. Da ein PC im 16-Bit-Modus gestartet wird, müssen Sie mindestens so viel lernen, dass Sie den flachen 32-Bit-Modus aktivieren können.

Gerade bemerkt, dass Sie auch über Real-Modus vs Protected-Modus gefragt. Der Real-Modus ist der von MS DOS verwendete Modus. Jedes Programm hatte Zugang zu jeder Hardware-Funktion, zum Beispiel war es üblich, direkt mit dem Controller der Grafikkarte zu sprechen, um etwas zu drucken. Es verursachte kein Problem, weil es kein Multitasking-Betriebssystem war.

Aber auf jedem modernen Betriebssystem greifen normale Programme nicht direkt auf Hardware zu, sie greifen nicht einmal direkt auf den Speicher zu. Das Betriebssystem verwaltet die Hardware und entscheidet, welcher Prozess auf dem/den Prozessor (en) ausgeführt wird. Es verwaltet auch einen virtuellen Adressraum für jeden Prozess. Diese Art von Funktion ist im Protected-Modus verfügbar, von dem ich glaube, dass er mit dem 386 kam, dem ersten 32-Bit-Prozessor für PCs.

+0

+1 für detaillierte Antwort! –

+0

So ist die segmentierte Speicheradressierung wie eine Formel, die in ein 16-Bit-Register passt und die Adresse aus dem Speicher definiert, die größer als die Registerkapazität ist. Ein PC startet im 16-Bit-Adressierungsmodus bedeutet, dass das BIOS keine 32-Bit-Adresse lesen kann? Vielen Dank! – ali

+0

@ali: Ich weiß nicht, wie BIOS implementiert sind.Technisch denke ich, dass nichts ein BIOS daran hindert, zu 32 Bits zu wechseln und dann zu 16 Bits zurückzukommen, wenn es aus irgendeinem Grund wirklich benötigt wird. –

8

Befehle, die auf etwas zugreifen, das eine Adresse verwendet (Speicher, E/A, speicherkontierte E/A usw.) liefern manchmal die vollständige Adresse (aus der Perspektive der Prozessorausführungsschicht), manchmal bieten sie einen Offset. Ihre nahen oder relativen Sprünge zum Beispiel der Programmzähler ist die Basisadresse und der Befehl liefert einen Offset zu dieser Basis, addiert die zwei zusammen und Sie erhalten die Adresse (auf dieser Ebene).

Nehmen Sie ein 16-Bit-System mit 16-Bit-Registern und einem maximalen Adressraum von 64 KByte. Eine sehr einfache Möglichkeit, diesen Speicher zu erweitern, ist das Segmentieren. Anstelle des Registers, das die gesamte Adresse enthält, enthält das Register in Ihrem Befehl einen Offset zu einer Basis, ähnlich wie bei einer pc-relativen Anweisung. Außer in diesem Fall gibt es noch ein anderes Register, das als Basisadresse verwendet wird. Sie sehen dies in einer Reihe von Architekturen, die ihren Adressbereich leicht erweitern wollten, ohne zu viel, wenn überhaupt Änderungen am Kern vorzunehmen. (kann im Speichercontroller ohne Änderung des Kerns getan werden) Im Fall des x86 gab es ein paar Register. Einer wurde verwendet, um die Reichweite der Ausführung, Zweige zu erweitern. Eine weitere Möglichkeit, die Reichweite von Datenzugriffen zu erweitern, zu laden und zu speichern. Die Adresse einer nicht-pc-relativen Verzweigung wurde unter Verwendung des um 4 Bits nach links verschobenen Codesegments berechnet und dann zu dem in der Anweisung spezifizierten Register addiert. Für Ladungen und Speicher, die nicht pc-relativ sind, wurde das Datensegmentregister verwendet, Verschiebung nach links 4 füge das in der Anweisung spezifizierte Register hinzu. Wenn Sie zum Beispiel 0x123456789 adressieren möchten, könnte das Segmentregister 0x12340000 enthalten und das für die Adressierung verwendete Register 0x56789 enthalten, oder das Segment 0x12345678 und das gpr enthalten 0x9. PC relative Adressierung ist natürlich Segment + PC + Offset.

Dies führte zur Übernahme verschiedener Speichermodelle. klein, klein, mittel, groß, riesig. Sie können sich vorstellen, dass das kleinste Modell die Regel haben oder annehmen würde, dass im Fall von x86 alles innerhalb eines 64K-Speicherplatzes liegt, der Compiler und Ihr Code sich nie um Segmentregister kümmern müssen. Für größere Modelle oder wenn Sie einen weiter entfernten Fernzeiger verwenden, ist das kein großes Problem, Sie legen das Datensegment fest, legen dann den Datenoffset fest und führen das Laden oder Speichern durch. Bei Code könnte man es sich etwas schwerer vorstellen, denn sobald man das Code-Segmentregister ändert, wirkt sich dies auf die Gesamtadresse aus, an die man Befehle holt. Vielleicht möchten Sie eine Hardware-Lösung, die es einer Verzweigung erlaubt, sowohl Segment als auch Offset zu modifizieren, oder Sie können dies im Code tun (wenn die Hardware erlaubt ist). Ich werde dich jetzt nicht mit dem verwechseln.

Jedes Mal, wenn Sie einen Array im Code haben:

unsigned char abc[123]; 

, die im Grunde das gleiche ist. Die Basisadresse, die Adresse, an der das Array im Speicher startet, ist wie Ihr Segment und der Index ist Ihr Offset. Wenn in obigem abc die Adresse 0x1004 war, dann ist abc [5] an Adresse 0x1004 + 5 = 0x1009. Nicht verschoben wie das x86-Segment: Offset-Adressierung, aber das gleiche Konzept des Hinzufügens der Basis und des Offsets. Einige segmentierte Architekturen, die Sie nicht hinzufügen, einige Bits in irgendeinem Register sind die oberen Bits. Nehmen Sie Adresse 0x12345 auf einem dieser Systeme 0x1 muss im Segment und 0x2345 in der 16-Bit-gpr sein. Sie können es sich als eine Verschiebung vorstellen und hinzufügen, wenn Sie möchten, aber im Gegensatz zum x86-Segment: Offset können Sie es auch als Verschiebung und oder betrachten.

Flacher Speicherplatz ist ein bisschen eine Illusion, vor allem in x86-Systemen. x86 Computer, 32 Bit und sogar viele 64 Bit, begrenzen die Menge des flachen Speicherplatzes für Plug-in-Karten auf insgesamt 1 Gig, macht sehr viel Sinn für ein 32-Bit-System, wo Sie 4 Gig-Adressraum insgesamt haben, und ist, warum einige von ihnen geben Sie eine 3-Gig Limit, oder geben Sie die Illusion von 4 Gig, aber haben einige davon für die Plug-in-Karten gehackt. (Viele Ihrer Motherboard-Elemente sind in diesem Raum sowie die tatsächlichen Plug-in-Karten). Abhängig von der Grafikkarte und der Auflösung usw. können Sie manchmal nicht den gesamten Framepuffer in die Teilmenge dieses peripheren Bereichs einfügen, daher müssen Sie Ihren Zugriff segmentieren. Das Bios hat Ihnen möglicherweise die Adresse 0x80000000 als Basis im x86-Adressraum zugewiesen. In einem anderen Register der Videokarte geben Sie die Adresse im Adressbereich der Grafikkarte an. Zu Demonstrationszwecken sagen wir, Sie hätten ein 16MByte-Fenster an der x86-Adresse 0x80000000 erhalten. 16 MByte ist 0x01000000. Wenn Sie auf die Adresse 0x04321888 im Videospeicher zugreifen möchten, können Sie sich vorstellen, ein Segmentregister in der Grafikkarte auf 0x04 zu setzen, dann im x86-Adressraum (der auch pci (e) ist) die Adresse 0x80321888.

Die Quintessenz hier sind einige Bits von hier und einige Bits von dort, setzen sie zusammen und das ist die Adresse am Ziel. Wenn Sie mit Peripheriegeräten arbeiten, sei es eine Videokarte oder die integrierten E/A-Controller oder PCI- oder PCE-Controller, müssen Sie lernen, in Bezug auf den Zieladressraum zu denken. Der Prozessor verfügt über einen Adressraum aus der Perspektive Ihres Programms. Die mmu kann und scramble das in einen physischen Adressraum, dann haben Sie Ihren PCE-Adressraum und dann haben Peripheriegeräte, auf die pcie zugreift, ihren eigenen Adressraum. Was Intel und die Intel-basierte PC-Welt getan haben, macht den physischen Adressraum der Prozessoren und den Adressraum der pcie gleich. Die virtuelle vs physische Verschlüsselung in der MMU ist immer noch da, und das Fenster in den Adressraum der Peripherie ist immer noch da, du musst noch ein wenig Adresse von hier und ein wenig von dort nehmen, um die letzte Adresse bei welchem ​​Ziel zu bekommen.

Wirklich und geschützt hat mit Zugang zu tun. In C zum Beispiel können Sie Zeiger erstellen, die Zeiger ändern und die gewünschte Adresse erstellen. Bedeutet das nicht, dass Sie in einem anderen Anwendungsspeicher oder im Speicher des Kernels herumstochern können?Idealerweise wollen Sie dies nicht so für jede Anwendung tun, wenn Sie Anweisungen für diese Anwendung ausführen, sind Sie in einem Stück einer virtuellen Maschine, jeder Speicherzugriff, sei es Code oder Anweisung durchläuft einen Filter, wenn Sie so wollen. Dieser Filter überprüft, ob dieser Zugriff innerhalb des erlaubten Speicherplatzes für Programme liegt. Wenn er außerhalb dieses Speicherplatzes eine Ausnahme passiert (denke Interrupt), erlaubt diese Ausnahme dem Kernel (der diese Einschränkungen nicht hat oder andere Einschränkungen hat), diesen Zugriff zuzulassen oder vielleicht einen Zugriff auf etwas virtualisieren oder eine Warnung für den Benutzer auslösen (Allgemeiner Schutzfehler). Nehmen Sie zum Beispiel ein virtuelles Programm wie VMware, erlauben Sie dem virtualisierten Programm, Anweisungen auf dem Prozessor auszuführen, wenn das virtualisierte Programm auf die Adresse der Grafikkarte zugreift, ein Schutzfehler auftritt, der VMware-Treiber/-Anwendung (think kernel level) nimmt diese Adresse und täuscht die Reaktion der Videokarten vor und gibt die Kontrolle an die Anwendung zurück. Das Ausführen von Anweisungen auf dem Metall ermöglicht eine viel schnellere Virtualisierung der Alternative, um jeden Prozessorbefehl zu simulieren. Das ist der Extremfall, sogar der Webbrowser, den Sie gerade lesen, wurde virtualisiert, so dass er denkt, dass er über einen Speicherplatz verfügt, der auf einer Basisadresse wie 0x000 oder 0x8000 basiert. Sie kompilieren jedes Programm für ein bestimmtes Betriebssystem flacher virtueller Speicherplatz und das Betriebssystem kümmert sich darum, die Adressen von virtuell auf physikalisch zu ändern. Der Zugriff Ihres Webbrowsers auf die Adresse 0x8000 könnte physisch 0x12345678 sein, und der Zugriff Ihres MP3-Player-Programms 0x8000 könnte physisch 0x2345678 sein, aber für beide Anwendungen berechnen die Anweisungen 0x8000.

Fragen, was das Beste ist, ist immer ein relativer Begriff, eine Person ist am besten eine andere Person am schlechtesten. Sie müssen am besten von sich selbst am schlechtesten definieren. Das Momentum und die öffentliche Meinung haben x86 in den flachen Speicherraum oder zumindest die Illusion von flachem Speicherplatz aus der Perspektive der Programmierer getrieben, so dass Sie mit dem Fluss weniger Probleme haben werden.

Ich empfehle, eine Kopie der 8086/8088 Programmierer und Hardware-Referenz Handbuch, kann man für ein paar Dollar bekommen.

http://www.amazon.com/Manual-Programmers-Hardware-Reference-240487-001/dp/1555120814/ref=sr_1_1?ie=UTF8&qid=1340000636&sr=8-1&keywords=8088+programmers+reference

einen Simulator wie pcemu nehmen (ich zu diesem Zweck einen Klon haben http://github.com/dwelch67/pcemu_samples) und mit dem Befehlssatz, der alten Schule und zurück, bevor Virtualisierung, Schutz usw. spielen, wenn Sie als berechnet Segmente und Offsets hatte Wie oben beschrieben, verschieben Sie das Segment links vier und addieren Sie den Offset (alles in diesem Handbuch beschrieben). Seither hat jede Generation versucht, etwas zu verbessern, während sie versucht, rückwärtskompatibel zu sein. Was natürlich den Gewinnen geholfen hat, aber die Prozessoren in fiese Bestien verwandelt hat. Du solltest besser x86-Details vergessen und ein paar sauberere Systeme lernen. Aufgrund der Weiterentwicklung von x86 wirst du minimale Gewinne haben, indem du zum Beispiel versuchst, etwas in asm über kompiliertem Code zu schreiben. Da Prozessoren aus verschiedenen Familien den gleichen Code mit unterschiedlichen Geschwindigkeiten ausführen, führt die neue Generation häufig manuell abgestimmten Code vom Vorgänger mit einer viel langsameren Rate aus. Sie können nicht etwas tun, um auf allen Plattformen schnell zu sein, nicht schneller als der Compiler, also lassen Sie einfach x86-Asm-Code an die Compiler. Arbeiten Sie auf vernünftigen Plattformen, wo Sie diese Probleme nicht haben und tunen können, wenn Sie mögen oder einen besseren Compiler, etc.