Autor Thema: Was genau ist ein Sprung?  (Gelesen 14236 mal)

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« am: 15. February 2013, 14:14 »
Ich lese gerade, aber ich verstehe nicht wirklich, was ein Sprung ist... Und anscheinend gibt es auch noch Unterschiede zwischen verschiedenen Sprüngen, also wie weit man springt etc.

Also meine Frage: Was genau ist ein Sprung?

mfg :)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 15. February 2013, 14:32 »
Ein Sprung ist eine Diskontinuität im Programmfluss.
Oder: Ein Sprungbefehl ist ein Befehl, nach dem (zeitlich) nicht zwingend der (im Speicher) folgende Befehl ausgeführt wird.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 15. February 2013, 15:04 »
OK. Hat das etwas mit jmpzu tun?

TheThing

  • Beiträge: 105
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 15. February 2013, 15:56 »
Ja, hat es. jmp steht für jump, engl. to jump = springen. jmp sorgt dafür, dass der Prozessor zur angegebenen Speicheradresse springt.
Ein kleines Beispiel:
mov eax, 0xDEADC0DE
jmp testlabel
mov eax, 0xDEADBEEF
testlabel:
#irgendetwas...
Die Prozessor wird zuerst "mov eax, 0xDEADC0DE" ausführen, danach findet er jmp (das Label ist natürlich in der Maschinensprache nicht mehr vorhanden, sondern wird durch die entsprechende Adresse ersetzt) und überspringt den zweiten mov-Befehl.
Würde der Prozessor keine Sprünge kennen, hätten wir am Schluss 0xDEADBEEF in eax, da der Prozesor aber ein braver Kerl ist und unseren Befehlen gehorcht, steht da auch schön 0xDEADC0DE drin.
Sprünge sind immer dann notwendig, wenn du von einer strikt linearen Programmausführung abweichen willst, d.h. bei Verzweigungen (if) brauchst du Sprünge, ebenso bei Prozeduraufrufen.
Allerdings gibt es mehrere Sprungbefehle, je nachdem warum genau du springen willst. Für Prozeduraufrufe z.B. gibt es afaik "call", welches dir eine Rücksprungadresse auf den Stack legt (schließlich möchte deine Prozedur die Kontrolle auch zurückgeben), dann gibt es noch bedingte Sprünge, d.h. der Prozessor wird nur springen, wenn bestimmte Flags gesetzt sind o.Ä.

P.S:  Der Assembler-Code ist ohne jegliche Gewähr, ich hab in letzter Zeit mehr mit MIPS-Assembler als mit x86-Assembler zu tun.
« Letzte Änderung: 15. February 2013, 16:00 von TheThing »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 15. February 2013, 16:04 »
Darum habe ich dir übrigens mal Bücher zum Thema empfohlen, lieber KTvuzG.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 15. February 2013, 16:05 »
@Svenska: Ich hab mir doch Bücher ausgeliehen, allerdings verstehe ich das Zeug trotzdem nur so halb!

Eine Frage noch: Wie springe ich in einen Hardwaretask, und vor allem, wie mache ich das, wenn ich gar kein Multitasking nutze?

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 15. February 2013, 17:02 »
dann gibt es noch bedingte Sprünge, d.h. der Prozessor wird nur springen, wenn bestimmte Flags gesetzt sind o.Ä.
z.b JLE und JL Für mehr Infos hierzu siehe :
http://www.lowlevel.eu/wiki/Teil_2_-_Assembler_101 Absatz "Vergleiche und Sprünge"

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 16. February 2013, 03:10 »
Eine Frage noch: Wie springe ich in einen Hardwaretask, und vor allem, wie mache ich das, wenn ich gar kein Multitasking nutze?
Dazu musst du den Hardwaretask finden. Ohne Multitasking ist das ziemlich unmöglich, damit kannst du da auch nicht reinspringen. :-)

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 16. February 2013, 13:30 »
Hmm, naja, wenn ich kein Multitasking habe, ist das doch quasi ein einziger Task in Ring 0, oder?
Dann brauche ich doch nur noch einen zweiten, der in Ring 3 läuft.

Währenddessen muss ja der in Ring 0 nicht weiterlaufen, ich brauch das ja nur ganz kurz am Anfang...

Oder?

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 16. February 2013, 15:23 »
Hallo,

wenn du kein Multitasking hast, hast du nur einen Ring0-Task, das stimmt soweit. Allerdings kannst du diesen Task nicht anspringen, da ihm die notwendigen Datenstrukturen (TSS) fehlen. Für die CPU ist es also kein Task, sondern nur ein Haufen Programmcode. Wenn dein Kernel im Ring 0 weiterlaufen soll, musst du ihn erst zu einem Task machen; das macht man aber üblicherweise nicht.

Der Kernel erzeugt normalerweise einen (Monolith) oder mehrere (Microkernel) Ring3-Tasks und endet in dem Augenblick, wo er den Scheduler aktiviert. Jeder Task, der dann etwas vom Kernel möchte, tut das über einen Syscall, der zwar den CPU-Modus wechselt (in den Ring 0), aber kein Taskwechsel ist.

Gruß,
Svenska

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 16. February 2013, 16:02 »
Der kann doch eigentlich problemlos in Ring 0 bleiben, wüsste nicht, wo da das Problem ist...?

Meine Recherche zu TSS ergibt: http://www.lowlevel.eu/wiki/Task_State_Segment.

Aha. OK. Muss ich dann wohl machen.  :|

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 16. February 2013, 16:22 »
Der kann doch eigentlich problemlos in Ring 0 bleiben, wüsste nicht, wo da das Problem ist...?
Kannst du. Das ist aber unabhängig vom grundsätzlichen Multitasking.

Verschiedene Tasks sind unabhängig voneinander, das heißt sie haben verschiedene Register, verschiedene Stacks, verschiedene Program Counter, (verschiedene Dateideskriptoren, verschiedene Speicherblöcke, verschiedene ... - je nachdem, was dein OS unterstützt). Der Ring ist da eher nebensächlich. Normalerweise hat man alle Tasks in Ring 3 und führt Kernel-Code im Ring 0, aber im Kontext des zuletzt laufenden Tasks aus. Wenn du nun alle Tasks in Ring 0 verlegst, kann jeder Task dein System zum Absturz bringen, einfacher wird es dadurch aber nicht (wenn du es vernünftig implementieren möchtest).

Gruß,
Svenska

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 16. February 2013, 16:34 »
Macht ja nichts, ich hab dann ja nur einen Task (den in Ring 0), den zweiten (in Ring 3) brauch ich ja nur für VM86... (ich beende den dann einfach sofort wieder)
« Letzte Änderung: 16. February 2013, 16:36 von KtmnjjpfjsFvzG »

w_ciossek

  • Beiträge: 2
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 24. June 2013, 15:47 »
So wie ich es sehe, sind viele Antworten bezüglich zu einem Prozessor (80x86) geschrieben worden.
Allgemein und unabhängig vom Prozessortyp kann man sagen, daß ein Sprung nichts weiteres ist, daß ein Register welcher der Befehlszähler ist, mit einem Adresswert geladen wird. Im Prinzip kann ein Prozessor ohne Sprungbefehle auskommen, wenn beispielsweise ein Move-Befehl wie move <Programmzähler>,<Adresswert> existieren würde. Ein Jump-Befehl tut genau dieses, wo der Programmzähler nicht explizit angegeben werden muß.
Einige Jump-Befehle werden nur in Abhängigkeit von Flags ausgeführt, so daß nach einer Bedingung gesprungen wird, sofern sie erfüllt ist, oder der Jump-Befehl wird ignoriert und der Programmzähler erhöht sich um den Betrag, um den nächsten folgenden Befehl auszuführen.

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 24. June 2013, 17:49 »
So wie ich es sehe, sind viele Antworten bezüglich zu einem Prozessor (80x86) geschrieben worden.
Allgemein und unabhängig vom Prozessortyp kann man sagen, daß ein Sprung nichts weiteres ist, daß ein Register welcher der Befehlszähler ist, mit einem Adresswert geladen wird. Im Prinzip kann ein Prozessor ohne Sprungbefehle auskommen, wenn beispielsweise ein Move-Befehl wie move <Programmzähler>,<Adresswert> existieren würde. Ein Jump-Befehl tut genau dieses, wo der Programmzähler nicht explizit angegeben werden muß.
Einige Jump-Befehle werden nur in Abhängigkeit von Flags ausgeführt, so daß nach einer Bedingung gesprungen wird, sofern sie erfüllt ist, oder der Jump-Befehl wird ignoriert und der Programmzähler erhöht sich um den Betrag, um den nächsten folgenden Befehl auszuführen.
Ja ein unbedingter Sprung ist nichts anderes als ein mov $Addresswert, %eip in X86. Allerdings deutest du auch schon an das es bedingte Sprünge gibt etwa jnz jz jl jg etc.. Da sich auf X86 nur diese Sprünge bedingt ausführenlassen, sind Sprung Anweisungen als Implementierung von if else in den Hochsprachen unumgänglich. Interessant ist hier allerdings ARM; Dort lässt sich jede Instruktion durch einen Suffix bedingt ausführen. jz entspräche dann:

cmp r0. r1
moveq r15, #addr

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 24. June 2013, 21:55 »
Im Prinzip kann ein Prozessor ohne Sprungbefehle auskommen, wenn beispielsweise ein Move-Befehl wie move <Programmzähler>,<Adresswert> existieren würde.
Ein Prozessor kann ohne Sprungbefehle auskommen, wenn er zum Beispiel einen Sprungbefehl hätte?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #16 am: 25. June 2013, 12:33 »
Im Prinzip kann ein Prozessor ohne Sprungbefehle auskommen, wenn beispielsweise ein Move-Befehl wie move <Programmzähler>,<Adresswert> existieren würde.
Ein Prozessor kann ohne Sprungbefehle auskommen, wenn er zum Beispiel einen Sprungbefehl hätte?
Nein, bei x86 ist es so, dass in den Programmzähler nicht direkt geschrieben werden kann, also dass "mov $Adresse,%eip" ein Fehler erzeugt. Ob man daraus lesen kann, weiss ich gerade nicht.
Aber wenn das möglich wäre (also das Schreiben in den IP), dann bräuchte es keine JMP-Befehle mehr.
Viele Grüsse
OsDevNewbie

Ein Computer ohne Betriebsystem ist nicht mehr wert als ein Haufen Schrott.
Ein Computer ist eine Maschine, die einem Lebewesen das kostbarste klaut, was sie selber nicht hat:
DIE ZEIT DES LEBENS

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 25. June 2013, 13:50 »
Nein, %eip kann man nicht in Operanden reinkodieren. Lesen oder schreiben macht dafür keinen Unterschied.

Mein Punkt war, dass du selbst wenn du den jmp-Opcode loswirst und dafür mov ..., %eip einführst, du immer noch einen Sprungbefehl hast. Der wäre dann eben als mov statt als jmp kodiert, aber das macht ihn ja nicht weniger sprungbefehlig.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Jonathan

  • Beiträge: 22
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 25. June 2013, 17:31 »
Ein mov ..., %eip ist nicht möglich - weil bei einem jmp noch zusätzliche Logik dabei ist, die ein Leeren der Pipeline und eine Synchronisation macht. Ansonsten würde es seeeehr tolle Effekte bei einem Sprung geben, wie z.B. sowas, dass einige der Befehle hinter dem Sprung noch ausgeführt werden (oder sogar nur Teile davon) und dann erst die neuen Befehle vom neuen eip kommen - verursacht durch Out of Order Execution und Pipelining.

Ein Sprung ist deshalb das Neuladen des IP gekoppelt mit einer Initialisierung der CPU auf die neue Adresse.


Gruß
Jonathan
« Letzte Änderung: 25. June 2013, 17:33 von Jonathan »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 25. June 2013, 20:35 »
Naja, dass der Befehl als mov kodiert ist, müsste ja nicht zwingend heißen, dass es keine Nebeneffekte gibt, wenn der Zieloperand %eip ist. Aber du hast schon recht, daran hatte ich nicht gedacht und es ist ein guter Hinweis.

Beim MIPS ist das mit den Delay Slots ja noch vorhersehbar und macht auf eine gewisse Weise sogar Spaß, aber bei der Komplexität heutiger x86-Prozessoren würde ich das eher nicht wollen...
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen