Lowlevel

Lowlevel => OS-Design => Thema gestartet von: erik.vikinger am 14. July 2009, 22:11

Titel: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 14. July 2009, 22:11
Hi @all,


ich bin vor ein paar Tagen auf diese interessante Seite gestoßen und möchte mal ein spezielles Thema diskutieren.


Ich will ein OS mit Segmentierung, ähnlich der des 386 im PM, implementieren.
(aber auf einer anderen Plattform welche Segmentierung sehr gut unterstützt, ob es auch einen 386-Port geben wird weis ich noch nicht)


Ich möchte das OS als Microkernel implementieren. In diesen Microkernel sollen nur die Speicherverwaltung, der Scheduler, das Process/Thread-Management, IPC-Mechanismen, Message-Pipes und ein simples Timing-System integriert werden. (das meiste davon habe ich vor einigen Jahren schon mal als Kooperatives Multithreading auf Basis des TNT-DOS-Extender in Assembler für 386-32Bit-PM implementiert, dieses Framework nutze ich heute noch gerne wenn ich mal ein sehr Hardwarenahes Programm für den PC schreiben muss und auf kein bestimmtes OS angewiesen bin)


Segmentierung bringt zwar einige Vorteile aber auch ein paar Nachteile.


Ein großer Nachteil ist natürlich das kein heute üblicher Compiler Segmentierung, also FAR-Pointer, unterstützt. Unter DOS benutze ich den Open-Watcom, dieser unterstützt zwar auch im 32Bit-PM FAR-Pointer aber mit einer ziemlich umständlichen Syntax und (was noch viel schlimmer ist) ohne Optimierungen. Für die Zielarchitektur gibt es eh noch keinen C-Compiler also werde ich sowieso die Mühe haben ein Target für den gcc zu entwickeln, so weit wie ich bis jetzt in den gcc-Source-Code hinein gesehen hab sollte es möglich sein eine vernünftige Unterstützung für FAR-Pointer zu implementieren.

Ein interessanter Vorteil der Segmentierung ist das man aufs Paging verzichten kann, falls der physische Speicher ausreicht, und man damit einen gewissen Performance-Vorteil bekommt durch das wegfallen der Adress-Umsetzung von virtual nach physisch bei jedem Speicherzugriff. Wenn man dann doch das Paging anschalten muss, zwegs Swapping, kann man mit nur einer Page-Table für alle Prozesse auskommen (da die Prozesse ja eh über verschiedene Segmente, aus verschiedenen LDTs, separiert sind) und damit das Prozess-Kontext-Umschalten nicht durch blöde TLB-Flushs ausgebremst wird.

Auch für shared Memory als IPC bietet Segmentierung einen Vorteil. Mann könnte ein spezielles Segment erstellen das beiden Prozessen zugänglich ist, innerhalb dieses Segments währen sogar NEAR-Pointer für alle teilnehmenden Prozesse gültig.

Die Speicherverwaltung ist bei Segmentierung etwas komplizierter da man als erstes den linearen Speicher, für die Segmente, verwalten muss und zusätzlich noch den physischen Speicher fürs Swapping. Dafür gibt es IMHO keinen Bedarf zusammenhängenden physischen Speicher zu allozieren, das reduziert eventuell die Komplexität der Verwaltung des physischen Speichers.


Welche Nachteile, oder auch Vorteile, seht Ihr für ein OS das ganz auf Segmentierung setzt?

Als "ähnliche" Plattform kann ruhig der 32Bit-PM des 386 gelten, meine Zielplatform hat vor allem deutlich mehr Register (auch mehr Segment-Register) und eine konsequent auf Segmentierung ausgerichtete Architektur (z.B. die Shadow-Register für die Segmente lassen sich einfach manipulieren und das globale Paging wird in Hardware synchron zwischen den CPUs gehalten).


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: kevin am 14. July 2009, 22:37
Spannendes Thema, ich streue einfach mal ein paar Gedanken ein. Und willkommen im Forum natürlich erstmal. :)

Ich will ein OS mit Segmentierung, ähnlich der des 386 im PM, implementieren.
(aber auf einer anderen Plattform welche Segmentierung sehr gut unterstützt, ob es auch einen 386-Port geben wird weis ich noch nicht)
Was für eine Plattform ist es denn? Oder ist es nichts öffentlich zugängliches? Du schreibst zwar oft "ähnlich zu i386", aber am Ende willst ja nicht wissen, wie man es auf i386 am besten machen würde. Und wir wollen ja auch was neues lernen. ;)

Zitat
Ein großer Nachteil ist natürlich das kein heute üblicher Compiler Segmentierung, also FAR-Pointer, unterstützt. Unter DOS benutze ich den Open-Watcom, dieser unterstützt zwar auch im 32Bit-PM FAR-Pointer aber mit einer ziemlich umständlichen Syntax und (was noch viel schlimmer ist) ohne Optimierungen.
An dieser Stelle stellt sich die Frage, wofür du die Segmente denn tatsächlich einsetzen willst. Wenn ich mal von der i386-Basis aus denke, würde ich Segmente in erster Linie wohl dazu benutzen, Programme an die richtige virtuelle Speicheradresse zu schieben - aber es dann trotzdem bei einem Segment pro Programm belassen. In diesem Fall bräuchte man sich nicht viele Gedanken darüber machen. In die DOS-Zeiten, wo man sich beim Programmieren von Anwendungen ständig mit der Segmentierung rumschlagen musste, würde ich jedenfalls nicht zurückwollen.

Zitat
Für die Zielarchitektur gibt es eh noch keinen C-Compiler also werde ich sowieso die Mühe haben ein Target für den gcc zu entwickeln, so weit wie ich bis jetzt in den gcc-Source-Code hinein gesehen hab sollte es möglich sein eine vernünftige Unterstützung für FAR-Pointer zu implementieren.
Oha. Das wird nicht ganz trivial werden, nehme ich an. Insofern wirst du wohl erstmal einen ganzen Haufen Zeit hier reinstecken, bevor du dir überhaupt Gedanken um das OS machen brauchst.

Zitat
Ein interessanter Vorteil der Segmentierung ist das man aufs Paging verzichten kann, falls der physische Speicher ausreicht, und man damit einen gewissen Performance-Vorteil bekommt durch das wegfallen der Adress-Umsetzung von virtual nach physisch bei jedem Speicherzugriff.
Hm, ich glaube kaum, dass das in Sachen Performance groß was rausreißt. Abgesehen davon will man nicht auf eine MMU verzichten, wenn man sie haben kann. Mit Segmentierung kommst du möglicherweise mit einem einzigen Kontext weg (kommt drauf an, ob der virtuelle Adressraum groß genug ist), aber du willst nicht darauf verzichten, virtuellen Speicher dynamisch zuteilen zu können. Ansonsten müssen Programme entweder beim Start den maximalen Speicher bekommen oder mit nichtlinearem Speicher zurechtkommen. Beides klingt für mich nicht gerade optimal.

Zitat
Auch für shared Memory als IPC bietet Segmentierung einen Vorteil. Mann könnte ein spezielles Segment erstellen das beiden Prozessen zugänglich ist, innerhalb dieses Segments währen sogar NEAR-Pointer für alle teilnehmenden Prozesse gültig.
Das ist jetzt aber nicht wirklich ein Vorteil von Segmentierung, das kriegst du mit Paging genauso hin. Und weil du Paging sowieso haben willst (siehe oben), würde ich es hier auch tatsächlich einsetzen, damit es bei einem Segment pro Prozess bleibt. Alternative wäre, IPC in eine in Assembler geschrieben Bibliothek zu kapseln (angenommen, man möchte den Aufwand vermeiden, dem C-Compiler Segmente beizubringen).

Zitat
Dafür gibt es IMHO keinen Bedarf zusammenhängenden physischen Speicher zu allozieren, das reduziert eventuell die Komplexität der Verwaltung des physischen Speichers.
Zusammenhängenden physischen Speicher braucht man immer wenn es um Hardware geht, also DMA. Darum wirst du auch mit Segmentierung nicht herumkommen. Es sei denn natürlich, deine Plattform kennt kein DMA - aber dann braucht man auch ohne Segmentierung keinen zusammenhängenden physischen Speicher.

Außer wenn du auf Paging verzichtest, dann brauchst du praktisch für alles physisch zusammenhängenden Speicher. Aber dass ich das für eine schlechte Idee halte, habe ich ja schon gesagt.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 15. July 2009, 07:39
Hallo,


Zitat
Spannendes Thema,
:-D
Zitat
ich streue einfach mal ein paar Gedanken ein.
Darum hab ich das Thema ja zur Sprache gebracht.
Zitat
Und willkommen im Forum natürlich erstmal.
Danke!

Zitat
Was für eine Plattform ist es denn? Oder ist es nichts öffentlich zugängliches?
Diese Platform ist noch nicht öffentlich zugänglich. Es handelt sich um eine Soft-CPU welche auf einem FPGA läuft.


Zitat
... wie man es auf i386 am besten machen würde.
Nein, es geht mir eher um Grundsätzliche Dinge. Alles was auf meiner Zielplatform geht kann man auch mit einem 386 machen nur einiges nicht so effizient.


Zitat
An dieser Stelle stellt sich die Frage, wofür du die Segmente denn tatsächlich einsetzen willst
Zur Speicherseparierung für die einzelnen Prozesse. Jeder Prozess wird beim Start 5 Segmente bekommen (Code, Stack(für den ersten Thread), Data, Const und Heap(ist erst mal leer)).

Zitat
In die DOS-Zeiten, wo man sich beim Programmieren von Anwendungen ständig mit der Segmentierung rumschlagen musste, würde ich jedenfalls nicht zurückwollen.
Was war denn an den Segmenten unter DOS so schlimm? Von der Beschränkung auf 64kBytes mal abgesehen. Ich habe auch viel im reinen DOS, im RM, programmiert und man hat es meinem C-Code nur sehr selten angesehen das er für DOS ist. Es gibt wegen der blöden Überlappung der Segmente zwar ein paar Stolperfallen wenn man den Adress-Modus "HUGE" benutzt aber ansonsten kann ich mich nicht an ernsthafte Schwierigkeiten erinnern.

Zitat
Hm, ich glaube kaum, dass das in Sachen Performance groß was rausreißt.
Das 4-Stufige Paging des Long-Mode soll angeblich etwa 10 bis 15 Prozent Performance kosten. Da mann das Paging im Long-Mode nicht abschalten kann kann man das natürlich kaum überprüfen. Aber "etwas" Performace kostet es auf jeden Fall.


Zitat
Mit Segmentierung kommst du möglicherweise mit einem einzigen Kontext weg (kommt drauf an, ob der virtuelle Adressraum groß genug ist),
Ja, alle Programme teilen sich den linearen Adressraum, der auf 32Bit-Systemen "nur" 4GByte groß ist. Auf einer richtigen 64Bit-Architektur ist das aber auf absehbare Zeit kein Problem.

Zitat
aber du willst nicht darauf verzichten, virtuellen Speicher dynamisch zuteilen zu können.
Wieso sollte das nicht mehr gehen? Wenn ein Programm "malloc()" aufruft schaut dies ob im Heap-Segment noch Platz ist und wenn nicht wird das Segment vom OS angemessen vergrößert und da die Programme nicht wissen wo ihre Segmente im linearen Adressraum liegen kann das OS diese auch jederzeit verschieben und gar defragmentieren. Ich sehe da kein Problem nur Arbeit.


Zitat
Das ist jetzt aber nicht wirklich ein Vorteil von Segmentierung, das kriegst du mit Paging genauso hin.
Nicht wenn der gewünschte virtuelle Adressraum in einem der Prozesse bereits mit was anderem belegt ist. Und da dieser Prozess sicher irgendwo bereits einen Pointer auf dieses andere hat kann man es auch nicht mehr verschieben um Platz zu schaffen.


Zitat
Zusammenhängenden physischen Speicher braucht man immer wenn es um Hardware geht, also DMA.
Alle mir bekannte Hardware kann ihre Daten auch in mehreren verteilten Stücken in den physischen Speicher schreiben. Ich glaube das meint man mit "Scatter/Gatter".


Mir ist noch eingefallen das Memory-Mappen-File-I/O von der Segmentieren profitieren könnte. Man erstellt einfach ein Segment mit der Größe der Datei und das Programm kann ganz normal drauf rumackern und das OS kümmert sich per Paging darum das alles funktioniert. Natürlich muss auch hierfür der lineare Adressraum groß genug sein.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: Jidder am 16. July 2009, 22:16
Ich finde der größte Nachteil am segmentierten Speichermodell ist, dass es zwei Arten von Zeigern gibt. Du kannst ja near pointer und far pointer nicht einfach so mischen. Bei jeder API, jeder Datenstruktur und jedem Algorithmus, der darauf operieren soll, musst du vorher festlegen welche Art von Zeigern sie nutzen.

Man kann auch nicht einfach pauschal far pointer für alles nehmen. Ganz ohne Overhead sind die ja nicht. Allein weil sie mindestens 2 Bytes (oder wieviel auch immer) größer als near pointer sind und damit evtl. auch größer als der Datenbus.


Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 17. July 2009, 08:20
Hallo,


Zitat
Ich finde der größte Nachteil am segmentierten Speichermodell ist, dass es zwei Arten von Zeigern gibt. ...
Ja das stimmt. Deswegen sollte man IMHO für alles FAR-Pointer nehmen und NEAR-Pointer sind nur für den internen Gebrauch des Compilers geeignet, z.B. bei lokalen Variablen auf dem Stackframe oder bei globalen Variablen im Data-Segment.


Zitat
Ganz ohne Overhead sind die ja nicht. ....
Auf einer entsprechend ausgestatteten Plattform ist das kein allzu großes Problem. Der Performanceverlust ist IMHO auf jeden Fall kleiner als bei Paging.

Ein Beispiel :
Funktion int printf(const char* text,.....);müsste denn Pointer bereits in einem Segmentregister und einem normalen Register übergeben bekommen (per ABI so definiert) und der Compiler kann sämtliche Speicherzugriffe auf 'text' über das bestimmte Segment laufen lassen und es würde daher in 'printf()' kein einziger zusätzlicher Befehl oder CPU-Takt für die Segmentierung benötigt. Das geht bei 386 eben nicht da es dort schon an einer ausreichenden Anzahl an Segmentregistern mangelt und diese (vor allem FS und GS) auch nur äußerst lieblos in den Befehlssatz (siehe MOVS, LODS und STOS) integriert sind. Als ich mal ein größeres Programm für einen 80186 entwickelt hatte hab ich mir oft das Listing angeschaut und es war leider so das der Compiler gezwungen war für fast jeden zweiten Speicherzugriff ein Segmentregister (also DS oder ES) zu laden. Mit nur zwei, einigermaßen frei benutzbaren, Segmentregistern kommt kein Compiler auf guten Code. Auch ein fähiger Assemblerprogrammierer (und ich behaupte einfach mal ich bin einer) kann das nicht spürbar besser lösen. Auf meiner Wunsch-Ziel-Plattform sind 16 Segmentregister vorhanden wovon dem Programmierer/Compiler etwa 10 frei zur Verfügung stehen. Auch lassen sich alle Speicherzugriffe und alle Zugriffsarten über alle Segmentregister benutzen. Zusätzlich sind noch ein paar weitere Optimierungen in Hardware integriert, z.B. muss die CPU keinen Zugriff auf die Descriptor-Tabellen durchführen wenn das gewünschte Segment bereits in einem der anderen Segmentregister zur Verfügung steht und das dürfte sehr oft vorkommen da Pointer ja für gewöhnlich nur auf den Heap, das Data-Segment oder den Stack zeigen (natürlich lässt sich das abschalten damit das OS auch bewusst einen neuen Descriptor laden kann).

Fakt ist das dieses Konzept eine gute Unterstützung durch den Compiler benötigt um sauber und ohne Performanceeinbußen zu funktionieren.
Dann hat man auch etwas von den Vorteilen wie z.B. 100%-tigem Schutz gegen Code-Injectionen per Buffer-Overflow o.ä. oder flexible unbegrenzte Stacks.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 07. August 2009, 14:38
Hallo,


entschuldigt bitte das ich noch mal störe.

Kennt jemand ein Executable-File-Format das Segmentierung unterstützt?
Mir fällt da nur die NE-EXEs von WIN16 ein. Gibt es da noch was anderes das man als Inspirationsquelle nutzen kann?


Zitat
Zitat
In die DOS-Zeiten, wo man sich beim Programmieren von Anwendungen ständig mit der Segmentierung rumschlagen musste, würde ich jedenfalls nicht zurückwollen.
Was war denn an den Segmenten unter DOS so schlimm?

Schade das dazu nichts weiter gesagt wurde. Würde mich wirklich interessieren welcher Art die Probleme waren. Vielleicht kann ich die ja bei meinem Anlauf vermeiden.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: DerHartmut am 07. August 2009, 14:59
Zitat
entschuldigt bitte das ich noch mal störe.

Also bitte, hier stört niemand, erst recht keiner mit gescheiten Fragen ;)

Also mir fallen da auch nur die NE-EXEs ein...
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 10. August 2009, 19:30
Hallo,


Zitat
Also mir fallen da auch nur die NE-EXEs ein...
Bei MS gibts immerhin eine knappe Dokumentation, als Anhaltspunkt was ich mindestens benötige sollte das taugen.
Danke für Deine Antwort.


Zitat
erst recht keiner mit gescheiten Fragen
Ich habe nicht den Eindruck das "Segmentierung" in die Kategorie "gescheite Fragen" gehört. Ich hab schon viele Leute darauf angesprochen und alle haben mir unisono erklärt das Segmentierung Teufelswerk ist. Bei der Frage warum kam, ebenfalls übereinstimmend, entweder Schulter zucken oder gar nichts. Manche haben sich immerhin noch an die 64k-Grenze erinnert und sind dann nach meinem Hinweis auf mein Ziel einer reinrassigen 32/64 Bit Architektur verstummt. Ist hier offensichtlich nicht anders.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: kevin am 10. August 2009, 19:44
Ich denke es liegt eher daran, dass Segmentierung einfach etwas unüblich ist (auf x86 will man nicht auf Paging verzichten und mit Paging gibt es nur noch wenige Gründe für Segmentierung). Insofern hat damit niemand richtig viel Erfahrung, sondern höchstens theoretisches Wissen und dunkle Erinnerungen aus DOS-Zeiten.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 10. August 2009, 21:24
Hallo taljeth,


auf die Gefahr hin unverschämt zu werden.


Zitat
Insofern hat damit niemand richtig viel Erfahrung, sondern höchstens theoretisches Wissen und dunkle Erinnerungen aus DOS-Zeiten.
Ist das die Begründung für Sätze wie denn
Zitat
In die DOS-Zeiten, wo man sich beim Programmieren von Anwendungen ständig mit der Segmentierung rumschlagen musste, würde ich jedenfalls nicht zurückwollen.
??


Zitat
dass Segmentierung einfach etwas unüblich ist
Ich kenne auch keine andere Plattform, mit Marktbedeutung (noch nicht mal ohne), die Segmentierung wenigstens ähnlich gut unterstützt wie der 386-PM. Womit ich nicht sagen will das der 386 Segmentierung gut unterstützt trotzdem kann ihm da seit über 20 Jahren niemand das Wasser reichen.

Zitat
und mit Paging gibt es nur noch wenige Gründe für Segmentierung
Also mir würde da zuverlässiger Speicherschutz einfallen. Um der Code-Injektion durch Bufferoverflows auf dem Stack/Heap entgegenzuwirken hat sich Intel die umständliche Krücke "NX-Bit" ausgedacht und diese dann ans Paging drangefummelt. Von seiner einstigen Kernkompetenz, die "virtuelle Speichermehrung", hat sich das Paging auf heutigen CPUs recht weit entfernt.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: kevin am 10. August 2009, 21:47
Zitat
Insofern hat damit niemand richtig viel Erfahrung, sondern höchstens theoretisches Wissen und dunkle Erinnerungen aus DOS-Zeiten.
Ist das die Begründung für Sätze wie denn
Zitat
In die DOS-Zeiten, wo man sich beim Programmieren von Anwendungen ständig mit der Segmentierung rumschlagen musste, würde ich jedenfalls nicht zurückwollen.
Du willst jetzt nicht ernsthaft anfangen, die Segmentierung im Real Mode für vergnügungssteuerpflichtig zu erklären? Im Protected Mode sieht die Welt zugegebenermaßen schon wieder ganz anders aus, und an dem willst du dich ja eher orientieren, wenn ich das richtig verstanden habe.

Zitat
Ich kenne auch keine andere Plattform, mit Marktbedeutung (noch nicht mal ohne), die Segmentierung wenigstens ähnlich gut unterstützt wie der 386-PM. Womit ich nicht sagen will das der 386 Segmentierung gut unterstützt trotzdem kann ihm da seit über 20 Jahren niemand das Wasser reichen.
Vermutlich will ihm da gar niemand das Wasser reichen. ;) Und mit x86_64 ist das ganze ja auch schon wieder vorbei.

Zitat
Zitat
und mit Paging gibt es nur noch wenige Gründe für Segmentierung
Also mir würde da zuverlässiger Speicherschutz einfallen. Um der Code-Injektion durch Bufferoverflows auf dem Stack/Heap entgegenzuwirken hat sich Intel die umständliche Krücke "NX-Bit" ausgedacht und diese dann ans Paging drangefummelt.
NX ist sicher nicht die Erfindung von Intel. x86_64 kommt immer noch von AMD, und schon davor hatte ungefähr jede andere ernstzunehmende Architektur so etwas ähnliches. Eigentlich ist es nur eine logische Erweiterung, ein Flag für beschreibbare Pages gab es schon immer, eins für ausführbare Pages ist dann nur konsequent.

Gehen wir einmal von aktuellen Prozessoren mit NX-Bit aus: Wo ist Segmentierung sicherer?

Zitat
Von seiner einstigen Kernkompetenz, die "virtuelle Speichermehrung", hat sich das Paging auf heutigen CPUs recht weit entfernt.
Also Swapping ist ungefähr das einzige an Paging, worüber ich noch nicht nachgedacht habe, es einzusetzen. ;)
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 11. August 2009, 08:37
Guten Morgen,


Zitat
Du willst jetzt nicht ernsthaft anfangen, die Segmentierung im Real Mode für vergnügungssteuerpflichtig zu erklären?
Nein, natürlich nicht, aber so schlimm wie sie oft dargestellt wird ist sie IMHO auch nicht.

Meine letzten DOS-RM Erfahrungen sind jetzt knapp 4 Jahre her. Auf einer kleinen Embedded-Schachtel mit einem 80186-Clone, sone Single-Chip-Lösung wo der ganze Basis-Chipsatz (PIC, DMA, UART u.s.w.) mit drin ist, und 512kByte RAM. Das schlimmste daran was das bescheidene ROM-DOS und die Binär-Bibliotheken (TCP/IP-Stack u.a.) die ich benutzen musste. Dafür hätte ich von meinem Arbeitgeber am liebsten Gefahrenzulage verlangt. Die Segmentierung hat zwar dafür gesorgt das der Compiler (Borland-C/C++) kaum effizienten Code generieren konnte aber meinem C/C++-Code hat man davon fast nichts angesehen. Der Umgang mit Pointern war völlig normal. Der meiste Code war sogar problemlos für Windows XP und später für ThreadX auf einem ARM7 lauffähig. Der bedeutendste Unterschied war das es unter DOS kein preemptives Multithreading gibt aber unter Windows XP und ThreadX schon.

Was nun so schlimm war an der Segmentierung unter DOS hast Du immer noch nicht erläutert.


Zitat
Im Protected Mode sieht die Welt zugegebenermaßen schon wieder ganz anders aus
Was ist im PM soviel anders? Die Segmente können größer sein, also keine 64k-Grenze und damit kein HUGE-Adress-Modus. Was mir Vorschwebt würde dem damaligem Large-Mode entsprechen, also ein (oder mehrere) Code-Segmente und mehrere Daten-Segmente also einzelne Funktionen und Daten-Objekte können sich nicht über mehrere Segmente verteilen. Und meine Segmente werden sich nicht überlappen (außer eventuell für spezielle Dinge).

Zitat
... und an dem willst du dich ja eher orientieren, wenn ich das richtig verstanden habe.
Ja.


Zitat
Vermutlich will ihm da gar niemand das Wasser reichen.
Doch, ich. :evil:
Zitat
Und mit x86_64 ist das ganze ja auch schon wieder vorbei.
Ja, leider.


Zitat
NX ist sicher nicht die Erfindung von Intel. ...
Ja, Du hast recht. Entschuldige bitte, das hätte ich vorher nachlesen sollen.
Zitat
Eigentlich ist es nur eine logische Erweiterung, ...
Stimmt.


Zitat
Gehen wir einmal von aktuellen Prozessoren mit NX-Bit aus: Wo ist Segmentierung sicherer?
Das Problem ist das es im Flat-Mode nur einen Adress-Raum gibt. Eine 32/64Bit-Zahl als Pointer interpretiert kann alles erreichen/modifizieren, jedes Stückchen Code, jede Verwaltungsstruktur und jede Constante. Und das nicht nur von Deinem eigentlichem User-Mode-Programm sondern auch von allen dynamisch dazugelinkten Librarys und eventuell auch Bereiche vom Kernel falls man auf einige Dinge aus Ring 3 zugreifen darf. Und da bei 386 keine Overflow/Underflow-Behandlung für Pointer existiert funktioniert das auch immer egal wo Du den Code, Daten und Kernel in den Adress-Raum reinlegst. Sicher wird auch mit Segmentierung ein Bufferoverflow passieren nur sind die daraus folgenden Konsequenzen deutlich eingeschränkter. Ich werde z.B. die Heap-Verwaltung in ein zusätzliches Segment legen und da nur malloc() und free() den Segmentselector kennen kann auch erstmal kein Schadcode darauf zugreifen, dieses Segment ist quasi versteckt. Außerdem gibt es auf meiner Plattform keinen Pointer-Overflow also 0x00300000 + 0xFFFFFFF0 zeigt nicht auf 0x002FFFF0 sondern löst eine Exception aus.


Zitat
Also Swapping ist ungefähr das einzige an Paging, worüber ich noch nicht nachgedacht habe, es einzusetzen. :wink:
Deshalb werde ich in meinem ersten Anlauf ganz auf Paging verzichten.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: kevin am 11. August 2009, 11:23
Die Segmentierung hat zwar dafür gesorgt das der Compiler (Borland-C/C++) kaum effizienten Code generieren konnte aber meinem C/C++-Code hat man davon fast nichts angesehen. Der Umgang mit Pointern war völlig normal.
Okay, akzeptiert. Du gibst die Drecksarbeit an den Compiler ab, was ja auch genau dessen Aufgabe ist. In diesem Fall bleibt bei dir natürlich nicht viel hängen.

Außer du musst erstmal den Compiler anpassen, aber das ist dir ja bewusst. ;)

Zitat
Was nun so schlimm war an der Segmentierung unter DOS hast Du immer noch nicht erläutert.

Zitat
Im Protected Mode sieht die Welt zugegebenermaßen schon wieder ganz anders aus
Was ist im PM soviel anders? Die Segmente können größer sein, also keine 64k-Grenze und damit kein HUGE-Adress-Modus.
Ja, in erster Linie sind es die fixen 64k, die mich stören, und die dafür sorgen, dass man Zeug auf mehrere Segmente aufteilen muss, auch wenn man es gar nicht will.

Zitat
Das Problem ist das es im Flat-Mode nur einen Adress-Raum gibt. Eine 32/64Bit-Zahl als Pointer interpretiert kann alles erreichen/modifizieren, jedes Stückchen Code, jede Verwaltungsstruktur und jede Constante. Und das nicht nur von Deinem eigentlichem User-Mode-Programm sondern auch von allen dynamisch dazugelinkten Librarys und eventuell auch Bereiche vom Kernel falls man auf einige Dinge aus Ring 3 zugreifen darf.
Richtig. Nur... ist das bei Segmentierung anders? Du hast gesagt, du willst grundsätzlich Far-Pointer nehmen. Dann ist das ganze Zeug eben nicht über eine 32-Bit-Zahl, sondern über eine 48-Bit-Zahl erreichbar. So what? Das einzige, was hier schützt, ist bestimmte Zugriffe zu unterbinden (also die Flags für Segmente und/oder Pages richtig zu setzen - scheibbar, ausführbar, im Usermode sichtbar...).

Zitat
Ich werde z.B. die Heap-Verwaltung in ein zusätzliches Segment legen und da nur malloc() und free() den Segmentselector kennen kann auch erstmal kein Schadcode darauf zugreifen, dieses Segment ist quasi versteckt.
Man nennt dieses Konzept auch Security by Obscurity. ;) Und auch auf einem System, das keine Segmentierung benutzt, schreibt keiner der libc vor, wo sie ihre Datenstrukturen zur Heapverwaltung ablegt. Dort kann das also genauso "versteckt" werden.

Zitat
Außerdem gibt es auf meiner Plattform keinen Pointer-Overflow also 0x00300000 + 0xFFFFFFF0 zeigt nicht auf 0x002FFFF0 sondern löst eine Exception aus.
Das ist natürlich eine sinnvolle Sache. Geht aber wohl auch nur, wenn der Overflow direkt bei einem Zugriff passiert und nicht bei irgendwelcher Pointerarithmetik davor - dort ist es ja einfach nur eine Zahl.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: bluecode am 11. August 2009, 11:32
Das Problem ist das es im Flat-Mode nur einen Adress-Raum gibt. Eine 32/64Bit-Zahl als Pointer interpretiert kann alles erreichen/modifizieren, jedes Stückchen Code, jede Verwaltungsstruktur und jede Constante. Und das nicht nur von Deinem eigentlichem User-Mode-Programm sondern auch von allen dynamisch dazugelinkten Librarys und eventuell auch Bereiche vom Kernel falls man auf einige Dinge aus Ring 3 zugreifen darf.
Sonlange es nicht ausschließlich für den Kernelmode gemappt ist und solange schreiben darauf erlaubt ist. Es wird niemand Schreiben auf Code erlauben, insofern fällt das schonmal weg und alles andere ist auch mit Segmentation über Segment:Offset erreichbar, d.h. prinzipiell modifizierbar (siehe unten, Security by Obscurity).

Zitat
Und da bei 386 keine Overflow/Underflow-Behandlung für Pointer existiert funktioniert das auch immer egal wo Du den Code, Daten und Kernel in den Adress-Raum reinlegst. Sicher wird auch mit Segmentierung ein Bufferoverflow passieren nur sind die daraus folgenden Konsequenzen deutlich eingeschränkter.
Und warum sollen die eingeschränkter sein? Wenn jemand das Segment kennt, und raten ist bei 8192 (zumindest x86) nicht so schwer ist es auch damit vorbei. Das ist komplett Security by Obscurity und noch dazu schlechtere Obscurity (meine Einschätzung) als zB Address layout randomization (was nur über Paging geht).

Zitat
Ich werde z.B. die Heap-Verwaltung in ein zusätzliches Segment legen und da nur malloc() und free() den Segmentselector kennen kann auch erstmal kein Schadcode darauf zugreifen, dieses Segment ist quasi versteckt.
Huh? Wie soll denn das gehen. Wenn ich auf mein Datensegment zugreifen muss, dann muss ich doch sicherlich den Segmentselektor kennen (zumindest x86), insofern lässt sich das nicht auf malloc beschränken.


Zitat
Außerdem gibt es auf meiner Plattform keinen Pointer-Overflow also 0x00300000 + 0xFFFFFFF0 zeigt nicht auf 0x002FFFF0 sondern löst eine Exception aus.
hm? d.h. man kann keine Integerzahlen sinnvoll addieren, oder wie soll ich mir das vorstellen bzw. auf welcher Ebene wird denn diese Einschränkung umgesetzt? Im x86 pmode mit Paging kann man natürlich die Adresse berechnen, aber beim Zugriff kommt halt (wenn der Zugriff nicht gerechtfertigt ist) eine Exception.

Zitat
Zitat
Also Swapping ist ungefähr das einzige an Paging, worüber ich noch nicht nachgedacht habe, es einzusetzen. :wink:
Deshalb werde ich in meinem ersten Anlauf ganz auf Paging verzichten.
Das einzige wofür ich Segmentation noch für gerechtfertigt (auf x86) halte ist Thread local storage, das bekommt man mit Paging nicht hin. Alles andere ist gefixt worden (NX-Bit).
Der Vorteil von Paging ist halt, das es um einiges feinkörniger ist und eine weniger kaputte Speicherverwaltung im Kernel benötigt.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 11. August 2009, 13:16
Hallo,


Zitat
Du gibst die Drecksarbeit an den Compiler ab, ...
Ja selbstverständlich, wofür sollte ich sonst eine Hochsprache benutzen wenn nicht dafür das Architektur-Spezifische Eigenheiten vor mir verborgen werden.

Zitat
Ja, in erster Linie sind es die fixen 64k, ...
Dann bin ich ja beruhigt.
Zitat
dass man Zeug auf mehrere Segmente aufteilen muss, auch wenn man es gar nicht will.
Das sollte eigentlich ein guter Compiler mit dem Huge-Modus vor Dir verbergen. Ob der Borland-Compiler das kann weis ich nicht ich habe vor diesem Huge-Modus immer einen ehrfürchtigen Bogen gemacht. Mir ist schon bewusst das ohne ordentliche Compilerunterstützung die Hölle los ist, daher ist das einer der wichtigsten Zwischenschritte zu meinem Ziel.


Zitat
... Dann ist das ganze Zeug eben nicht über eine 32-Bit-Zahl, sondern über eine 48-Bit-Zahl erreichbar. So what?
FAR-Pointer werden nicht immer in voller Größe geladen, oft ist der Selector noch im Segment-Register drin. In meinem printf-Beispiel vom 17.07. würde nie ein Selector geladen. Damit ist die Angriffsfläche deutlich kleiner. Auch wenn eine Funktion Register auf dem Stack sichert, um sie selbst verwenden zu können, müssen Selector und Offset nicht nebeneinander liegen was wieder die Anzahl an Zugriffen erhöht, die benötigt werden um einen bestimmten Pointer unter zu schieben.


Zitat
also die Flags für Segmente und/oder Pages richtig zu setzen
Mit Paging lässt sich sicher ein ähnlich hoher Schutzgrad erreichen wie mit Segmentierung nur ist die Angriffsfläche, die ein typisches User-Programm bietet, deutlich kleiner.

http://www.heise.de/newsticker/meldung/64624
Das Tool, welches in der zweiten Hälfte des Artikels genannt wird, hätte auf einem System mit Segmentierung deutlich weniger Chancen was passendes zusammen zu suchen. Dazu kommt das ein Far-Pointer nicht mit einem einzigen Speicher-Zugriff manipuliert werden kann eben weil er größer ist als die native Word-Breite.


Zitat
Man nennt dieses Konzept auch Security by Obscurity.
Ja das stimmt, genau so wie Address layout randomization. Trotzdem ist es eine weitere Hürde die ein Angreifer überwinden muss.


Zitat
Geht aber wohl auch nur, wenn der Overflow direkt bei einem Zugriff passiert
Richtig, das dürfte aber die Regel sein.
Zitat
und nicht bei irgendwelcher Pointerarithmetik davor - dort ist es ja einfach nur eine Zahl.
Hier könnte der Compiler ja immerhin die Flags prüfen. Okay wer will schon diesen (sicherlich geringen) Performance-Verlust.


Zitat
noch dazu schlechtere Obscurity (meine Einschätzung)
Also ich schätze das anders ein. Es sind immerhin 15 Bit die erraten werden müssen. Das ist zumindes nicht schlechter als Address layout randomization.

Zitat
Address layout randomization (was nur über Paging geht)
Wieso sollte Address layout randomization nur mit Paging gehen? Niemand zwingt mich den Code an Offset 0 im Code-Segment beginnen zu lassen. Code sollte immer Positionsunabhängig sein.


Zitat
Zitat
Ich werde z.B. die Heap-Verwaltung in ein zusätzliches Segment legen und da nur malloc() und free() den Segmentselector kennen kann auch erstmal kein Schadcode darauf zugreifen, dieses Segment ist quasi versteckt.
Huh? Wie soll denn das gehen.
Damit ist gemeint das die Verwaltungsdaten für den Heap in einem anderen Segment liegen. Die normalen Userdaten bleiben natürlich im normalen Heap für den jeder den Selector kennt.


Zitat
Das einzige wofür ich Segmentation noch für gerechtfertigt (auf x86) halte ist Thread local storage, das bekommt man mit Paging nicht hin.
Wird das heutzutage überhaupt benutzt? Ich hab in meinem Konzept zwar Thread local storage vorgesehen aber weiß noch nicht ob ich es implementieren will.


Zitat
Der Vorteil von Paging ist halt, das es um einiges feinkörniger ist und eine weniger kaputte Speicherverwaltung im Kernel benötigt.
Das sind zwei Behauptungen die erstmal erklärt/bewiesen werden sollten. Insbesondere das Attribut "kaputt" ist mir nicht klar.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: MNemo am 11. August 2009, 16:03
Zitat
Ja, in erster Linie sind es die fixen 64k, ...
Dann bin ich ja beruhigt.
Was mich stört ist vor allem das überlappen der Segmente. Ist mein Bootsector Code jetzt bei 0x0000:7C00, 0x0350:4700 oder doch bei 0x07C0:0X0000? Alles das gleiche und dann doch irgendwie nicht.

Zitat
Zitat
Der Vorteil von Paging ist halt, das es um einiges feinkörniger ist und eine weniger kaputte Speicherverwaltung im Kernel benötigt.
Das sind zwei Behauptungen die erstmal erklärt/bewiesen werden sollten. Insbesondere das Attribut "kaputt" ist mir nicht klar.

Ohne Paging bist du darauf angewiesen, dass der Speicher den du für einen Task bzw. dessen Segmente brauchst, jeweils an einem Stück zur Verfügung steht, was nach kurzer zeit zu Problemen führen kann/wird, weil du zwar theoretisch genug freien Speicher hast, der aber nicht zusammenhängend ist und du kein Segment daraus basteln kannst.

Paging löst das Problem, weil es ermöglicht Physisch nicht zusammenhängende Speicherbereiche virtuell beliebig anzuordnen.

Als kaputt würde ich z.B. eine Implementierung bezeichnen die Bestehende Segmente im Speicher verschiebt um doch noch genügend große Speicherblöcke zu erhalten. Oder statt dessen das Verteilen von Zusammengehörigen Daten auf mehrere kleiner Segmente.

Und andere Lösungen fallen mir da jetzt nicht ein.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: bluecode am 11. August 2009, 16:53
Zitat
noch dazu schlechtere Obscurity (meine Einschätzung)
Also ich schätze das anders ein. Es sind immerhin 15 Bit die erraten werden müssen. Das ist zumindes nicht schlechter als Address layout randomization.
Nur weil es 15bit sind heißt das noch lange nicht, dass ich alle Bits erraten muss. Wenn ich den Algorithmus kenne, mit dem du deine Selektoren aussuchst, brauch ich sicherlich nicht so viele Bits zu erraten. Deine Selektoren sind ja auch nicht unabhängig von den Segmenten anderer Programme, bei address layout randomization ist aber die Anordnung in meinem Prozess komplett unabhängig von anderen Prozessen. Und bei einem 64Bit System kommen dann schon ein paar mehr Bits zusammen als 15 :wink:

Zitat
Zitat
Address layout randomization (was nur über Paging geht)
Wieso sollte Address layout randomization nur mit Paging gehen? Niemand zwingt mich den Code an Offset 0 im Code-Segment beginnen zu lassen. Code sollte immer Positionsunabhängig sein.
D.h. du willst Speicher bewusst verschwenden? Ich mein der Speicher zu Beginn des Segments muss ja physisch vorhanden sein, oder nicht?

Zitat
Zitat
Zitat
Ich werde z.B. die Heap-Verwaltung in ein zusätzliches Segment legen und da nur malloc() und free() den Segmentselector kennen kann auch erstmal kein Schadcode darauf zugreifen, dieses Segment ist quasi versteckt.
Huh? Wie soll denn das gehen.
Damit ist gemeint das die Verwaltungsdaten für den Heap in einem anderen Segment liegen. Die normalen Userdaten bleiben natürlich im normalen Heap für den jeder den Selector kennt.
Das wird dein System langsam machen, wäre meine Einschätzung, da eine Heapverwaltung extrem schnell von dem eigentlichen Pointer auf die Datenstrukturen kommen muss. Die trivialste Implementierung ist da halt, seine Heapverwaltungsdatenstrukturen vorne an den Speicherbereich hinzuhängen, dann kommt man mit einem sub <x> auf den Pointer aus.

Zitat
Zitat
Das einzige wofür ich Segmentation noch für gerechtfertigt (auf x86) halte ist Thread local storage, das bekommt man mit Paging nicht hin.
Wird das heutzutage überhaupt benutzt? Ich hab in meinem Konzept zwar Thread local storage vorgesehen aber weiß noch nicht ob ich es implementieren will.
Ja, es wird sogar in den nächsten C++ Standard kommen. Eventuell auch in den nächsten C Standard, aber da hab ich ehrlich gesagt keine Ahnung.

Zitat
Zitat
Der Vorteil von Paging ist halt, das es um einiges feinkörniger ist und eine weniger kaputte Speicherverwaltung im Kernel benötigt.
Das sind zwei Behauptungen die erstmal erklärt/bewiesen werden sollten. Insbesondere das Attribut "kaputt" ist mir nicht klar.
feinkörnig, da ich Flags auf 4k-Ebene setzen kann. Das ist in der Praxis (!) wohl einiges feinkörniger als Segmente.
Und kaputt hat MNemo ja bereits beschrieben, da fällt mir auch nicht mehr ein.

edit:
Zitat
http://www.heise.de/newsticker/meldung/64624 (http://www.heise.de/newsticker/meldung/64624)
Das Tool, welches in der zweiten Hälfte des Artikels genannt wird, hätte auf einem System mit Segmentierung deutlich weniger Chancen was passendes zusammen zu suchen.
Warum? Ich sehe das ehrlich gesagt nicht, aber ich hab kA von den Details der dort verwendeten Technik.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 11. August 2009, 19:51
Hallo,


Zitat
Alles das gleiche und dann doch irgendwie nicht.
Ja, dieses Phänomen kann ganz schön verwirren. Aber in diese Richtung will ich ja nicht.


Zitat
Ohne Paging bist du darauf angewiesen, dass der Speicher den du für einen Task bzw. dessen Segmente brauchst, jeweils an einem Stück zur Verfügung steht
Ja, das stimmt, ist aber kein unüberwindbares Problem.

Zitat
Als kaputt würde ich z.B. eine Implementierung bezeichnen die Bestehende Segmente im Speicher verschiebt um doch noch genügend große Speicherblöcke zu erhalten.
Warum? Das ist für mich gerade der Reiz. Durch die Verwendung der Segmente ist eine Live-Defragmentierung des linearen Adress-Raums keine Hexerei mehr. Genau das möchte ich implementieren. Wenn man dazu das Paging benutzt kann man das sogar beliebig langsam im Hintergrund laufen lassen und die Programme können davon nichts bemerken, noch nicht mal Performance-Einbußen da der Defragmentierer ja ein Low-Priority-User-Mode-Task ist der keine IRQs bzw. Real-Time-Tasks blockiert. Was daran "kaputt" sein soll kann ich mir beim besten Willen nicht erklären, man muss sich einfach nur mal gedanklich auf die Segmentierung einlassen und schon wird vieles klarer.


Zitat
Oder statt dessen das Verteilen von Zusammengehörigen Daten auf mehrere kleiner Segmente.
Das ist genau das was früher der Huge-Mode gemacht hat aber das muss der Compiler zur Compile-Zeit erledigen und kann nicht zur Laufzeit passieren oder man müsste noch eine weitere (mir unerklärliche) Abstraktions-Schicht dazwischen ziehen.


Zitat
Nur weil es 15bit sind heißt das noch lange nicht, dass ich alle Bits erraten muss.
In dem Fall musst Du wohl doch raten da die 15 Bits aus einem echten Zufallsgenerator kommen. Jede LDT fasst bei mir 32k-Einträge und die kann ich beliebig durcheinander verwenden. Es gibt keine Abhängigkeiten auf den nummerischen Wert eines Selectors. Solange mein Zufallsquelle von guter Qualität ist hast Du keine andere Chance als zu Raten und bei 1:32768 wird Dir kein gezielter/unauffälliger Angriff gelingen.

Zitat
Deine Selektoren sind ja auch nicht unabhängig von den Segmenten anderer Programme
Doch, jeder Task hat seine eigene LDT. In der GDT sind keine Task-Spezifischen Segmente.

Address layout randomization ist in bestimmten Situationen recht einfach und vor allem unbemerkt zu überwinden. Da ja nicht jede Funktion einzeln per Zufall verteilt wird kann man von der Adresse einer unsicheren Funktion, die ihre Adresse mit einem Bufferoverflow o.ä. verrät, auf eine andere interessante Funktion schließen. Mit so einem zweistufigem Angriff sollte sich jede address layout randomization überwinden lassen ohne zu raten. Das trifft natürlich auch meine Segmente.


Zitat
du willst Speicher bewusst verschwenden?
Vielleicht, ich sehe da keinen allzu großen Nutzwert, aber wenn dann nicht viel. Auf jeden Fall ist es möglich.


Zitat
Das wird dein System langsam machen, wäre meine Einschätzung, da eine Heapverwaltung extrem schnell von dem eigentlichen Pointer auf die Datenstrukturen kommen muss.
Die einzigste Funktion die vom User-Pointer auf die Verwaltungsstrukturen schließen muss ist free() und die kann man asynchron implementieren. free() legt einfach den User-Pointer in einen FIFO und kehrt zurück, irgendwann später kommt ein Hintergrundthread und arbeitet diesen FIFO in aller Ruhe ab. Das funktioniert auch in einem Flat-Memory-System wunderbar und hoch-performant.

Zitat
Die trivialste Implementierung ist
manchmal auch die ungeeignetste und nicht zwingenst die schnellste.


Zitat
feinkörnig, da ich Flags auf 4k-Ebene setzen kann.
Wenn ein Programm 20MByte Code hat musst Du 5000 Pages als Executable markieren. Das ist zwar feinkörnig aber auch hochgradig redundant. Ich kann da keinen Vorteil gegenüber einem Segment, das die 20MBytes mit einem einzigen Bit als executable markiert, erkennen.


Zitat
Ja, es wird sogar in den nächsten C++ Standard kommen.
Dann werden sich die verantwortlichen bestimmt auch überlegt haben wie man das in einem heute gängigen OS (alle mir bekannten nutzen Flat-Memory und Paging) umsetzt.
Eventuell wird dann nicht mehr eine Page-Table pro Task sondern eine pro Thread benötigt, und dann soll noch mal jemand behaupten das Paging keine Performance kostet. :wink:


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 11. August 2009, 20:46
Hallo,


einen Punkte hatte ich vergessen:

Zitat
Zitat
http://www.heise.de/newsticker/meldung/64624
Das Tool, welches in der zweiten Hälfte des Artikels genannt wird, hätte auf einem System mit Segmentierung deutlich weniger Chancen was passendes zusammen zu suchen.
Warum? Ich sehe das ehrlich gesagt nicht, aber ich hab kA von den Details der dort verwendeten Technik.
Entschuldige, da hab ich was unklar erklärt. Das ist weniger ein Vorteil durch die Segmentierung, auch wenn die viele der "nützlichen" Code-Fragmente seltener macht, sondern eher ein Problem von x86 (auch im 64Bit-Modus). Bei x86 kann jede beliebige Bytefolge als Code betrachtet werden, es gibt kein Alignment. Bei typischen RISC-CPUs sind Opcodes immer, auf z.B. 32Bit, ausgerichtet. Das macht solche Zufalls-Code-Sequenzen deutlich seltener. Meine Plattform geht sogar noch weiter, in Richtung Itanium, und verwendet 128Bit (ausgerichtete) Code-Wörter die immer mehrere Befehle, an krummen Bit-Offsets, enthalten. Es dürfte also extrem unwahrscheinlich sein (eigentlich unmöglich) das man Befehle findet die gar nicht bewusst vom Compiler erzeugt wurden.
Auf einer Plattform mit Segmenten benötigt man mehr zusammenhängende Befehle um einen FAR-Pointer zu laden und insbesondere der Befehl zum laden eines Selectors in ein bestimmtes Segmentregister ist recht selten. Ich kann mir vorstellen das so eine Suche nach ausreichend geeigneten Code-Sequenzen, die für einen Angriff ohne eigenen eingeschleusten Code benötigt werden, selbst bei großen Programmen erfolglos bleibt.
Hinzu kommt das x86 die Rücksprungadresse zum Aufrufer bei einem Call immer auf den Stack legt, viele andere CPUs legen denn in ein spezielles "Link-Register" und das wird nur bei Bedarf auf den Stack gesichert. Man kommt also deutlich schwieriger an eine Rücksprungadresse, ist aber trotzdem nicht unmöglich.
All diese Punkte zusammen können den Nutzwert der address layout randomization auf meiner Platform wahrscheinlich steigern, ob es reicht um dafür Speicher zu opfern werde ich sehen.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: kevin am 11. August 2009, 21:49
Naja, der Bedarf, das Linkregister auf dem Stack zu parken, entsteht sobald eine Funktion eine weitere Funktion aufrufen will. Also praktisch gesehen immer.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: bluecode am 12. August 2009, 11:46
Zitat
Ja, es wird sogar in den nächsten C++ Standard kommen.
Dann werden sich die verantwortlichen bestimmt auch überlegt haben wie man das in einem heute gängigen OS (alle mir bekannten nutzen Flat-Memory und Paging) umsetzt.
Eventuell wird dann nicht mehr eine Page-Table pro Task sondern eine pro Thread benötigt, und dann soll noch mal jemand behaupten das Paging keine Performance kostet. :wink:
Es wird afaik über Segmentation erreicht. Sowohl unter x86 als auch unter x64. Wie gesagt, der einzige Grund wo es m.E. von Vorteil ist.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 12. August 2009, 12:43
Hallo,


Zitat
Naja, der Bedarf, das Linkregister auf dem Stack zu parken, entsteht sobald eine Funktion eine weitere Funktion aufrufen will.
Ja, aber man muss es nicht sofort nach dem Einsprung in eine Funktion tun sondern kann es auf später, kurz vor dem Aufruf der Unterfunktion, erledigen. Damit ist die Rücksprungadresse nicht so lange auf dem Stack und daher weniger, eventuell gar nicht, angreifbar. Ob heutige Compiler sowas können weiß ich aber nicht.
Außerdem gibt es viele kleine Funktionen die gar keine Unterfunktionen aufrufen, die sparen sich mindestens 2 Speicherzugriffe.


Zitat
Es wird afaik über Segmentation erreicht.
:-D

Zitat
als auch unter x64
Da bleiben ja nur FS und GS als verstümmelte "Segment-Imitatoren" übrig. Viel Spaß.

Was ist dann eigentlich mit ARM, ALPHA, AVR32, MIPS, Microplace, Itanium, PowerPC ...... ??
Ob die dann wohl nicht mehr C++ kompatibel sind?


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: kevin am 12. August 2009, 19:15
Da bleiben ja nur FS und GS als verstümmelte "Segment-Imitatoren" übrig. Viel Spaß.
Die Basisadresse ist da. Also genauso viel wie bei den tollen Real-Mode-Segmenten, die im hochgelobten DOS gestern noch Spaß gemacht haben. ;)

Zitat
Was ist dann eigentlich mit ARM, ALPHA, AVR32, MIPS, Microplace, Itanium, PowerPC ...... ??
Ob die dann wohl nicht mehr C++ kompatibel sind?
Wie kommst du auf das schmale Brett, auf diesen Architekturen könnte man keinen TLS implementieren? Ich kenne die Architekturen kaum mehr als vom Namen, insofern kann ich dir nicht sagen, wie man es im einzelnen macht. Aber PPC zum Beispiel hat Segmentierung. Sogar extra für dich mit fixer Größe. ;)
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 12. August 2009, 21:27
Hallo,


Zitat
Die Basisadresse ist da.
Mehr aber auch nicht, also doch nur "Segment-Imitatoren".


Zitat
Wie kommst du auf das schmale Brett, auf diesen Architekturen könnte man keinen TLS implementieren?
Nunja das wird wohl schon irgendwie gehen. Das einzigste was mir dafür einfällt ist eine Page-Table pro Thread und nicht nur eine pro Task.
Die genanten Architekturen, so wie fast alles was zwischen 0 und 1 unterscheiden kann, haben alle (Okay der PowerPC hat wohl sowas ähnliches wie Segmentierung aber nichts berauschendes und ob der Itanium in seiner HW-x86-Emulation den 386-PM komplett unterstützt weis ich nicht) "nur" Paging und auf allen genanten (und etlichen mehr) läuft Linux und noch ne Reihe anderer Embedded/Real-Time-OS welche das Paging genau so benutzen wie die meisten OSdever hier es auch tun.

Alles was im OS-Bereich Rang und Namen hat basiert auf den selben "altgedienten" bzw. "altbewährten" Speicherverwaltungskonzepten. Wird Zeit das da mal was neues kommt. :wink:


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: bluecode am 12. August 2009, 22:55
Zitat
Die Basisadresse ist da.
Mehr aber auch nicht, also doch nur "Segment-Imitatoren".
Exakt das was man für TLS eben braucht (und dafür ein Pointer auf eine Kernelstruktur zu speichern kann man gs mut swapgs dann auch recht gut hernehmen).

Man kann mindestens auf folgende Arten TLS implementieren (abgesehen von den bereits genannten):
* ein Syscall get_thread_storage() der einen Zeiger zurückgibt auf den TLS-Bereich. Das wird wohl auf jeder Architektur gehen, halt halt den Syscall-Overhead was ja ziemlich viel sein kann
* Stacks zB an 4MB alignen und die obersten 4/8 Byte für einen Zeiger auf den TLS nutzen, das geht ohne das man Paging bei jedem Thread verschieden macht und es ist sicherlich extrem fix
* wenn ich schon die Pagetables verbiegen will, dann mach ich das doch aber nur auf einer Seite und lege da eben einen Zeiger auf den eigentlichen TLS ab, alles andere würde das Programmiermodel beeinträchtigen (du kannst keine Zeiger auf TLS anderer Threads verwenden)

Außerdem glaube ich kaum, dass das C/C++-Standardkomitee Sachen standardisieren würde, welche auf relevanten Systemen nicht implementierbar sind. Die Frage des Aufwands der Implementation ist natürlich eine andere, aber da muss man auch ganz klar sehen, dass Hardware dafür da ist Software laufen zu lassen, insofern hat es das zu unterstützen was sinnvoll/möglich ist in angemessener Geschwindigkeit, va. wenn das andere Platformen ohne Probleme hinkriegen.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 14. August 2009, 19:31
Hallo,


entschuldige mein Delay, aber ich wollte mich erst mal etwas genauer in das Thema TLS einlesen. Interessant war da vor allem der Artikel in der englischen Wikipedia und dessen externe Links. http://en.wikipedia.org/wiki/Thread-local_storage

Ich bin z.B. davon ausgegangen das ein Pointer in den TLS immer auf den TLS des aktuellen Threads verweisen soll und nicht auf den TLS eines anderen Threads oder das der TLS selber in dem Segment, auf x86 eben GS, steckt.
In Wirklichkeit gibt es nur einen Thread-Spezifischen Pointer auf eine jeweilige Struktur (im normalen Adress-Raum) die den TLS für alle Threads auf die gleiche Weise aber mit verschiedenem Inhalt beschreibt. Sieht insgesamt einigermaßen kompliziert aus. Gleich im ersten externen Link des Wikipedia-Artikels wird das für einige Plattformen konkret beschrieben und ich hab jetzt auch eine Idee wie ich das für mein OS umsetzen möchte. Wenn es wirklich demnächst in den C/C++-Standard rein kommt wird wohl früher oder später die Notwendigkeit auftauchen das zu unterstützen wenn ich mal ein Programm portieren möchte.


Da Du die Stacks ansprichst, wie machst man das eigentlich in einem Flat-Memory-System?
Die einzelnen Stacks der verschiedenen Threads müssen ja hintereinander in den einen  Adress-Raum des Tasks gelegt werden, oder irre ich da? Wie sieht das aus wenn ein Thread dann mehr Stack braucht als Platz bis zum nächsten Stack eines anderen Threads ist? Merkt das das OS eigentlich zuverlässig?
Für die Segmentierung hab ich mir gedacht ich erstelle für jeden Thread ein eigenes lokales Segment mit einer kleinen Anfangsgröße und wenn der Stack wächst, auf meiner Plattform übrigens hin zu den höheren Adressen bzw. Offsets, wird das Segment vom OS vergrößert (eventuell nur bis zu einem definiertem Maximum). Beim Zugriff auf Offsets die das Stack-Segment-Limit überschreiten wird eine Exception ausgelöst aber vom OS speziell behandelt da ja wachsender Stack normal ist. Falls das Segment an seiner momentanen Position im Linearen-Adress-Raum keinen Platz mehr hat muss es eben schnell umgelegt werden. Ob ich ein Schrumpfen, wenn das OS beobachtet das der Stack eine Weile lang wieder kleiner ist, implementiere weis ich noch nicht, währe aber ne nette Idee.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: bluecode am 14. August 2009, 23:48
Die einzelnen Stacks der verschiedenen Threads müssen ja hintereinander in den einen  Adress-Raum des Tasks gelegt werden, oder irre ich da?
"Hintereinander" ist da eher relativ, man kann ja speicher zwischendrin ungemappt lassen (zB. 4MB virtuell für einen Stack vorsehen, davon die obersten 4kB mappen), stört ja keinen. Wenn dann bei einem Thread der Stack zu klein wird kommt beim Zugriff eben ein Pagefault und man mappt ein bisschen mehr.
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 15. August 2009, 11:05
Hallo,


Zitat
man kann ja speicher zwischendrin ungemappt lassen
Ahja, reicht das als Sicherheitsmaßnahme gegen einen Stackoverflow wirklich aus?
Nehmen wir mal an man würde die Stacks an 0xBFFFFF00, 0xBEFFFF00 und 0xBDFFFF00 (32Bit OS) jewails nach unten wachsen lassen, also alle 16MByte einen Stack. Die Pages an  0xBF000000, 0xBE000000 und 0xBD000000 jeweils ungemappt lassen. Wenn dann der mittlere Thread (also der Thread dem der mittlere Stack gehört) eine Funktion wie die folgende aufruft
void foo()
{
  int z;
  char test[16777216];

  z = 1234567;
}
dann währe die 1234567 im Stack eines anderen Thread gelandet und niemand hätte das bemerkt. Eventuell müsste man die Deklaration von z und test vertauschen damit z an der kleineren Adresse steht aber prinzipiell sollte diese Untat funktionieren, oder hab ich da was übersehen?
Das mit den ungemappten Lücken, zwischen den Stacks, wirkt ja nur wenn da auch jemand drauf zugreift. Niemand hindert das User-Space-Programm am überspringen dieser Lücke.

Was passiert eigentlich wenn ein Thread berechtigt mehr Stack benötigt, also auf so eine ungemappte Lücke zugreift? Wird dann einfach der komplette Task gekillt?
Das OS kann ja nicht entscheiden ob da ein böser Programmierer, eine fehlerhafte Endlos-Rekursion oder einfach ganz normaler Stackverbrauch vorliegt.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: Termite am 15. August 2009, 11:59
Hi

Ich hab jetzt nicht wirklich alles gelesen.

aber auf gewissen hw achritekturen, gerade im embedded bereich, gibt es gewisse hw seitige enschränkungen, die dynamisch wachsende Task stacks nicht ermöglichen. Ohne MMU oder etwas ähnlichem wird das nicht gehen.
Auf dem PC kann jede Task / Thread / Prozess seinen eigene Virtuelle Addressierung haben, die von der MMU wieder auf die Physikalische umgerechnet wird. Bei systemen mit MMU kann keine Task speicher einer anderen Task gefährden.

beim PC wird eine Ausnahme geworfen, wenn der Stack überläuft/ bzw auf Virtuelle Addresen zugegriffen wird für die kein Mapping existiert. Dies veranlast das OS dann eine neue speicherseite in den Stackadressraum einzuhängen.

und einfach irgend was durch die gegendschieben z.B. ganze Segmente geht auch nicht immer (absolute Addresierun / relative Addresierung). Du sagst, du hast eine segmentierte addressieren, dann funktioniert das nur solang dein  Programm nicht über eine Segment grenze hinweg springen muss.

Im embedded bereich wird normalerweise die Stacksize jeder Task zur designzeit definiert, zur laufzeit wird da nichts mehr vergrössert oder verkleinert, da die HW wie oben beschrieben das meist gar nicht ermöglicht. bzw das meist eine zusätzliche fehlerquelle ist die mang gerne ausschliesen möchte. Das einzige, was man machen kann, ist beim taskwechsel zu prüfen, ob der Taskblock inclusieve definiertem stack noch in ordnung ist. (magic number) wenn nicht kann das os die verarbeitung einstellen, da es ja nicht wisssen kann, was genau alles Überschrieben wurde.

Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: Termite am 15. August 2009, 12:37
wobei mir gerade einfällt in einem FPGA könnte man die MMU ja extern nachrüsten und über einen interrupt an mit der CPU verbinden.

welches FPGA willst du eigentlich einsetzen, nur interesse halber.
den namen der soft cpu wolltest du ja nicht preisgeben. Ich nehme aber an, das es was exotisches ist, bzw ganz spezielle eigenschaften. müsste eine 16 Bit cpu sein, da sonst die segmentierung wenig sinn machen würde.

gruss
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 15. August 2009, 14:20
Hallo Termite,


Zitat
aber auf gewissen hw achritekturen, gerade im embedded bereich, gibt es gewisse hw seitige enschränkungen, die dynamisch wachsende Task stacks nicht ermöglichen.
Ich persönlich bin der Meinung das das eher eine konzeptionelle Einschränkung ist. Wenn in dem einem Adress-Raum einer Task bereits dort irgendwas liegt wo ein Stack gerne hinwachsen möchte dann geht das eben nicht. Bei Segmentierung existiert das Problem nicht, die einzelnen Segmente einer Task sind, aus Sicht des Task selber, unabhängig von einander. Die Segmente haben keinen Bezug zueinander. Jedes Segment kann prinzipiell seine Größe ändern, natürlich wird das OS dem bestimmte Grenzen auferlegen, das Code-Segment z.B. wird das OS bestimmt nicht ohne triftigen Grund verändern.

Zitat
beim PC wird eine Ausnahme geworfen, wenn der Stack überläuft/ bzw auf Virtuelle Addresen zugegriffen wird für die kein Mapping existiert. ...
Das wird IMHO auf allen Plattformen, die das Paging für die Speicherverwaltung benutzen, so gemacht. Hindert das User-Space-Programm trotzdem nicht daran über eine ungemappte Lücke hinweg zu springen.

Zitat
und einfach irgend was durch die gegendschieben z.B. ganze Segmente geht auch nicht immer
Warum nicht? Das Task selber benutzt nur absolute Adressen, jede für das Task erreichbare Speicherstelle ist mit Segment:Offset eineindeutig adressierbar. Wo die Segmente im linearen Adress-Raum, oder gar im physischen Adress-Raum, liegen weis das Task nicht und genau deshalb kann das OS da schieben was es will, mit etwas Geschick sogar während das betreffende Task läuft.

Zitat
dann funktioniert das nur solang dein Programm nicht über eine Segment grenze hinweg springen muss.
Was genau meinst Du damit?
Die Daten eines Task verteilen sich über mehrere Segmente (Code, Constanten, Daten, Heap, (mehrere) Stacks und sonstiges) und jedes Segment hat eine bestimmte Größe, wenn der Code versucht ein Offset oberhalb eines Segment-Limits (oder kleiner 0) zu lesen/schreiben gibts ne Exception.

Zitat
Im embedded bereich wird normalerweise die Stacksize jeder Task zur designzeit definiert ...
Weis ich, ich hab lange im Embedded-Bereich programmiert (beruflich und privat). Im PC-Bereich wird das aber nicht gemacht. Stell Dir vor Windows würde nur 1MByte Stack erlauben. Ich kenne einige Programme die damit ein Problem hätten.


Zitat
welches FPGA willst du eigentlich einsetzen
Wahrscheinlich Spartan 6, ich möchte die einzelnen Componenten gerne mit den High-Speed-Transceivers verbinden. Ich würde gerne den Virtex 6 einsetzen aber das sprengt mein Budget.

Zitat
müsste eine 16 Bit cpu sein, da sonst die segmentierung wenig sinn machen würde.
Wieso macht Segmentierung bei einem 32/64Bit-System keinen Sinn?
Mein System wird es in beiden Varianten geben, mit identischen Segmentierungs-Fähigkeiten, und ich möchte auf jeden Fall eine PU (Paging-Unit, ich nenne das absichtlich nicht MMU) einbauen, damit kann man an einigen Stellen etwas tiefer in die Trickkiste greifen (Beispiele hab ich ja schon ein paar genannt) und vor allem swappen.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: Termite am 17. August 2009, 09:22
Moin

Segmentierung, so wie ich sie kenne, (C166 / 8086) hatte damals was mit dem Bedürfniss zu tun, mehr speicher zu addressieren, als mit 16 bit überhaupt möglich ist, darum wurden die Segmentregister eingeführt, durch die man  die Addressierung von 16 auf 20, 24 ,.... bit aufborehn konte. daher auch die lustigen far jumps, bei denen segmentregister und dann der IP manipuliert wird.

Bei 32 bit. ist das normalerweise fast nicht mehr notwendig. ausnahmen wie der PC der mehr als 4gb RAM addressieren soll mal ausgenommen. Beim PC gibts ja jetzt dafür die 64Bit maschienen. Im serverberich / High performenc computing waren die ja genau desewegen ja schon lange im einsatz, da dort 4gb ram schon lang nicht mehr ausgereicht haben. (alpha, ultrasparc, ... )

Bei aktuellen 80X386 CPUs gibt es ja die SegmentSelectoren. Die aber meines wiessens wieder auf einen gemeinsamen virtuellen 32Bit Addressraum zeigen. (Code, Stack, Data zusammen dürfen nicht mehr als 4gb belegen)
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 17. August 2009, 13:24
Hallo,


Zitat
Segmentierung, so wie ich sie kenne, (C166 / 8086) ....
Ja, das glaube ich gern.
Kaum jemand hat sich wohl je mit den tollen Möglichkeiten beschäftigt die der PM des 286/386 bieten sollte. Im 286 ist natürlich noch die 64k-Grenze drin (die möchte ich heute auch nicht mehr haben) aber konzeptionell war der ganze PM schon sehr fortschrittlich und wurde dann im 386 mit echten 32Bit-Adressen und dem Paging komplettiert.


Zitat
Bei 32 bit. ist das normalerweise fast nicht mehr notwendig.
Natürlich gibt es ein paar Vorteile wenn man den gesamten erreichbaren Speicher mit einem "simplen" (NEAR-)Pointer erreichen kann aber es gibt eben auch ein paar Vorteile das mit einem "komplexen" (FAR-)Pointer zu machen.


Zitat
Bei aktuellen 80X386 CPUs gibt es ja die SegmentSelectoren.
Ohne das damit je was vernünftiges gemacht wurde. :-( So hatten sich die Intel-CPU-Ingenieure damals das sicher nicht vorgestellt.
Zitat
Die aber meines wiessens wieder auf einen gemeinsamen virtuellen 32Bit Addressraum zeigen.
Das machen die OS-Coder absichtlich so um damit die Segmentierung komplett auszuhebeln so als währe sie nicht da.
Ich hab mir damals (vor über 15 Jahren) ein Buch über die System-Programmierung des 386 gekauft und der Autor hat über den virtuellen (segmentierten) Adress-Raum des 386-PM regelrecht geschwärmt, angeblich unglaubliche 64TByte (also einfach 4GByte * 16384 Segmente, da ja GDT und LDT zusammen so viele fassen). Der Autor ist wohl davon ausgegangen das jemand ernsthaft versuchen würde Segmentweise zu swappen, ist zwar theoretisch möglich aber in der Praxis völliger Schwachsinn da man ja eigentlich immer mehrere Segmente (mindestens Code, Daten und Stack + OS-Kram) gleichzeitig benötigt. Ein paar Kapitel später wurde dann sehr bodenständig erklärt wie man mit dem Paging beengte Verhältnisse im physischen RAM umgeht und bei diesen Erklärungen lagen auch immer alle Segmente in einem linearen Adress-Raum.


Zitat
(Code, Stack, Data zusammen dürfen nicht mehr als 4gb belegen)
In meinem Konzept dürfen alle Tasks (und das OS) zusammen nicht über die 4GByte (zumindest in der 32Bit-Variante) hinaus wachsen da sie alle in einem einzigen linearen Adress-Raum liegen der, bei Bedarf mit Hilfe des Paging, größer sein kann als physischer RAM existiert. Ich sehe in dieser Beschränkung auch erstmal keine Probleme, mein Entwicklungsrechner z.B. kommt mit seinen physischen 1,5GByte auch aus ohne zu swappen trotz KDE usw. Spätestens auf einer vollwertigen 64Bit-Plattform ist dann auf absehbare Zeit ein gemeinsamer linearer Adress-Raum kein Problem mehr.


Grüße
Erik
Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: FritzS am 18. August 2009, 15:19
Hallo Termite und erik

Ich will mal einige Aspekte aus der Sicht des Users betrachten.
Der User ist eigentlich der Compiler bzw. Linker der den ladbaren
Programmfile erstellt

- Flat-Speicher
  Adresse beginnt immer bei 0x00
  das OS gibt vor wo der Code anfängt
  das Programm muss sich selbst kümmern ob das sich
  Stack, Code und Daten nicht in die Quere kommen.
  jede Änderung des Limits kann nur das OS über Systemaufrufe
  jeder Zugriff außerhalb des Speicherlimits muss eine Exception werfen
Wenn nun dieser Speicher im Hitergrund in mehrere Pages zerteilt ist das erstmal egal. Sind aber nun mit diesen Seiten mit unterschiedlichen Attributen verknüpft (NoeXecute, ReadOnly) so ist das ziemlich merkwürdig.
- Segmentierung
  jedes Segment  beginnt auch bei 0x00
  jedes Segment soll keine Überlappung in ein anderes Segment haben
  Zugriffe außerhalb der Segmente müssen auch dann eine Exception
  werfen wenn sie in einem anderen gültigen Segment landen
far-Pointer sind eigentlich nicht nötig sondern nur Segment-Override-Präfixe

Für beide Modelle muss gelten das der schreibende Zugriff auf die
Deskriptoren eine Exception wirft (auch wenn der User sysadmin ist).

Hinter beiden Speichermodellen sollte nun noch das Paging stehen
um die Adressen in den realen Speicher zu übersetzen.

MfG
Und was hindert uns als OS-Designer daran beide Modelle im
fertigen OS anzubieten.

Titel: Re: OS für Plattform mit Segmentierung
Beitrag von: erik.vikinger am 18. August 2009, 21:17
Hallo,


Zitat
Adresse beginnt immer bei 0x00
Der virtuelle Adress-Raum, im Flat-Model, beginnt zwar bei 0 aber die 0-te Page lässt man für gewöhnlich ungemappt damit ein NULL-Pointer eine Exception wirft.

Zitat
das OS gibt vor wo der Code anfängt
ja, das stimmt, kann man übrigens auch bei Segmentierung so machen

Zitat
das Programm muss sich selbst kümmern ob das sich Stack, Code und Daten nicht in die Quere kommen.
Der Linker markiert das im Executable-File als Sektionen so das diese Unterscheidung der Executable-Loader  vom OS passend treffen kann, der verteilt dann alles vernünftig im virtuellem Adress-Raum vom neu zu erstellendem Task.

Zitat
jede Änderung des Limits kann nur das OS über Systemaufrufe
jeder Zugriff außerhalb des Speicherlimits muss eine Exception werfen
Im Flat-Memory-Model gibt es kein Limit. Es gibt nur ungemappte bzw. unberechtigte (z.B. Kernel-Space) Bereiche im linearen Adress-Raum eines Task.

Zitat
Wenn nun dieser Speicher im Hitergrund in mehrere Pages zerteilt ist das erstmal egal.
Davon merkt das User-Task ja gar nichts.

Zitat
Sind aber nun mit diesen Seiten mit unterschiedlichen Attributen verknüpft (NoeXecute, ReadOnly) so ist das ziemlich merkwürdig.
Das ist nicht "merkwürdig" sondern der einzigste Weg wenigstens ein bisschen Sicherheit innerhalb eines Task zu etablieren. Die Task untereinander können sich ja aufgrund der unterschiedlichen Adress-Räume eh nicht in die Quere kommen.
Diese Page-Attribute werden anhand der Sektions-Eigenschaften aus dem Executable-File passend gesetzt, sind also etwas was Compiler bzw. Linker direkt beeinflussen können.


Zitat
jedes Segment  beginnt auch bei 0x00
Beim 386-PM ja, deshalb kann man dort die Null-Pointer-Exception nicht so zuverlässig implementieren. Auf meiner Zielplatform gibt es für jedes Segment nicht nur ein individuelles Limit sondern auch ein kleines individuelles Minimum, damit werden zwar in jedem Segment ein paar (wenige) Bytes verschwendet aber dafür gibts zuverlässige Null-Pointer-Exceptions.

Zitat
jedes Segment soll keine Überlappung in ein anderes Segment haben
Richtig. Es gibt aber ein paar Ausnahmen, z.B. muss ein Debugger für das Code-Segment seines Client-Programms ein Alias-Daten-Segment (mit der selben Basis und dem selben Limit) erstellen damit er überhaupt den Programm-Code sieht (sonst gäbe es keine Disassembler-Ansicht) da das Code-Segment ja Executable-Only ist (also nicht lesbar und erst recht nicht schreibbar). Aber Teil-Überlappungen, so wie im 8086-RM, soll es aber definitiv nicht geben.

Zitat
Zugriffe außerhalb der Segmente müssen auch dann eine Exception werfen wenn sie in einem anderen gültigen Segment landen
Was genau meinst du damit?
Das User-Task weis nicht wo seine Segmente im linearen Adress-Raum liegen (das kann sich sogar mit der Zeit ändern) also gibt es keine Beziehungen der Segmente untereinander. Die CPU selber wird jedenfalls nicht prüfen ob ein Offset das aus einem Segment raus ragt in ein anderes rein fällt.

Zitat
far-Pointer sind eigentlich nicht nötig
Irgendwie muss ja ein allgemein geltendes Stück Programm-Code einem Pointer ansehen welches Segment gemeint ist. Dazu dient der Selector-Teil in einem FAR-Pointer.

Zitat
sondern nur Segment-Override-Präfixe
Dafür gibt es nicht genügend Segment-Register, auf keiner CPU. Ein Task benötigt eine ganze Reihe an Segmenten. Schau die mal die Menge an Sektionen in einem typischen Executable-File an.


Zitat
Für beide Modelle muss gelten das der schreibende Zugriff auf die Deskriptoren eine Exception wirft
Auch bei Lese-Zugriffen sollte eine Exception kommen, sonst könnte ja ein Programm die Internas von anderen Programmen, oder gar dem OS, ausspionieren.


Zitat
Und was hindert uns als OS-Designer daran beide Modelle im fertigen OS anzubieten.
Auf einem vorhandenen Flat-Memory-OS ein segmentiertes Programm laufen zu lassen stelle ich mir quasi unmöglich vor. Umgedreht sollte es gehen auch wenn es einiges an Arbeit kostet und natürlich alle Vorteile der Segmentierung wegfallen, wenn das OS dann noch das Paging ausschaltet (weil nicht benötigt) dann sind alle Schutzmechanismen weg und das Flat-Memory-Task läuft noch unsicherer als auf dem primitivsten Flat-Memory-OS.
Wenn Du wirklich ein OS für beide Memory-Modelle entwickeln möchtest dann nur zu, ich würde mich über Source-Code (natürlich nur zum inspirieren lassen) sehr freuen.


Grüße
Erik