1

Ich möchte ein Programm erstellen, das Teilungsprobleme berechnen kann. Das Problem ist, dass mein Programm abstürzte, als ich versuchte, durch eine negative Zahl zu teilen, obwohl ich eine Verzweigung namens "DivNeg" erstellte, die verhindern sollte, dass es abstürzt. Hat jemand Ideen, wie man das beheben kann?Teilen Sie eine positive Zahl durch eine negative Zahl in Assembly

Hier ist mein Assembler-Code

.386 

.model flat 

public _Divide 

.code 

_Divide proc 
     mov eax, [esp + 4] ; First address ; this is the dividend 
     mov ebx, [esp + 8] ; Second address ; this is the divisor 

     cmp ebx, 0 
     je DivZero 
     cmp ebx, 0 
     jnae DivNeg 

     cdq 
     idiv ebx   ; To divide by eax by ebx 
     mov ebx, [esp + 12] ; Third address; this is the remainder 
     jmp Done1 

DivZero: 
    mov  eax,-1   ; If user divides by zero, this will set the result to negative 1 
    mov  edx, 0   ; If user divides by zero, this will set the remainder to 0 
    mov  ebx,[esp +12] ; Needed for the remainder if divided by 0 
    cmp  ebx, 0 
    je  Done2 


Done1: 
    mov  [ebx], edx 
    je Done1 

DivNeg: 
    cmp  ebx, 0 
    jge  Done2 
    mov  eax, -1 
    neg  eax 
    je  DivNeg 


Done2: 
     ret 
_Divide endp 

     end 
+4

nur vom ersten Blick; Du hast: 'je DivZero; Je DivNeg' eins nach dem anderen; und was sollte DivNeg tun? Warum gibt es einen Ascii eines '-'? –

+0

Ich habe die DivNeg-Schleife erstellt, so dass das Ergebnis und der Rest der Division durch eine negative Zahl angezeigt werden. Ohne es würde das Programm aus irgendeinem Grund abstürzen. Als Teil des DivNeg-Teils stelle ich das für den Fall auf, dass der Divisor kleiner als Null ist. – Jaquai

+2

Ich denke, du solltest ein bisschen mehr über asm lesen; die 'loop' macht keinen sinn - es ist eax> 0 es wird für immer loopen. Das ganze Problem ist ein wenig "seltsam" für die Aufgabe, die es tun sollte –

Antwort

1

cdq/idiv ebx nur #DE (Teile Exception) in 2 Fällen erhöhen:

  • eax = alles, ebx = 0. Division durch Null.
  • eax = 0x80000000, ebx = -1. Dies läuft über, weil die richtige Antwort nicht in eax passt. Die negativste Zahl (höchste Größe) in einer vorzeichenbehafteten Zweierkomplement-Darstellung hat keine Inverse. passt in eine vorzeichenbehaftete 32-Bit-Ganzzahl, aber +2^31 nicht. (In C ist dies der Grund, warum INT_MIN/-1 undefiniertes Verhalten ist.) Siehe Why does integer division by -1 (negative one) result in FPE? für weitere Details.

Es gibt keine Möglichkeit für cdq/idiv ebx mit einer positiven Dividende zu bemängeln und einem negativen Divisor, weil Überlauf nicht möglich ist. Sie verwenden cdq korrekt, um eax in edx:eax zu signieren. (Ohne das, es ist leicht möglich, 64b/32b => 32b Division das Ergebnis zu überfluten.)

Wenn Sie sich nicht auf idiv selbst abstürzt, dann haben Sie einen anderen Fehler und sollte einstufiges Code in einem Debugger. Im unteren Bereich des Tagwikis finden Sie Tipps zum Debuggen mit GDB oder mit Visual Studio.

+0

Ich habe es ein wenig aktualisiert: Unter 'je DivZero' habe ich 'cmp ebx, 0' und dann 'jnae DivNeg' hinzugefügt.Im 'DivNeg:' Schleife, war der Updates 'mov ebx, 0', \t 'cmp \t \t ebx, -1' \t 'JGE \t \t Done2' \t 'mov \t \t eax, -1' \t 'neg \t \t eax' \t 'je \t \t Done2'. Als ich das Programm debuggte, zeigte es das korrekte Ergebnis/Rest, aber dann stürzte es wieder ab und zeigte auf 'mov [ebx], edx' in der 'Done1' Schleife. – Jaquai

+0

@Jaquai: schau dir den Wert in 'ebx' an und finde heraus, warum es kein gültiger Zeiger ist. Ändern Sie den Code von früher im Programm und beobachten Sie, wie sich die Registrierungswerte ändern. –

+0

In der 'Done1'-Schleife soll' [ebx] 'das Ergebnis sein, während' edx' der Rest ist. Selbst nach dem Debuggen des Programms kann ich immer noch nicht herausfinden, warum es abgestürzt ist. Alles andere läuft ganz gut (außerhalb der Teilung durch Negative). Außerdem springt in der 'DivNeg'-Schleife nichts auf' Done1'. – Jaquai

1
mov eax, [esp + 4] ; First address ; this is the dividend 
mov ebx, [esp + 8] ; Second address ; this is the divisor 
... 
mov ebx, [esp + 12] ; Third address; this is the remainder 

Diese Kommentare zeigen, dass die Argumente an die Funktion sind Adressen. Dies bedeutet, dass Sie die Dereferenzierung durchführen müssen, bevor Sie an den Werten selbst arbeiten können. Sie haben das für das 3. Argument richtig gemacht, aber am 1. und 2. Argument gescheitert!

mov eax, [esp + 4] ; First address 
mov eax, [eax]  ; this is the dividend 
mov ebx, [esp + 8] ; Second address 
mov ebx, [ebx]  ; this is the divisor 

cmp ebx, 0 
je DivZero 
cmp ebx, 0 
jnae DivNeg 

Sie brauchen nicht die cmp Anweisung zu wiederholen. Die Flags bleiben für Ihren zweiten bedingten Sprung gesetzt. Auch weil die EQ-Bedingung aussortiert wurde, verwenden Sie am besten jna oder besser noch jl.

cmp ebx, 0 
je DivZero 
jl DivNeg 

Done1: 
mov [ebx], edx 
je Done1 

Sehr problematisch Code dieser! (Unendliche Schleife vs unerwünschten Fall durch).
Besser schreiben:

Done1: 
    mov [ebx], edx ;Return remainder 
    jmp Done2 

Wenn ich Sie wäre, würde ich meine Done1 Etikett, 3 Zeilen weiter oben, so dass die Kontrolle zum Schutz vor einem Nullzeiger setzen immer getan wird.

Done1: 
    mov ebx,[esp +12] ; Needed for the remainder if divided by 0 
    cmp ebx, 0 
    je Done2 
    mov [ebx], edx 
    jmp Done2 

Wenn sowohl die Dividende und die Teiler positiv sind, können Sie sicher div anstelle von idiv. Wenn der Dividend positiv ist und der Dividierer negativ ist, können Sie den Dividierer negieren, wie zuvor div verwenden, aber den Quotienten negieren.

DivNeg: 
    neg ebx 
    cdq 
    div ebx 
    neg eax 
    jmp Done1 
Verwandte Themen