Forum: PC-Programmierung Frage zu Register in x86 Prozessoren


von Samuel J. (capstrovor)


Lesenswert?

Ich lese gerade ein Tutorial über die OS entwicklung.
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId786364

Da wird in der ersten Zeile des Kernels (zu Anfang nur ein Hello World 
Kernel) in das Register AX der Wert 0x07C0 geladen. Diesen Schritt 
verstehe ich noch. Dann aber wird der Wert von AX in DS und ES geladen. 
Als Kommentar steht "set up segments". Wofür muss ich diesen Wert in DS 
und ES laden? Wozu sind diese Register da?

Ersten 3 Zeilen Code aus dem Tutorial:

mov ax, 0x07C0  ; set up segments
mov ds, ax
mov es, ax

von Mark B. (markbrandis)


Lesenswert?

Das sind Segmentregister.

"In real mode the registers CS, DS, SS, and ES point to the currently 
used program code segment (CS), the current data segment (DS), the 
current stack segment (SS), and one extra segment determined by the 
programmer (ES)."

http://en.wikipedia.org/wiki/X86_memory_segmentation

von Samuel J. (capstrovor)


Lesenswert?

ok danke, aber was nützt es, wenn ich das Datasegment und das 
Extrasegment an die gleiche Adresse lege?

von (prx) A. K. (prx)


Lesenswert?

Zwingt dich niemand dazu. Hängt davon ab, was du machen willst.

von Sebastian H. (sebihepp)


Lesenswert?

Wenn du auf eine Speicheradresse zugreifst, dann wird die physikalische 
Adresse aus Segment und Adresse berechnet. Das Segment wird um 4 Bits 
nach links geshiftet und die Adresse hinzuaddiert.

Du kannst es dir auch so vorstellen, dass der Arbeitsspeicher aus 
Segmenten besteht, wovon jedes 16 Byte groß ist.
Segment 0x0000 - 16 Byte
Segment 0x0001 - 16 Byte
usw.

Jetzt können sich die Bereiche aber überlappen, da du ja auch 16 Bit 
Adressen hast. Segment 0x0000 mit Adresse 0x0010 zeigt auf den selben 
Speicherbereich wie Segment 0x0001 mit Adresse 0x0000.

Und etwas Hintergrundwissen:
Das BIOS lädt den Bootsector oder den MBR an die Adresse 0x7C00. Wenn in 
deinem Assemblercode des BS oder MBR Variablen sind, z.B. das 5. Byte, 
dann müsstest du immer die Adresse 0x7C00 mit verrechnen - 5. Byte wird 
zu Adresse 0x7C05. Setzt du dagegen das Segmentregister auf 0x07C0, dann 
kannst du das 5. Byte auch mit Adresse 5 adressieren.

DS ist das Segmentregister für Datenzugriffe (Read/Write), CS für 
Codezugriffe(Wird also mit dem IP verrechnet) und ES für Extrzugriffe 
(Benötigt bei z.B. CMPS).

von Samuel J. (capstrovor)


Lesenswert?

Und gibt es irgendwo eine Liste mit den Regsitern, die nach dem Booten 
gefüllt werden müssen? Also so etwas ähnliches wie der Start von jedem 
Kernel.

von Samuel J. (capstrovor)


Lesenswert?

ok danke, ich glaub den Ansatz habe ich verstanden! :)

von Samuel J. (capstrovor)


Lesenswert?

Noch eine Frage:
Im nächsten Schritt soll eine Trennung zwischen Bootloader und Kernel 
stattfinden. Dazu muss ja die Startadresse des Kernels verändert werden. 
Im ersten Teil des Tutorials war sie ja 0x07C0. Jedoch soll sie jetzt 
auf 0x7C00 gesetzt werden. Mach man das nur, um den Bootloader mehr 
Platz zu geben?

von Εrnst B. (ernst)


Lesenswert?

Gegenfrage:
Für einen Kurzen Moment muss Bootloader und Kernel gleichzeitig im RAM 
stehen. Geht das, wenn beide auf derselben Adresse liegen?

von Samuel J. (capstrovor)


Lesenswert?

oh ok danke! :)

von Magic S. (magic_smoke)


Lesenswert?

Bei Adressierung z.B. DS:SI ist 0000:7C00 die gleiche Adresse wie 
07C0:0000 wenn ich mich nicht irre. Meine DOS-Assembler-Programmierung 
ist leider schon eine Weile her.

von Samuel J. (capstrovor)


Lesenswert?

Moment, ich blick immer noch nicht durch. Am Anfang war Bootloader und 
Kernel in der selben Datei. Da war der Anfang bei 0c07C0. Jetzt sollte 
der Anfang des Bootloaders aber bei 0x7C00 und der des Kernel bei 0x1000 
sein. Das macht irgendwie keinen Sinn, oder?

von Samuel J. (capstrovor)


Lesenswert?

@Magic_smoke

aber es wird immer nur das Register DS beschrieben, nie das Register SI.

von Samuel J. (capstrovor)


Lesenswert?

oh... Im Bootloader Sourcecode wird nicht so gearbeitet:
mov AX, 0x07C0
mov DS, AX

sondern so:
org 0x7C00

macht das einen Unterschied?

von Sebastian H. (sebihepp)


Lesenswert?

Ja, das macht einen Unterschied.

DS=0x07C0 => Adresse 0x0000

org 0x7C00 weist den Assembler an, sich den Dateianfang an Adresse 
0x7C00 zu denken. Daraus würde dann DS=0x0000 und Adresse=0x7C00 
ergeben.

von Samuel J. (capstrovor)


Lesenswert?

Ah ok.

Dann noch eine letzte Frage ;)

Was macht dieser Befehl hier (ich weiß nicht mal den Ansatz):

mov [bootdrive], dl
call load_kernel

load_kernel:

mov dl,[bootdrive]
    xor ax, ax
    int 0x13
    jc load_kernel

von Εrnst B. (ernst)


Lesenswert?

xor AX,AX Setzt AX auf 0, nur "schneller und kürzer" als ein MOV :)

INT 13 Ruft INT 13 auf, das sind BIOS-Funktionen :)

INT 13 mit AX==0: "Reset Drive Status".

http://en.wikipedia.org/wiki/INT_13H#INT_13h_AH.3D00h:_Reset_Disk_Drive

jc load_kernel: Wenn Fehler: Gleich nochmal...

von Magic S. (magic_smoke)


Lesenswert?

Für den Prozessor nicht.

Bei .EXE-Dateien ist im Header auch eine Einsprungadresse in das 
Programm angegeben. DOS lädt die Datei also ins RAM und springt dann an 
diese Adresse. .COM-Dateien haben das nicht, die werden ins RAM geladen 
und immer bei CS:0100 angesprungen. CS ist immer variabel, da das 
Programm keinen Einfluß darauf hat, an welche Stelle im RAM es geladen 
wird.

Die x86-Prozessoren können nur bestimmte (nicht-Segment) Register zur 
Adressierung nutzen. Beispielsweise DS:SI, ES:DI, CS:IP, SS:SP.
Was nicht geht ist z.B. DS:AX, CS:CX oder AX:BX.

von Samuel J. (capstrovor)


Lesenswert?

Ok danke! Soweit verstehe ich es.
Nur was macht das
mov dl, [bootdrive]
?

von Sebastian H. (sebihepp)


Lesenswert?

>mov [bootdrive], dl
hier schreibst du den Inhalt von Register dl an die Speicheradresse 
bootdrive. Die [] ist die Intel Syntax, dass das, was dazwischen steht, 
als Adresse aufgefasst werden soll.

>call load_kernel
Hier machst du einen call. Der schreibt die Rücksprungadresse auf den 
Stack und springt an die Adresse load_kernel

>load_kernel:
Das hier weißt den Assembler an, load_kernel mit der Adresse zu 
verknüpfen, die an der Stelle in der Datei vorliegt. Hier ist jetzt ein 
großer Unterschied ob CS=0x07C0 oder org 0x7C00 benutzt wurde.

>mov dl,[bootdrive]
Hier schreibst du den Inhalt des Speichers an Adresse bootdrive zurück 
ins Register dl.

>xor ax, ax
Hiermit setzt du Register ax auf Null. (xor mit sich selbst setzt alle 
Bits auf 0 und braucht bei einem x86er weniger Bytes als mov ax, 0x0000)

>int 0x13
Interrupt 0x13 aufrufen, davor noch die Rücksprungadresse auf den Stack 
legen.

>jc load_kernel
Wenn das Carry Bit gesetzt ist, dann springe zu Adresse load_kernel

von Εrnst B. (ernst)


Lesenswert?

Samuel J. schrieb:
> mov dl, [bootdrive]

dasselbe wie jeder andere MOV Befehl, einen Wert Kopieren, nicht MOVen 
...

In diesem Fall: RAM -> Register...

von Magic S. (magic_smoke)


Lesenswert?

Es lädt DL mit dem Byte an Adresse DS:[bootdrive] wobei bootdrive ein 
irgendwo definierter offset ist.

von Samuel J. (capstrovor)


Lesenswert?

OK, vielen Dank an alle! :)

von heinz (Gast)


Lesenswert?

Nicht ganz sicher.

Der Bios setzt Dir im DL Register das Bootlaufwerk zB 0x80 die erste 
Festplatte.

mov [xyz],dl speichert Dir das Laufwerk in die Adresse xyz
alle Biosfunktionen 0x13 wollen das anzusprechende Laufwerk in dl
deshalb
mov dl,[xyz] ; dl enthaelt das Bootlaufwerk
mov ah,42h   ; lba read
mov si, offset dap
int 13h

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.