Segmentierung

  • Themenstarter Themenstarter Gelöschtes Mitglied 14523
  • Beginndatum Beginndatum
G

Gelöschtes Mitglied 14523

Guest
Hi community

Ich beschäftige mich seit kurzem mit Paging bzw Segmentierung und dabei ist für mich die ein oder andere Frage, was das Umwandeln bzw Berechnen der Adressen betrifft, aufgetreten.

Zur Segmentierung. Ich gehe mal von nen einfachen 8086 Prozessor aus, welcher im Realmode mit 16 bit großen Segment- bzw Offsetregister arbeitet. Die physikalsche Adresse erhält man, wenn man Segmentregister* 16 + Offsetregister rechnet. Soweit sogut.
Nun mal 2 Beispiele zum Berechnen der physikalischen Adresse:

Code:
Segmentadresse:           0000 0001 0000 0000 0000
Offsetadresse:                 0001 1100 1001 0110
physikalisch:            0000 0010  1100 1001 0110

Segmentadresse:           0000 0010 0000 0000 0000
Offsetadresse:                 0000 1100 1001 0110
physikalisch:            0000 0010  1100 1001 0110

In den Beispielen sprech ich 2 verschieden Segmente an, mit unterschiedlichen Offsetwerten, jedoch ist die physikalische Adresse die selbe?! Währe sehr dankbar für einen Hinweis auf meinen Denkfehler.
Außerdem, liege ich richtig mit meiner Vermutung, dass Segmenttables nur im Protected Mode verwendet werden?
 
Soweit ich mich noch erinnere:
Segement : Offset sind beide 16-Bit Zahlen.
Mit Segment hat man also 65535 "Speicherblöcke"
Da Segment nur mit 16 multipliziert wird, wird es auf eine 20Bit lange Zahl "gestreckt" - also ein MB Speicher, welches damit in 65535 Blöcken zu je 16Byte angesprochen werden kann. Man kann dadurch nur die einzelnen Bytes in diesen Blöcken nicht konkret addressieren.
Durch die Addition des Offsets kann man nun auch die einzelnen Bytes ansprechen - es ergeben sich allerdings deutliche Überlappungen (da ja eine 16 Bit Zahl addiert wird, die wiederum bis 65535 Werte beinhalten kann).
Vereinfacht gesagt: man hat 2 16-Bit Zahlen zur Verfügung (mit denen man theoretisch 4GB Speicher adressieren kann) und verwendet diese, um nur 1 MB zu adressieren - Wertebereichüberlappungen sind da eigentlich vorprogrammiert.
 
Danke für die schnelle Antwort.
Als muss man mit dieser Werteüberlappung quasi leben.
Hmm nur frage ich mich wie man mit dieser Technik ein System zum Laufen bringt, welches nicht jede Minute wegen "inkorrekter" Adressierung (aufrgrund von Werteüberlappung) abstürtzt.


EDIT:
Das Thema hat sich erledigt, anscheined muss man als Programmierer drauf achten eine Überlappung zu verhindern. Ganz schön mühselig :D

Einen kleinen Denkanstoß könnt ich jedoch noch gebrauchen ;)
Diesmal gehts um die Segmentierung im Protected Mode (32 bit). Dort werden ja die Segmentregister als Selektoren eingesetzt, welche auf einen Deskriptor verweisen.
So ein Deskriptor enthält(unabhängig von GDT,LDT oder IDT) unter anderm eine Basisadresse. Die virtuelle Adresse (bei aktiven Paging) setzt sich aus der Basisadresse welche sich eben im Deskriptor befindet und einen Offset(32 bit) zusammen.

Wenn ich ne Executable mit OllyDbg öffne, zeigt er mir doch in der linken Spalten die virtuellen Adressen an. Als Coder kann ich die ImageBaseAddress bestimmen und laut Olly setzt sich die virtuelle Adresse aus ImageBaseAddress + RVA zusammen.
Wenn ich aber nun 2 Programme mit ner BaseAddress von 400000 am laufen hätte, würde dies wiederum zu einer Überlappung der Adressen führen.

Mich verwirrt das grad unheimlich, gibt es demzufolge 2 verschieden virtuelle Adressen (1: ImageBaseAdress + RVA, 2: BaseAddress von Deskriptor + Offset)?
 
Zu der wirklichen Funktionsweise von protektedmode Segmentierung kann ich nicht viel sagen (hab nur vereinfachte Modelle Umgesetzt bzw erklären müssen), allerdings bringst Du hier glaube ich etwas durcheinander:
jeder Prozess hat einen eigenen virtuellen Adressraum und eigene Seitentabellen für die Umrechnung zwischen physikalischen und virtuellen Adressen. D.h sofern das OS nicht durcheinander kommt, dass hier keinerlei Überlappungen entstehen sollen. Als Coder kannst du zwar sagen, dass der Code deiner Exe z.B ab 500000 anfangen soll - das gilt allerdings nur für den Sandkasten aka V-Space der Exe. Denn ich garantiere Dir, dass im Moment auf Deinem System mindestens 15 Programme mit jeweilgen ImageBase 40 0000 laufen :D

Die Berechnung ImageBase+RVA gilt nur für den Windows-PE-Loader (an welche VAs letzendlich die Code,Daten usw Bytes geladen werden sollen). Ist quasi eine Art Vorgabe dass es so abläuft und hat nichts mit der "richtigen" Segmentierung gemeinsam.

Das "Überlappungsproblem" hat man nur, wenn man mehrere Executables aka DLLs in einem Adressraum laufen lassen möchte - da macht plötzlich das Konzept mit RVA und ImageBase Sinn (denn bei DLLs ist ImageBase eher eine "Wunschadresse" - Windows kann die DLL auch an andere Basisadressen laden. Dank RVA Angaben und Relocations stellt es auch kein Problem dar. So können zig DLLs nebeneinander laufen und die Programmierer müssen sich nicht vorher absprechen, wer welche Adressbereiche besetzen soll.
 
"...jeder Prozess hat einen eigenen virtuellen Adressraum und eigene Seitentabellen für die Umrechnung zwischen physikalischen und virtuellen Adressen. D.h sofern das OS nicht durcheinander kommt, dass hier keinerlei Überlappungen entstehen sollen..."

Woher beziehst du das? Ich meine damit nicht, dass deine Aussagen fragwürdig sind, sondern dass ich halt mehr über dieses Thema lesen möchte.

MfG
 
Original von CDW
Vereinfacht gesagt: man hat 2 16-Bit Zahlen zur Verfügung (mit denen man theoretisch 4GB Speicher adressieren kann) und verwendet diese, um nur 1 MB zu adressieren - Wertebereichüberlappungen sind da eigentlich vorprogrammiert.

Wie willst du mit 2 16 Bit Zahlen 4gb Adressieren?

Nochmal eine andere Erklärung:

Der 8086 hatte einen 20 bit breiten Adressbus aber nur 16 bit Register. Demzufolge hätte er theoretisch 2^20 = 1 Mbyte Arbeitsspeicher adressieren können. Jedoch lassen sich 20 bit nicht in ein 16 bit Register "pressen". Man halt also den Arbeitsspeicher in 16 byte Blöcke unterteilt. 2^16 = 65536 ->Man adressiert mithilfe des Segmentregisters 65536 Segmente zu je 16 byte. Nun kann man aber die Adressen innerhalb der Segmente nicht ansprechen. Demzufolge nimmt man ein 2-tes 16 bit Register, das Offset Register, zur Hilfe. Mit diesem Register lassen sich nun die einzelnen Bytes der Segmente ansprechen. Doch um 16 byte Offset zu adressieren braucht man nur 4 bit. Demzufolge kann ein Offset Register immer mehrere Offsets von Segmenten adressieren.
Man konnte den Arbeitsspeicher aber nur max. in 16 byte Blöcke unterteilen, da der Adressbus nur 20 bit breit war und eine Unterteilung in 32 byte Blöcke somit nicht möglich ist.

Wie kann es nun dazu kommen, sich eine physikalische Adresse auf unterchiedlichen Segemten: Offset Werten berechnen lässt?

Es gibt immer Segmentgrenzen (alle 16 bytes durch die Unterteilung in 16 byte Blöcke). Ein Offset kann jedoch mehr als 16 byte adressieren. Demzufolge kann man mit dem Offestregister die Segmentgrenzen "überwinden" und Segmente können sich überlappen.

Ein Segment, welches an der Segmentgrenze 0 beginnt und 48 byte groß ist, überlappt ein Semgent, welches an der Segmentgrenze 1 beginnt uns 16 byte groß ist. Demzufolge kann eine physikalische Adresse durch untersch. Segment : Offset Werte gebildet werden.
 
Original von Darkslide
Original von CDW
Vereinfacht gesagt: man hat 2 16-Bit Zahlen zur Verfügung (mit denen man theoretisch 4GB Speicher adressieren kann) und verwendet diese, um nur 1 MB zu adressieren - Wertebereichüberlappungen sind da eigentlich vorprogrammiert.

Wie willst du mit 2 16 Bit Zahlen 4gb Adressieren?

In den man ein Register als "höhere" Bytes interpretiert und das andere als "niedrige".

Bsp: 1.Register 105Eh //highbytes
2.Register 456Ah //lowbytes

=> Adresse = 105E456Ah

Im RealMode ist allerdings nur 1 MB adressierbar, da dieser ursprünglich für den 8086 Prozessor entwickelt wurde. Der 8086 besitzt einen 20 bit breiten Adressbus (2^20 = 1048576 => 1MB zirka). Multipliziert man nun in den Beispiel das 1.Register mit 16, erhält man einen 20bit Wert. Dieser Wert + den Wert im 2.Register ergibt dan die physikalsche (20bit) Adresse.
 
genau - nach dem selben Muster:
Segment*0x10000+Offset
(wobei in der Hardware die Multiplikation noch nicht mal umgesetzt werden muss, da hier ein Shifting ode einfaches Zusammenführen der Register vollkommen ausreicht). Denn: 16+16=32 Bit :)
 
So nun fehlt mir nur noch ein Schritt wie ich von den VAs einer PE-Executable zu der zugehörigen physiklischen Adresse komme. Die VAs welche in Olly dargestellt werden, sind ungleich den virtuellen(linearen) Adressen bei der Segmentierung bzw beim Paging.
Mir ist bekannt, dass ich mithilfe einer logischen Adresse (Selektor + Offset)
die virtuelle(lineare) Adresse ermitteln kan und in weiterer Folge, durch Paging, auf die physikalische komme.
Nun ist die Frage wie ich zu dieser logischen Adresse komme. der Selektor davon ist noch klar(Selektor = Segmentregister). Wie bekomm ich aber den Offsetwert?

Noch ein Beispiel um die Frage zu verdeutlichen.

Ich geh jetzt mal von ner ImageBase von 40 0000 aus.
Virtuelle Adresse vom Datensegment = 2000.
Nun verschiebe ich die ersten 4 Bytes des Datensegmentes in das EAX Register

mov EAX, Dword PTR DS:[402000]

Vermutung: für DS wird der Wert des Datasegmentregisters genommen(= Selektor) und der Offset wird durch eine "Routine" berechnet(Offset = 402000 - ImageBase - VA von Datensegment => 0)

Stimmt meine Vermutung? Wenn ja, wie nennt man diese "Routine"?

EDIT: 402000 - Basisadresse - VA, korrekter Weise :D
 
Zurück
Oben