Autor Thema: OS für Plattform mit Segmentierung  (Gelesen 20512 mal)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« 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
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #2 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
Reality is that which, when you stop believing in it, doesn't go away.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 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.


Dieser Text wird unter jedem Beitrag angezeigt.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #4 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
Reality is that which, when you stop believing in it, doesn't go away.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #5 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
Reality is that which, when you stop believing in it, doesn't go away.

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #6 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...
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 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
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #8 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #9 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
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #10 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. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 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
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #12 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #13 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.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #14 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
Reality is that which, when you stop believing in it, doesn't go away.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #15 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.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #16 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
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.
« Letzte Änderung: 11. August 2009, 17:00 von bluecode »
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #17 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
Reality is that which, when you stop believing in it, doesn't go away.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #18 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
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #19 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen