Übungsprogramm klappt nicht richtig



  • hey 🙂
    ich wollte bisschen Üben und ein Programm schreiben, welches 5 Werte entweder addiert oder subtrahiert. Irvine32.inc stellt mir paar funktionen zum console input-output zur verfügung, wundert euch deswegen nicht (WriteString ReadHex etc.). Jedenfalls klappt alles soweit, aber wenn ich z. b. 5 mal 10 eingebe dann gibt es 80 als Ergebnis aus. Woran liegt das? Ihr könnt mir auch andere Sachen sagen die ich schlecht gemacht habe oder sagen was man besser machen könnte! Danke

    TITLE Calculator (Calculator.asm)
    
    INCLUDE Irvine32.inc
    
    .data
    addOrSubQ BYTE "Welcome! Do you want to add or subtract values? (1 = add, 2 = sub)", 0
    promptMessage BYTE "Pls tell me 5 values!", 0
    resultMessage BYTE "Here is the result: ", 0
    againOrNotQ BYTE "Do you want to calculate again? (1 = yes, 2 = no)", 0
    
    .data?
    values DD 5 DUP(?)
    addOrSubA DD ?
    result DD ?
    againOrNotA DD ?
    
    .code
    main PROC
    
    	mov eax, 10
    	call SetTextColor ; chance color
    start::
    	call addOrSub
    	call promptForValues
    	call calculateResult
    back::
    	call printResult
    	call againOrNot
    	call WaitMsg
    	exit
    
    main ENDP
    
    ; gives back the result (1 Or 2) to eaxreg
    addOrSub PROC
    	mov edx, OFFSET addOrSubQ
    	call WriteString
    	call crlf
    	call ReadHex ; read input
    	mov addOrSubA, eax
    	ret
    addOrSub ENDP
    
    promptForValues PROC
    	mov edx, OFFSET promptMessage
    	call WriteString
    	call crlf
    	call ReadHex
    	mov values, eax
    	call ReadHex
    	mov [values + 4], eax
    	call ReadHex
    	mov [values + 8], eax
    	call ReadHex
    	mov [values + 12], eax
    	call ReadHex
    	mov [values + 16], eax
    	call crlf
    	ret
    promptForValues ENDP
    
    calculateResult PROC
    	cmp addOrSubA, 1
    	JE addValues
    	cmp addOrSubA, 2
    	JE subValues
    	ret
    calculateResult ENDP
    
    addValues::
    	mov eax, values
    	add eax, [values + 4]
    	add eax, [values + 8]
    	add eax, [values + 12]
    	add eax, [values + 16]
    	mov result, eax
    	jmp back
    subValues::
    	mov eax, values
    	sub eax, [values + 4]
    	sub eax, [values + 8]
    	sub eax, [values + 12]
    	sub eax, [values + 16]
    	mov result, eax
    	jmp back
    
    printResult PROC
    	mov edx, OFFSET resultMessage
    	call WriteString
    	mov eax, result
    	call WriteInt
    	call crlf
    	ret
    printResult ENDP
    
    againOrNot PROC
    	mov edx, OFFSET againOrNotQ
    	call WriteString
    	call crlf
    	call ReadHex
    	mov againOrNotA, eax
    	cmp againOrNotA, 1
    	JE start
    	ret
    againOrNot ENDP
    END main
    


  • Zur eigentlichen Frage:
    Du liest dem Prozedurnamen "ReadHex" zufolge offenbar hexadezimale Zahlen (Basis 16, Ziffern 0-F) ein.
    "WriteInt" scheint jedoch Zahlen dezimal (Basis 10, Ziffern 0-9) auszugeben.
    Nun ist 10 hexadezimal gleich 16 dezimal. Dh. 5*10=50 hexadezimal ist 5*16=80 dezimal. Um Verwirrung vorzubeugen waere es also zweckdienlich, Zahlen mit der selben basis einzulesen und auszugeben.

    Noch allgemein:
    In Assembler ist es idR. keine gute Idee, Prozeduren zur reinen Strukturierung zu benutzen. Das laeuft irgendwo dem Sinn und Zweck von Assembler zum Schreiben effizienter Programme entgegen.
    Um den Code und das Prinzip der Prozedur uebersichtlich zu halten sollte man es auch vermeiden, zwischen Prozeduren mit normalen Sprungbefehlen zu wechseln.
    So laesst du zB. auch mit jedem Sprung von "againOrNot" zum Label "start" die Ruecksprungadresse auf dem Stack liegen, was bei mehreren Wiederholungen zwangslaeufig irgendwann zu einem Stack-Ueberlauf fuehren wird.
    Ich wuerde also vorschlagen, bis auf die Prozeduren aus der .inc-Datei saemtliche Prozeduren aus deinem Code zu entfernen und deren Funktionalitaet direkt hin zu coden.



  • vielen Dank Nobou T! Jetzt verwende ich ReadDec.
    Und danke auch für die Tipps!



  • jetzt habe ich noch ein größeres Problem.
    Ich soll mit ADC ( das ja das carry mitaddiert) 2 64 bit ints addieren und das Ergebnis zeigen.

    TITLE Chapter7Exercise (Chapter7Exercise.asm)
    
    INCLUDE Irvine32.inc
    
    .data
    op1 QWORD 18446744073709551615
    op2 QWORD 18446744073709551615
    result BYTE "The result is: ", 0
    
    .data?
    sum DWORD 3 DUP(?)
    
    .code
    main PROC
    
    	mov esi, offset op1
    	mov edi, offset op2
    	mov ebx, offset sum
    	mov ecx, 2 ; number of dword
    
    	clc ; clear carry
    
    L1:  mov eax, [esi]
    	adc eax, [edi]
    	pushfd
    	mov [ebx], eax
    	add esi, 4
    	add edi, 4
    	add ebx, 4
    	popfd
    	loop L1
    
    	adc WORD PTR[ebx], 0
    	popad
    
    	mov edx, offset result
    	call WriteString
    	call crlf
    
    	mov eax, [sum + 8]
    	call WriteInt
    
    	mov eax, [sum + 4]
    	call WriteInt
    
    	mov eax, sum
    	call WriteInt
    
    	mov eax, 2000
    	call Delay
    	exit
    
    main ENDP
    END main
    

    Leider steig ich da nicht mehr durch. Außerdem ist in sum kein richtiges Ergebnis. Könnte sich das bitte jemand anschauen?



  • habs jetzt nochmal mit einer anderen Version probiert. Es wird aber auch nicht das richtige ergebnis ausgegeben.

    TITLE Chapter7Exercise (Chapter7Exercise.asm)
    
    INCLUDE Irvine32.inc
    
    .data
    op1 QWORD 18446744073709551615
    op2 QWORD 18446744073709551615
    result BYTE "The result is: ", 0
    
    .data?
    sum DWORD 3 DUP(?)
    
    .code
    main PROC
    
    	mov eax, DWORD PTR op1 ; low word of op1
    	mov ebx, DWORD PTR [op1+4] ; high word of op1
    
    	mov ecx, DWORD PTR op2 ; low word of op2
    	mov edx, DWORD PTR [op2+4] ; high word of op2
    	clc ; clear carry to be safe
    
    	mov sum, eax ; low word op1
    	adc sum, ebx ; high word op2
    
    	add sum, ecx ; low op2
    	adc sum, edx ; high op2
    
    	mov edx, offset result
    	call WriteString
    
    	mov eax, sum
    	call WriteDec
    
    	mov eax, sum[4]
    	call WriteDec
    
    	mov eax, sum[8]
    	call WriteDec ; sollte jetzt so aussehen als wäre es 1 zahl, da es   nacheinander geschrieben wird.
    
    	mov eax, 5000
    	call Delay ; sleep
    	exit
    
    main ENDP
    END main
    


  • Das Prinzip ist, dass du nacheinander das 1. dword des 1. op mit dem des 2. op (beim 1. brauchst du auch noch kein adc, da der Uebertrag sicher 0 ist - so sparst du dir auch das clc) addierst und im 1. dword des Ergebnisses speicherst. Dann das 2. dword des 1. op mit dem des 2. op und den Uebertrag aus der 1. Addition dazu im 2. dword des Ergebnisses. Zuletzt brauchst du nur noch den Uebertrag der letzten Addition (also das Carry-Flag CF) an das Ergebnis anhaengen. Geht zB. indem du auf das dritte (ein Byte wuerde hier reichen) ein adc mit 0 machst.

    Das sieht im Prinzip im 1. Code auch ganz gut umgesetzt aus und das Ergebnis sollte so weit ich das mit diesem Schnipsel beurteilen kann auch stimmen. Bleibt fuer diesen Code eigentlich nur anzumerken, dass das "popad" in z. 34 dort IMHO nichts zu suchen hat und dass man so kurze Schleifen (weniger als 4 Durchlaeufe) besser direkt ausrollen sollte (wie du es in deinem?, dem 2. Code versucht hast).

    Beim 2. Code kommst du jedoch irgendwie mit den einzelnen Summanden total durcheinander und addierst auch immer nur wirr auf das 1. dword der Summe drauf. Da kann nichts sinnvolles bei herauskommen.
    Weiter kannst du einen integer nicht sinnvoll als Dezimalzahl ausgeben, indem du ihn auf diese Weise Stueck fuer Stueck hintereinander konvertierst. Das geht wohl nur mit Zahlensystemen, deren Basis eine Potenz von 2 ist. Also zB. hexadezimal wie im 1. Code.

    Beispiel:
    Ein word aus 2 Bytes (01 01) wird derart byteweise konvertiert.
    Ergebnis dezimal:
    jeweils 1 -> 11 -> falsch. sollte 257 sein.
    Ergebnis hexadezimal:
    jeweils 01 -> 0101 -> stimmt.

    Beachte beim Ueberpruefen des Ergebnisses des 1. Codes auch, dass die beiden Summanden aus irgendeinem Grund dezimal angegeben sind.



  • 🙂 🙂 🙂
    danke! Hab es verstanden.


Anmelden zum Antworten