Problem mit NASM?


15.03.2020, 16:05

Besser zum lesen weil GF so genial ist *NICHT*:

len:;eax Zahl und später Länge

 push  edi

 push  ebx

 push  esi

 mov   esi, 0

 mov   edi, eax

 call  len_count

len_count:

 mov   eax, edi

 mov   ebx, 10

 idiv  ebx

 call  resetcalc

 mov   edi, eax

 cmp   eax, 0

 je   len_iszero

 inc   esi

 jne   len_count

len_iszero:

 mov   eax, esi

 add   eax, 1

 pop   esi

 pop   ebx

 pop   edi

 ret

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Ich habe zwar keine Ahnung, was die resetcalc Funktion macht, aber ich glaube die Zeile 'call len_count' ist der Übeltäter.

Die Sprungposition 'len_count' muss eigentlich nicht mit 'call' aufgerufen werden, ich glaube diese Zeile 'call len_count' ist überflüssig.

Das führt dazu das die Rücksprungadresse nach der Instruktion 'call len_count' auf den Stack gelegt wird, und scheinbar nie wider heruntergekommen wird.
Das wiederum führt dazu das die Werte in edi, ebx und esi falsch wiederhergestellt werden und wenn die Funktion wider zurückspringen will, die Adresse vom Register edi nimmt.

Woher ich das weiß:Hobby
Simon221585 
Fragesteller
 16.03.2020, 14:58

Ich lege in der len_count Routine doch nichts auf den Stack? resetCalc setzt nur mit XOR eax und ebx zurück. Die Subroutine laufen durch und liefern auch das richtige Ergebnis.

Es war nicht immer len_count, hatte davor eine extra Subroutine, die nichts anderes gemacht hat, als len_count wieder aufzurufen, selber Fehler. Ich brauche ja hier eine Art Schleife, es wird ja solange durch 10 dividiert bis das Ergebnis null ist. Zähler + 1 ist dann die Länge meiner Zahl.

0
Klawutzel  16.03.2020, 15:19
@Simon221585

Nicht in der Routine, aber durch den Aufruf mit 'call len_count' legst du die Rücksprungadresse auf den Stack.

Diese wird normalerweise mit 'ret' wider vom Stack genommen, aber in deinem Code scheinst du am Ende der 'len_count' Routine mit 'je   len_iszero' rauszuhüpfen.

Die Rücksprungadresse wird nie vom Stack genommen, und das führt zu dem in meiner Antwort beschriebenen Fehler.

So wie ich das sehe, kannst du die Zeile 'call len_count' entfernen oder durch ein 'jmp len_count' ersetzen.

1
Simon221585 
Fragesteller
 16.03.2020, 16:08
@Simon221585

Also wenn ich call mache, muss ich immer mit ret zurück, weil sonst die Rücksprungsadresse im Stack für immer verbleibt und jmp nutzt nicht den Stack?

1
Klawutzel  16.03.2020, 16:14
@Simon221585

Die jmp springt einfach nur zu einer Adresse.
Die call legt den instruktion pointer (eip) auf den Stack und die ret nimmt diesen wider vom Stack.

1

Hallo,

die Frage ist zwar schon einige Tage alt aber ich denke hier werden sicherlich noch weitere interessierte Leser aufmerksam.

Der Fehler liegt "auf dem Stack":

  1. Es werden die Register edi, ebx und esi auf den Stack abgelegt.
  2. Mit "call  len_count" wird die Rücksprungadresse auf den Stack gespeichert. Somit wird der Stackpointer auch weitergeschoben und zeigt nicht mehr auf den Inhalt des esi-Registers (der letzte push-Befehl).
  3. Die pop-Befehle am Ende des Programms holen deshalb nicht die oben gesicherten Register wieder vom Stack, sonder die Rücksprungadresse des call-Befehls worauf der ret-Befehl im Nirwana landet.

So, ich hoffe ich konnte hier einigen Lesern weiterhelfen.

MatzeL aus H.