Frage zum Bootvorgang
-
Hey Leute,
bin auf zwei fetzen Code gestoßen, wo ich etwas nicht so ganz verstehe.Wenn ein PC angeschalten wird, dann wird ja der wert 0xFFFF in das Codesegment geladen, dort ist das Bios gespeichert. Dieses startet nun, und durchsucht die im Bios angegebenen Bootlaufwerke. Ist jetzt in einem dieser Bootlaufwerke im Bootsektor ein "Programm", welches am Ende des 512 Byte großen Segmentes( in den letzten beiden Bytes ) die Bootsignatur 0x55AA hat, wird dieses in den Arbeitsspeicher an die Adresse 0x7C00 geladen. Alles soweit so gut, das sollte ja normal der Bootloader sein, so wie hier:
org 0x7c00 cli times 510-($-$$) hlt db 0x55 db 0xAA
( kein richtiger Bootloader )
so nun hab ich ein Code gesehen, welcher ein Mini-Kernel sein soll ohne Bootloader, der Mini-Kernel soll also direkt gelesen werden, hier ein kleiner Codeausschnitt vom Anfang des Codes:
mov ax, 0x07C0 ; set up segments mov ds, ax mov es, ax mov si, welcome call print_string
Jetzt frage ich mich, warum nun als Datensegment 0x07C0 angegeben wird, und warum gar nicht angegeben wird, dass das Codesegment bzw der Code bei 0x7C00 losgeht?
Hoffe ihr könnt mir helfen und mir das ganze verständlich erklären=)
Schonmal vielen Dank
Lg freeG
-
Wirst du sicher besser verstehen, wenn du dich etwas mit der Adressierung im RealMode beschaeftigst. Siehe dazu z.B. FAQ, Wikipedia oder deine Lieblingssuchmaschine.
Bei den Intel-CPU bilden immer ein Segmentregister und ein Offset zusammen irgendwie (je nach Modus ist das Verfahren anders) eine physikalische Adresse im Speicher. Im RealMode geht die Rechnung im Wesentlichen:
Phys. Addr = Segment*16 + OffsetDer Bootsektor liegt an der phys. Adresse 0x7C00. Laedst du in die Segmentregister 0x07C0, kannst du die Daten in diesem Code also adressieren, als wuerden sie bei Offset 0 anfangen...
-
Erst mal Danke für die Antwort. Jetzt verstehe ich es auch, kannte zwar die Adressierung im RM, allerdings bin ich nicht drauf gekommen dass 7C00 / 16 gleich 7C0 ist
Allerdings haben sich bei mir noch ein paar neue Fragen aufgetan:
1. mit org 0x7C00 sag ich dem Assembler ja, dass dort der Code hinkopiert wird, damit er auch richtig die Speicheradressen berechnen kann oder?
2. mit
mov ax, 0x07C0 mov ds, ax mov es, ax
kopiere ich ja die 0x07C0 in das Datensegmentregister und Extrasegmentregister. Der Code selber, wird aber doch mit CS:IP adressiert, aber wie kommt die Adresse vom Code in das CS? Jetzt wo ich die Frage gerade schreibe, habe ich glaube ich die Lösung, das BIOS kopiert ja den Code nach 0x7C00, und das Bios schreibt dann warscheinlich auch diesen Wert in das CS-Register oder?
3. Vll kann mir jemand mal kurz den hlt Befehl erklären. Ich habe gelesen, er stoppt den Prozessor, dieser macht nun weiter wenn ein Interrupt eintrifft, außer dies wurde mit dem Interrupt-Flag blockiert, dann macht er nur noch durch spezielle Hardware-Interrupts weiter. So weit so gut...aber so könnt ich den Prozessor ja ganz einfach lamlegen, in dem ich das Interrupt-Flag lösche und den hlt Befehl ausführe oder etwa nicht? Zudem hab ich gelesen, dass in diesem Code fetzten
times 510-($-$$) hlt
das hlt das
db 0
ersetzt? Wieso das denn?
4. Wieso wird manchmal im code sowas verwendet( ich meine das section data/code )
segment code ; bla bla segment data ; bla bla
Was bringt mir das und was bewirkt das?
Für eure Hilfe bin ich schonmal im Voraus sehr dankbar, ich hoffe ihr könnt mir auch helfen
denn das sind im Moment die einzigen 4 Fragen, die ich mir nicht erklären kann.
Lg freeG
-
Ok, also der Reihe nach...
fr33g schrieb:
1. mit org 0x7C00 sag ich dem Assembler ja, dass dort der Code hinkopiert wird, damit er auch richtig die Speicheradressen berechnen kann oder?
Mit dem Metabefehl "org" legst du im Prinzip das aktuelle Offset fest. Das erste auf diesen Befehl folgende Datum wird also mit der in org angegebenen Offset-Adresse referenziert werden, alle folgenden entsprechend auch relativ zu diesem Offset. Naehere Details dazu findest du auch in der Dokumentation zum Assembler.
Beispiel:
org 0 test1 db "Toll!" test2 db 0 ;... mov si, test1 ; offset vom label test1 ist 0 => dh, wird zu mov si, 0 mov si, test2 ; das ist entsprechend 5... ;... org 0x7C00 test3 db "Yay!" test4 db 0 ;... ; das offset dieses codes selbst wird so uebrigens auch durch das obige org beeinflusst - schlaegt sich z.B. in der Adressierung von jumps oder calls mit absoluten Adressen nieder... mov si, test3 ; offset von test3 ist jetzt 7C00 mov si, test4 ; und das 7C04
fr33g schrieb:
2. mit
mov ax, 0x07C0 mov ds, ax mov es, ax
kopiere ich ja die 0x07C0 in das Datensegmentregister und Extrasegmentregister. Der Code selber, wird aber doch mit CS:IP adressiert, aber wie kommt die Adresse vom Code in das CS? Jetzt wo ich die Frage gerade schreibe, habe ich glaube ich die Lösung, das BIOS kopiert ja den Code nach 0x7C00, und das Bios schreibt dann warscheinlich auch diesen Wert in das CS-Register oder?
Ja, cs wird beim Sprung in den Bootsektorcode gesetzt. Bedenke: Der Pointer auf die naechste auszufuehrende Instruktion besteht sowohl aus dem Segment in cs, als auch aus dem Offset in IP. Wenn du cs veraenderst, fuehrst du also im Prinzip einen Sprung zu einem Befehl an einer anderen Adresse im Speichers aus.
Deshalb veraendert man cs idR. auch niemals direkt, sondern immer indirekt via far-Jumps oder calls...fr33g schrieb:
3. Vll kann mir jemand mal kurz den hlt Befehl erklären. Ich habe gelesen, er stoppt den Prozessor, dieser macht nun weiter wenn ein Interrupt eintrifft, außer dies wurde mit dem Interrupt-Flag blockiert, dann macht er nur noch durch spezielle Hardware-Interrupts weiter. So weit so gut...aber so könnt ich den Prozessor ja ganz einfach lamlegen, in dem ich das Interrupt-Flag lösche und den hlt Befehl ausführe oder etwa nicht?
Ja, dann geht nur noch der Nmi (nicht maskierbarer Interrupt). Der Befehl ist eben auch genau dafuer gedacht, die CPU "lahm", bzw. schlafen zu legen - spart Energie.
Windows oder aehnliche moderne Betriebssysteme kannst du auf diese Art aber nicht sabotieren. Hier greifen einige Sicherheitsmechanismen des Protected Mode der x86 CPU.fr33g schrieb:
Zudem hab ich gelesen, dass in diesem Code fetzten
times 510-($-$$) hlt
das hlt das
db 0
ersetzt? Wieso das denn?
times x y packt y (kann ein Datum oder ein Mnemonic sein) x mal hintereinander. Mehr steckt da eigentlich nicht dahinter. Siehe auch dazu wieder die Docs zum Assembler fuer mehr Details. Sehr praktisch, wenn man aus irgendwelchen Gruenden Platz auffuellen will. Besteht die Gefahr, dass diese Daten evtl. durch einen verirrten Sprung mal ausgefuehrt werden, ersetzt man die naheliegende 0 oft durch Befehle wie hlt oder db 0xCC (OpCode fuer int 3 - das ist die Debugger step exception).
fr33g schrieb:
4. Wieso wird manchmal im code sowas verwendet( ich meine das section data/code )
segment code ; bla bla segment data ; bla bla
Was bringt mir das und was bewirkt das?
Auch dazu empfehle ich die Dokumentation des Assemblers. Im Wesentlichen bieten diese Befehle die Moeglichkeit, deinen Code in verschiedene Sektionen zu gliedern. Das spielt eine Rolle beim assemblieren zu Objekt-Dateien und spaeter beim Linken in Programmcontainer wie .exe oder elf, die von einem laufenden Betriebssystem geladen werden muessen. IdR. wird den so definierten "Segmenten" beim Laden dann ein eingener Speicherbereich mit extra Segment-Adresse zugewiesen. Bei Protected Mode-Programmen werden Datensegmente zudem ggF. gegen Ausfuehren geschuetzt...
-
Erst mal vielen Dank für die ausführliche Antwort=)
Jedoch habe ich noch Fragen
zu 1.: mit org lege ich das aktuelle offset fest, wie wird jedoch dann das segment bestimmt sprich der cs wert?
zu 2.: Was times macht ist mir klar bzw genau zu diesem Zweck hab ichs auch schon genutzt( eben allerdings mit times x db 0 ), wieso aber ist times x hlt aquivalent dazu? Sprich wieso schreibt hlt x bytes hintereinander eine 0?
noch eine neue Frage:
; code hlt mov ax, 0x2D3F ; code
Wie kann ich das hlt jetzt verstehen? Es hält ja den Prozessor an. Wie lange bleibt der Prozessor denn dann stehen, also ich weiß nicht wie ichs formulieren soll, normal ja erst wenn ein normaler Interrupt bzw ein NMI eintrifft. Das würde ja heißen der nächste Befehl( mov ) würde erst ausgeführt werden, nachdem irgendein Interrupt beim Prozessor antritt oder?
Bis dahin auf jeden Fall schonmal vielen Dank für deine kompetente Hilfe=)
Lg freeG
-
fr33g schrieb:
zu 1.: mit org lege ich das aktuelle offset fest, wie wird jedoch dann das segment bestimmt sprich der cs wert?
Das BIOS fuehrt hier den Sprung in den Bootsektorcode aus, nachdem dieser an die physikalische Adresse 0x7C00 geladen wurde. Damit bestimmt allein das BIOS darueber, was am Anfang des Bootsektorcodes in cs:ip steht. AFAIK ist das auch nicht im Detail geregelt. Die Segment-Offset-Paare 0x07C0:0x0000 oder 0x0000:0x7C00 zeigen im RealMode zB. auf die selbe Speicheradresse (siehe Gleichung zur Berechnung der physikalischen Adresse), dh. beide Werte koennten im Prinzip am Anfang des Bootloaders in cs:ip stehen. Sehr oft spielt das fuer cs:ip aber auch keine Rolle, da Spruenge und Calls ihre Zieladresse idR. immer relativ zur Adresse angeben, an der sie stehen. Also sinngemaess sowas wie "springe von hier +50 bytes vorwaerts".
Zum Initialisieren der Segmentregister zum Adressieren der Daten (es und ds) kannst du in diesem Fall, wo die physikalische Adresse und das beim Uebersetzen deines Codes verwendete offset (via org eingestellt) bekannt sind, die Gleichung zur Berechnung der physikalischen Adresse umstellen.
Fuer RealMode:
seg = (phys.addr - offs) / 16Beispiel:
(0x7C00 - 0) / 16 = 0x07C0Bliebe noch mal zu bemerken: Die Org-Anweisung beeinflusst allein die Adressberechnung fuer Labels bei der Uebersetzung deines Codes und sonst nichts. Im Wesentlichen wirklich so primitiv, wie es mein Beispiel im letzten Beitrag zeigt.
fr33g schrieb:
zu 2.: Was times macht ist mir klar bzw genau zu diesem Zweck hab ichs auch schon genutzt( eben allerdings mit times x db 0 ), wieso aber ist times x hlt aquivalent dazu? Sprich wieso schreibt hlt x bytes hintereinander eine 0?
Tut es nicht. Es schreibt x mal hintereinander die Instruktion "hlt" (entspricht AFAIR db 0xF4). Eine Ersetzung von db 0 ist deshalb moeglich, weil der OpCode zu hlt eben auch nur 1 Byte lang ist. Weswegen man das praktisch so macht, habe ich im letzten Beitrag geschrieben.
fr33g schrieb:
noch eine neue Frage:
; code hlt mov ax, 0x2D3F ; code
Wie kann ich das hlt jetzt verstehen? Es hält ja den Prozessor an. Wie lange bleibt der Prozessor denn dann stehen, also ich weiß nicht wie ichs formulieren soll, normal ja erst wenn ein normaler Interrupt bzw ein NMI eintrifft. Das würde ja heißen der nächste Befehl( mov ) würde erst ausgeführt werden, nachdem irgendein Interrupt beim Prozessor antritt oder?
Bei Auftreten eines Interrupts (der nicht maskiert wurde), wird die CPU zunaechst in den entsprechenden Interrupt Handler springen. Erst nach Abarbeiten dieses Codes, kann zur naechsten Instruktion nach hlt gesprungen werden. zB. indem mit "iret" vom Interrupt-Handler zurueck gesprungen wird.
-
Ok vielen Dank jetzt habe ich das verstanden=) Wenn ich jetzt ein normales Assembler-Programm für Windows schreibe( nicht dos, also keine .com Datei ), dann brauche ich ja keine org-Anweisung. Also geht der Assembler vom Offset 0x0000 aus. Sprich jedes Programm wird vom Betriebssystem zwangsläufig in ein neues Segment geladen?
Wenn das so stimmt, dann denke ich habe ich alles verstanden
Lg freeG
-
Nicht ganz... Windows traegt quasi beim Laden von Programmen alle Offsets im Programm neu ein. Das ist etwas komplizierter...
Frueher fingen die Programme so immer AFAIR beim Offset 0x400000 an. Inzwischen koennen aber auch zufaellige Adressen gewaehlt werden, um fiese Schaedlinge zu verwirren.
Zum Schreiben von Windows- oder aehnlichen Programmen, die mit Segmenten in spezielle Container-Formate gelinkt werden, brauchst du dir um ein Offset idR. keine Gedanken machen... um Segmente auch nicht. Das initialisiert alles das Betriebssystem beim Laden deines Programms.
IdR. wirst du bei unprivilegierten Protected-Mode-Programmen die Segmentregister auch gar nicht mehr veraendern.
-
Ok, also kümmert sich kurz gesagt dann Windows um die Offsets und ich muss mich nicht drum kümmern
Dann versteh ich ja jetzt alles
Also vielen Dank für eine kompetente Hilfe
Lg freeG