Assemblerproblem

Ich weiss, Assembler gehört nicht zu den
höheren Programmiersprachen. Ich habe aber
kein passendes Forum gefunden.
Meine Frage:
Ich habe mich in letzter Zeit mit TSRs
und den Interupts beschäftigt. Dabei
habe ich gelesen, das einerseits die
Funktion 4Fh des Int 21h unter manchen
Umständen das Carry-Flag verändert.
Andererseits habe ich gelesen, dass die
CPU bei der Bearbeitung von Interupts
zuerst das Flagregister auf den Stack
sichert. Wie kann dann aber eine Interupt-
funktion das Carry-Flag dauerhaft verändern?

–Jan Vornberger

Hi Jan,

da machen sich ja so etwas wie nostalgische Gefühle bei mir breit. Das ist ja noch eine Frage aus der Zeit, als Computer riesige Kisten mit grünflimmernden Monitoren waren und es noch den fairen und ehrlichen Kampf Mann gegen Maschine gab! :wink:

Nun aber zur Sache: Ab dem AT sind die ersten 16 Interrupts (00h - 0Fh) Hardware-Interrupts. Diese werden durch Hardware-Ereignisse (Timer, Schnittstellen, etc.) ausgelöst. Der Aufruf aus einer Software heraus ist prinzipiell möglich, macht wenig Sinn, da ja in der Regel das zugehörige Hardware-Ereignis nicht zur Verfügung steht. Alle Interrupts mit höherer Nummer sind Software-Interrupts (BIOS, DOS, etc.), welche über int aufrufbar sind. Beim Aufruf der Hardware-Interrupts wird das Flagregister automatisch auf den Stack gelegt, bei den Software-Interrupts nicht. Diese Tatsache muß eben berücksichteigt werden, wenn man eigene Handler für die Interrupts programmiert.

War es das?

Gruß
Ted

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Vielen Dank! Jetzt ist es mir klar. Nur
noch eine Frage: Der Befehl IRET sichert
aber immer das Flagregister zurück, egal
ob es vorher gesichert wurde oder nicht,
richtig? Man muß also RET benutzten.
Restauriert IRET auch das CS-Register und
die IP wieder vom Stack?

–Jan Vornberger

Hi again!

Leider ist eines meiner Assembler-Bücher beim letzten Umzug auf der Strecke geblieben, so daß ich für den iret-Befehl keine Dokumentation mehr habe. Meine letzten Assembler-Programme habe ich auch vor ca. 7 Jahren geschrieben.

Vielleicht wirst Du ja im Netz fündig.

Gruß
Ted

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo !

Ich habe vor ein paar Jahren mal TSR’s unter DOS geschrieben.
Geht es bei Deinem Problem eigentlich wirklich nur um das Carryflag ? Oder hast Du vielleicht Probleme mit undefinierten Abstuerzen waehrend INT21h aufrufen aus TSR’s.
Ich bin mal in folgende Falle getreten:
Ich habe eine TSR- Uhr fuer DOS geschrieben. Sobald das TSR-aktiv war sind mir der Norton Commander oder alle moeglichen anderen DOS Programme abgestuerzt.
Der Grund lag im DOS. DOS hat interne Variablen und mehrere interne Stacks. DOS ist nicht wiedereintrittsfaehig-> d.h. wenn z.B. der Norton Commander gerade auf irgendwelche DOS - Funktionen zugreift kann er durch den TIMER- Interrupt meiner Uhr unterbrochen werden. Das TSR rief andere Funktionen des Int 21h (z.B. Uhrzeit lesen , Bildschirm schreiben) auf. Diese Aufrufe veraendern die internen Variablen und Stack- Inhalte von DOS. Ist die Interrupt-Routine beendet, faehrt der Prozessor nach dem IRET-Befehl mit der Ausfuehrung der unterbrochenen Int21h Funktion fort. Wenn das DOS- Stacksystem inzwischen veraendert wurde, kommt es dann meist zu Abstuerzen.
Die Loesung des Problems liegt leider darin keine DOS (Int21h und den anderen DOS- Interrupt) Funktionen in TSR’s zu benutzen. Die Uhrzeit habe ich mir vom BIOS geholt (in Sekunden seit Mitternacht). Die Bildausgabe habe ich durch direktes Schreiben in den Bildwiederholspeicher realisiert. Bios Funktionen sind wiedereintrittsfaehig-> d.h. Bios-Interrupts koennen sich selber unterbrechen.
Ich bin hinter dieses Problem erst nach einigen Wochen gekommen, als ich bei der Programmierung von Mikrocontrollern auf ein aehnliches Problem gestossen bin.
Oder willst Du nur wissen, wie es die Funktion 4fh schafft, das Carry-Flag zur Rueckgabe des Ergebnisses zu benutzen ? Der IRET-Befehl holt ja den Inhalt des FLAG-Registers bei der Rueckkehr aus einer Interrupt- Routine vom Stack. Die Funktion 4Eh braucht lediglich den letzten Stackwert zu poppen den Wert des Carry- Bits zu aendern und dann den Wert wieder auf den Stack zu pushen. Der IRET schiebt dann den modifizierten Wert ins Flag- Register.
So einfach gehts denke ich.

MfG

Andreas

Oder willst Du nur wissen, wie es die
Funktion 4fh schafft, das Carry-Flag zur
Rueckgabe des Ergebnisses zu benutzen ?

Das wollte ich wissen, aber trotzdem vielen
Dank für die interessante Vorgeschichte.

Der IRET-Befehl holt ja den Inhalt des
FLAG-Registers bei der Rueckkehr aus
einer Interrupt- Routine vom Stack. Die
Funktion 4Eh braucht lediglich den
letzten Stackwert zu poppen den Wert des
Carry- Bits zu aendern und dann den Wert
wieder auf den Stack zu pushen. Der IRET
schiebt dann den modifizierten Wert ins
Flag- Register.
So einfach gehts denke ich.

Ted Striker (siehe unten) schrieb doch,
dass bei Softwareinterupts zu (denen der
int 21h gehört) das Flagregister nicht
gepusht wird. Einer von euch beiden muss
also unrecht haben. Zu deiner Theorie:
Nachdem das Flagregister gepusht wurde,
wird aber auch noch CS und IP gepusht.
Will man also die Flags verändern, müsste
man diese beiden Werte auch noch poppen und
später wieder pushen. Ok, dass sollte
eigentlich kein Problem sein, aber ich
wollte es nur anmerken.

–Jan Vornberger

Was ich noch vergass…
Ich denke ich habe eine Lösung, für dein
Problem, dass dich zwingt, keine
Dos-Funktionen zu benutzen. Wenn du
dich an die Interupts 28h oder 2Fh hängst,
kannst du den int 21h gefahrlos benutzen.
Die Interupts 28h und 2Fh werden immer
dann ausgeführt, wenn die CPU nichts
zu tun hat, z. B. wenn ein Programm gerade
auf eine Eingabe wartet.

–Jan Vornberger

Ted Striker (siehe unten) schrieb doch,
dass bei Softwareinterupts zu (denen der
int 21h gehört) das Flagregister nicht
gepusht wird. Einer von euch beiden muss
also unrecht haben.

Das will ich mich lieber nicht drueber streiten, da noch keine Softwareinterrupt ausgetauscht habe ??? Von dieser Eigenart der Softwareinterrupts habe aber noch nichts gewusst.

Zu deiner Theorie:
Nachdem das Flagregister gepusht wurde,
wird aber auch noch CS und IP gepusht.

Da hast Du recht. Ich unterlag dem Irrtum, dass das Flagregister zuletzt gepusht wird, dass stimmt aber nicht. Wenn Du den Zeiger
auf eine Interruptroutine hast, sie aber aus der Interruptvektortabelle entfernt hast (bei mir der alte Timer- Interrupt) kannst Du das Ding auch mit call aufrufen:

PUSHF
CALL DWORD PTR OLD_INT

Hier pushe ich das Flagregister zuerst auf den Stack CALL tut dann noch CS und IP dazu.
Lange Rede kurzer Unsinn-> hab ich zwar falsch geschrieben aber schon mal richtig programmiert.

Will man also die Flags verändern, müsste
man diese beiden Werte auch noch poppen
und
später wieder pushen. Ok, dass sollte
eigentlich kein Problem sein, aber ich
wollte es nur anmerken.

–Jan Vornberger

Na ja !

Bin halt schon ein bisschen aus der Assembler - Uebung und C++ verweichlicht.

Hi!

Wenn Du mit
INT 21h
einen DOS-Interrupt aufrufst, dann passiert mit dem Stack und dem Aufruf genau das selbe, als ob der Prozessor einen Hardware-Interrupt ausführt. Ersatz-„Schau“-Bild:

PUSHF
CALLF [IntVec]

Du mußt bei jeder Interrupt-Service-Routine (egal ob Hardware- oder Software-Interrupt) immer mit
IRET
beenden.

Das muß auch der INT21, was er aber nicht tut. Natürlich nicht, einige DOS-Funktionen geben ja einen eventuellen Fehler im Carry-Flag zurück. Da tut er vor dem IRET (wenns überhaupt sowas is und kein normaler RET) aufm Stack rumschreiben. Und zwar genau das eine WORD, wo die Flags drin sind.

Das mit dem Hardware-Interrupt 00h-0Fh ist nicht ganz richtig. Das sind die Exceptions! Das sind „Fehlermeldungen“ direkt vom Prozessor. In Windows ein „Allgemeiner Ausnahmefehler“ ist sowas zB.

Intel hat schon beim 8088 (der Urvater vom 80386) schon gesagt, daß sie sich die Interrupts 00h-1Fh reservieren, die soll niemand verwenden. Die Deppen von IBM-PC-Erfinder haben aber dagegen verstoßen und die Hardware-Interrupts im PC (und später auch im AT) auf 08h-0Fh gelegt. Darum gibts da immer Konflikte mit den Exceptions, die (weil sich Intel das ja reserviert hat) die selben Interrupt-Nummern verwenden. Ab dem AT ist dann ein zweiter Interrupt-Controller eingebaut, der den Bereich A0h-A8h macht. Das is ok.

Aber nochmal: Hardware- und Software-Intertupts verhalten sich am Stack exakt gleich.

Bye
Hansi