Reputation: 11
I'm taking an x86 assembly programming class (it's mandatory for my major) and for some reason this code is outputting gibberish. I went to office hours and the professor wasn't sure why even after looking at my code.
Basically the professor wants us to use idiv and put things in the stack in order to pass them around from place to place.
I'm doing that but choosing certain numbers outputs gibberish along with the numbers or just plain gibberish.
I'm at a total loss of what to do.
Help would be appreciated.
.model flat, stdcall
.stack 4096
ExitProcess PROTO ,dwExitCode:DWORD
INCLUDE c:\irvine\Irvine32.inc ;Change path if necessary
include c:\irvine\macros.inc
includelib c:\irvine\irvine32.lib
includelib c:\irvine\kernel32.lib
includelib c:\irvine\user32.lib
.data
X DWORD 0
Y DWORD 0
A DWORD 90
B DWORD 0
W SDWORD ? ;W can be + or -
inputX BYTE "input X =", 0 ;IrvineLib WriteString expects null terminated string
inputY BYTE "input Y =", 0
outputW BYTE "output W=", 0
newline BYTE 0dh, 0ah, 0
calcW BYTE "calculating W....", 0
continue BYTE "Press Any Any key to continue or q to QUIT", 0
;
.code
main proc
call CrLf
topMain:
mov esi, offset InputX ;inputX=?
call getInput
mov X,eax
call CrLf
;
mov esi, offset InputY ;inputY=?
call getInput
mov Y, eax
call CrLf
mov edx, offset calcW ;print calculating W
call WriteString
call CrLf ; added this myself
push Y ; pass input PARAMETERS Right to left on STACK
push X
call calculateW
;Caller Cleans up the Stack
add esp,8 ;deallocate two 4Byte input parameters from stack
mov W,eax ;output parameter returned in register
mov edx, offset outputW ;Print "OutputW=""
call WriteString
push W ;input parameter on STACK
call outW
;Caller cleans up the Stack
add esp, 4 ;deallocate one 4-Byte input parameter from Stack
call CrLf
mov edx, offset continue ;prompt to continue or quit
call WriteString
call CrLf
call readchar ;this procedure does not echo
cmp al,'q'
jne topMain
invoke exitprocess,0
main endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
getinput proc
;Get Decimal Number from the keyboard and press enter key when done.
; ENTER key is CR = 0Dh
;This procedure calculates the binary equivalent of the decimal number it is typed and puts the result in a register.
;The Number is assumed to be positive, ie. Unsigned
;This procedure is the same as in Lab7.
;Entry: esi = address to string which prompts for input.
;Exit: eax = Result of the calculated number.
mov edx, esi ; Prompt user for xinput
call writestring
mov edi,0 ; initialize edi to 0
xLoop:
mov ecx, edi ; move edi into ecx
mov eax,10 ; move 10 to eax
imul edi ; multiply x by eax
mov edi, eax ; move eax to x
call readchar ; read and echo input
call WriteChar
cmp al, 0dh ; If al contains enter key, exit loop, else continue.
je outOfLoop
sub al,30h ; convert to interger
movzx ebx, al ; move from al to ebx
add edi, ebx ; add ebx to edi
jmp xLoop
outOfLoop: ;Where user goes when they hit enter to exit loop
mov eax,ecx
ret
getinput endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CalculateW proc
;Calculates a value based on X and Y inputs
;INPUT: X and Y . Y was pushed first
;OUTPUT: eax contains result.
;THIS VERSION USES LOCAL VARIABLES ALLOCATED ON STACK
;local variables are loc1,loc2,loc3,and sum
;All the local variables are 4 bytes (DWORD) and are
;explicitly allocated on the stack and accessed from the stack.
push ebp ; save ebp
mov ebp, esp
sub esp,16 ; Allocate stack space
;do loc 1
mov eax, 160 ; set eax to 160
imul DWORD PTR [ebp+12] ; multiply y by eax
mov ebx,eax ; Move eax to ebx to save y * 160 ----- EBX is Intermediary
mov eax, 2 ; now set eax to 2
imul DWORD PTR [ebp+8] ; multiply x times eax
add eax, ebx ; eax = Y * 160 + X * 2 ---------------ebx is now free
mov DWORD PTR [ebp-4], eax ; move eax to ebx which is our loc1.
;do loc2
mov eax, 950 ; Set eax to 950
mov edi, 90 ; since we're just using registers, and x is already done A = edi = 90
imul edi ; multiply a by eax
mov DWORD PTR [ebp-8], eax ; copy eax to edi which is our loc2.
;do loc3
mov ebx, DWORD PTR [ebp-4] ; Put loc 1 into a register so I can do math.
mov edi, DWORD PTR [ebp-8] ; Put loc 2 into a register so I can do math
sub edi,ebx ; Subtract loc1 from loc2.
mov DWORD PTR [ebp-12],edi ; move loc2-loc1 to loc3.
;do y
mov DWORD PTR [ebp+12],3000 ; set y to 3000
sub DWORD PTR [ebp+12],1 ;subtract 1 from y
;do sum
mov eax, DWORD PTR [ebp-12] ; move loc3 into eax
cdq
mov edi,16 ; move 16 into edi
idiv edi
mov [ebp-16],eax ; move loc3/16 somewhere so we don't lose it.
mov eax, DWORD PTR [ebp+12]
cdq
mov edi,4
idiv edi
add DWORD PTR [ebp-16],eax ; sum= loc3/16 + y/4
mov eax, DWORD PTR [ebp+12]
cdq
mov edi,200
idiv edi
add DWORD PTR [ebp-16],eax ; sum= loc3/16 + y/4 + y/200.
mov eax, DWORD PTR [ebp+12] ;put y into register
add DWORD PTR [ebp-16],eax ; sum= loc3/16 + y/4 + y/200 +y.
mov eax,DWORD PTR [ebp-16]
cdq
mov edi,3907
idiv edi ; divide by 3907 per professor's office hour feedback
add edx,3 ; Add 3 to modulus.
mov eax,edx ; move the modulus from to eax.
mov esp,ebp
pop ebp
ret
calculateW endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
outW proc
;This procedure outputs MULTIPLE DECIMAL DIGITS on the screen.
;The algorithm is based on repeated division of quotient by 10
;REMAINDERs are kept on the Stack and retrived in the reverse order.
; The number to be printed can be positive or negative.
;This procedure must print "-" sign if the number is negative.
;INPUT parameter:W=number to be printed in binary. Caller Pushed W on Stack before this procedure is called.
;OUTPUT parameter: None
COMMENT &
ALGORITHM FOR CHECKING IF NUMBER IS NEGATIVE AND CONVERTING AND PRINTING NEGATIVE SIGN AS NEEDED.
1. Get parameter (W=number) to be printed from the stack
2. Check if number is negative or positive
3. If it is positive Go to Step 8 to ConvertToDec and Print
4. If not, it is negative. Convert to positive (Use NEG instruction)before converting to decimal
5. save it temporarily
6. Display Negative Sign
7. get Number back into eax. It will be the dividend in the division below
8. Convert to Decimal. This step is exactly the same as the code you used in Lab 7
&
push ebp
mov ebp,esp
; Figure out if number is positive or negative
mov eax, DWORD PTR [ebp+8] ; Get W result value
cmp eax,0 ; Check if number is negative or positive
jge ConvertToDec ; If number is positive, convert to decimal else...
neg eax ; If number is negative, convert it to positive.
mov ebx,eax ; Temporarily save the number.
mov al, "-" ; Put negative sign in al register for printing.
call WriteChar ; Print negative sign.
mov eax,ebx ; Put number back into eax.
mov ecx,0 ;set ecx counter to 0
ConvertToDec:
mov edi, 10
cdq
idiv edi ; divide eax / edi
add edx,30h ; convert to ascii by adding 30h.
push edx
add ecx, 1
cmp eax,0
jne ConvertToDec
printingLoop: ; LOOP TO POP STACK TO EAX ONE BY ONE
pop eax
call WriteChar ; print eax.
loop printingLoop
call CrLf ; add an extra line to make it pretty.
mov esp,ebp
pop ebp
ret
outW endp
;;;;;;;;;;;;;;;;;;;;;;;;
end main```
Upvotes: 1
Views: 265
Reputation: 4163
You are using uninitialized ecx
register in outW
before incrementing it in a loop. The bug surface itself only in case the value of W
is positive.
See the following code:
mov eax, DWORD PTR [ebp+8] ; Get W result value
cmp eax,0 ; Check if number is negative or positive
jge ConvertToDec ; If number is positive, convert to decimal else... (1)
neg eax ; If number is negative, convert it to positive.
mov ebx,eax ; Temporarily save the number.
mov al, "-" ; Put negative sign in al register for printing.
call WriteChar ; Print negative sign.
mov eax,ebx ; Put number back into eax.
mov ecx,0 ;set ecx counter to 0 (2)
ConvertToDec:
You have an initialization of the counter (2), but notice it will only be execute if the jump in line (1) is not taken. If the value is positive the initialization is skipped.
To fix, your jump in (1) has to execute that line with mov ecx,0
too.
So the fix could be like this:
mov eax, DWORD PTR [ebp+8] ; Get W result value
cmp eax,0 ; Check if number is negative or positive
jge go ; If number is positive, convert to decimal else... (1)
neg eax ; If number is negative, convert it to positive.
mov ebx,eax ; Temporarily save the number.
mov al, "-" ; Put negative sign in al register for printing.
call WriteChar ; Print negative sign.
mov eax,ebx ; Put number back into eax.
go:
mov ecx,0 ;set ecx counter to 0 (2)
ConvertToDec:
Or zeroing of ecx
cold be moved to a common code before the jump if it's not destroyed by WriteChar
(didn't check that).
Upvotes: 2