Verstehe PUSH / POP nicht ganz
-
Vielen Vielen Dank!
Jo hier ist es sinnlos, aber bei einer weiteren Berechnung (QUADER) wird RECHTECK ge "call"ed, und dann macht es sinn denke ich, aber vielen dank erstmal.
-
Sehr trickreich das Ganze:
Aber nicht unbedingt schlau, oder übersehe ich da was?
-
Hallo, ich habe das mal bis
rechteck proc near add sp,2 pop bx pop ax
skizziert, stimmt so der ablauf im stack?
Ich bin mir bei schritt 4 sehr unsicher, was dem SP angeht.
Eine Frage auch noch: Wird IMMER von oben nach unten (Last In, First Out) gepopped - hat das poppen einen zusammenhang mit dem SP? Und was würde passieren wenn man SP nicht um 2 erhöht?
-
BunterVogel schrieb:
Verschiebe bei Deiner Skizze nur den SP-Zeiger und lasse AX, BX und RA immer an derselben Stelle, dann wird es klarer. Hilfreich ist auch, wenn Du Dir einen Schritt 0 aufzeichnest, der den Zustand von Stack und Zeiger vor der ganzen Stapelei zeigt.
ad 1) push ax; push bx
`bx <--- SP
ax`
SP zeigt auf den letzten gepushten Wert.
ad 2) call ...
`RA <--- SP
bx
ax`
SP zeigt auf die Rückkehradresse
ad 3) add sp, 2
`RA
bx <--- SP
ax`
SP zeigt auf bx. RA ist noch vorhanden, aber freigegeben, das ist das, was Bashar wohl als nicht schlau bezeichnet hat.
ad 4) pop bx; pop ax (so herum!)
`RA
bx
ax
<--- SP`
SP zeigt jetzt dahin, wohin es ganz am Anfang gezeigt hat. RA ist ungeschützt.
- push ax; push bx
`RA
bx <--- SP
ax`
AX und BX haben jetzt neue Werte. RA ist immer noch ungeschützt.
- add sp, -2
`RA <--- SP
bx
ax`
SP zeigt jetzt auf die Rückkehradresse. Hoffentlich ist bis dahin kein Timer-Interrupt passiert.
- ret
`RA
bx <---SP
ax`
RET kehrt zur Rückkehradresse zurück. SP zeigt jetzt auf die veränderten Werte.
- pop bx; pop ax
`RA
bx
ax
<---SP`
AX und BX sind mit den veränderten Werten geladen. SP hat jetzt wieder den Ursprungszustand.
PUSH, POP, CALL und RET verändern alle den SP-Zeiger und greifen immer in LIFO-Manier auf den Stack zu.
viele grüße
ralph
-
danke
bis ad 3) versteh ich das
aber bei 4) sind ja BX und AX immer noch im Stack,obwohl man die ja gepoppt hat?
und wenn man poppt, übernimmt man doch immer erst den Wert ganz oben, was ja RA ist in dem Fall ist, oder seh ich da was falsch
-
BunterVogel schrieb:
aber bei 4) sind ja BX und AX immer noch im Stack,obwohl man die ja gepoppt hat?
Ja, das ist der Trick bei der Sache: POP löscht nicht den Inhalt des Stacks, sondern verschiebt nur den Stackzeiger SP. Der Inhalt ist noch da - aber ungeschützt. Er kann durch ein anderes Ereignis (z. B. ein Interrupt) überschrieben werden. Das ist wie mit gelöschten Dateien: Sie sind nicht wirklich verloren und können durch Recovery-Programme wiederhergestellt werden.
und wenn man poppt, übernimmt man doch immer erst den Wert ganz oben, was ja RA ist in dem Fall ist, oder seh ich da was falsch
Man übernimmt den Wert ganz oben und verschiebt den Stackzeiger nach unten, so dass jetzt der Wert eins weiter unten jetzt "ganz oben" ist. Bei 3) war bx ganz oben; 4): einmal gepopt: ax ist jetzt ganz oben, noch einmal gepopt: Ursprungszustand ist ganz oben. Nochmal: "ganz oben" ist da, wo der Stackzeiger hinzeigt.
viele grüße
ralph
-
hmmmm vielen dank, damit dem gem ganz oben ist mir jetzt klarer geworden. also wenn man POPPt, dann holt man einfach den Wert heraus wo der SP Zeiger ist.
Aber was ich immer noch nicht kappiere ist, ob das ganze Theater nicht einfacher wäre mit
mul BX
Mein Professor meinte was mit, dass die Originalwerte durch diese Stack Methode gesichert werden könnten und später herausgepoppt, aber in diesem Fall ist das ja nicht so. Was ist auch merkwürdig finde ist, dass AX und BX in den stack gepushed werden und bevor die Multiplikation durchgeführt wird wieder gepopped wird - also einmal rein in den Stack und einmal raus aus dem stack^^
EDIT:
writes amsg ;Ausgabe Eingabeaufforderung readz a mov ax,a ;Seite A in AX writes bmsg ;Ausgabe Eingabeaufforderung readz b mov bx, b ;Seite B in BX call rechteck ;Aufruf Prozedur mov flaeche, ax ;Ergebnis in flaeche packen writez flaeche ;Ausgabe Ergebnis jmp ende ;Sprung ans Ende rechteck proc near ;Zeiger im Stack zwei tiefer zeigen mul bx ;multipliziere ax mit bx, ergebnis in ax jo zugross ret ;return zum Hauptprogramm endp
Hab das mal so gemacht, geht auch. Ich weiß nicht was das mit dem Stack bringen soll^^
-
BunterVogel schrieb:
Aber was ich immer noch nicht kappiere ist, ob das ganze Theater nicht einfacher wäre mit
mul BX
In diesem Fall wäre es das auch. Es handelt sich nur um ein Beispiel mit einer einfachen Funktion. Stelle Dir vor, es wäre eine Sinus-Berechnung, die von ganz verschiedenen Stellen im Programm aufgerufen wird.
Mein Professor meinte was mit, dass die Originalwerte durch diese Stack Methode gesichert werden könnten und später herausgepoppt, aber in diesem Fall ist das ja nicht so. Was ist auch merkwürdig finde ist, dass AX und BX in den stack gepushed werden und bevor die Multiplikation durchgeführt wird wieder gepopped wird - also einmal rein in den Stack und einmal raus aus dem stack^^
Wie gesagt: Es handelt sich nur um ein Beispiel. Es geht darum, wie Argumente an eine Funktion übergeben werden und wie Ergebnisse zurückgegeben werden. Die vorgestellte reine Stacklösung ist nur eine Möglichkeit. Deine Lösung (Übergabe und Rückgabe über die Register) ist eine andere Möglichkeit. Es gibt noch mehr Möglichkeiten ("Calling Conventions").
Ich weiß nicht was das mit dem Stack bringen soll^^
Nur ein Beispiel: Stell Dir zwei Programmierer vor, einer soll das Hauptprogramm schreiben, ein anderer ein paar Unterprogramme. Wenn der eine eine Funktion aufruft, macht er sich über die Register keine großen Gedanken über Register, schiebt alles auf den Stack, und holt sich alles aus dem Stack. Wenn der andere eine Funktion schreibt, macht er sich keine großen Gedanken über die Register im Hauptprogramm, holt sich alles aus dem Stack und schiebt die Ergebnisse in den Stack. Muss die Funktion z. B. um siebzehn Argumente erweitert werden: kein großes Problem, der eine schiebt siebzehn Werte mehr auf den Stack, der andere holt sich siebzehn Werte mehr vom Stack.
viele grüße
ralph
-
%§§"
-
BunterVogel schrieb:
... push ax ret endp ...
Ich habe mir gestern meinen Entwicklungsrechner mit VIRUT.BM krank gemacht. Deswegen kann ich momentan Deinen Code nicht sauber durchtesten und kein Beispiel entwerfen. Obiger Schnippsel kann aber nicht funktionieren:
push ax: AX wird auf den Stack gepusht. Oberster Wert ist AX.
ret: CPU holt sich den obersten Wert vom Stack und springt dahin. Da der oberste Wert aber nicht die Rückkehradresse sondern AX ist, springt die CPU sonstwohin.Pass auf, dass Dir die Makros nicht in die Register pfuschen. Am besten postest Du mal die relevanten Makros (writes, readz).
viele grüße
ralph
-
Jo hab's kappiert