Hello, I'm having a slight problem and hoping for some help. I have coded a program to find the GCD of two integers using a procedure and the stack. It works fine, however I recently found out that if you push the variables onto the stack at the beginning of the program this in effect makes the parameters global variables. So, in effort to avoid global parameters, I am trying to push them before call. However, every approach that I have taken has led to my program crashing. I hope you guys can give me some advice.
Here is my code. Notice the ; lines of code. They are a few things that I have tried which have led to my program crashing.
.CODE ; start of main program code
FindGCD PROC NEAR32
; procedure FindGCD(m, n : integer) : integer
; parameters are passed in double words to the stack
push value1 ; store first variable
push value2 ; store second variable
push ebp
mov ebp, esp
haveGCDLoop: mov ecx,[ebp+4]
cmp ecx, 0 ; if n = 0
jne findGCDLoop
mov eax, [ebp+8]
jmp endIfFound
findGCDLOop: mov edx, 0 ; prep edx for division
mov eax, [ebp+8] ; prep eax for division
idiv DWORD PTR [ebp+4] ; m mod n
mov [ebp+8],ecx ; m = n
mov [ebp+4], edx ; Remainder := n
jmp haveGCDLoop
endIfFound: pop value1
pop value2
pop ebp
ret 8
FindGCD ENDP
_start:
output prompt1 ; prompt for first number
input string, 40 ; read ASCII characters
atod string ; convert from ASCII to doubleword
mov value1, eax
;push value1 ; store first variable
output prompt2 ; prompt for second number
input string, 40 ; read ASCII characters
atod string ; convert from ASCII to doubleword
mov value2, eax
;push value1
;push value2
call FindGCD
;pop value1
;pop value2
;add esp,8
haveGCD: dtoa GCDValue, eax
output label1
I will have to assume a few things since you did not post the entirety of your app.
If you did not have any special instruction for the assembler regarding the creation of a stack frame for procedures, the first instructions generated by the assembler are:
push ebp
mov ebp,esp
Then you pushed two variables followed by another
push ebp
mov ebp,esp
which you coded yourself.
Your stack now looks like the following:
ebp ;=esp after the assembler pushed the first ebp
value2
value1
ebp ;the old value of ebp when the stack frame was created
return address
Then, when you eventually reach your endIfFound label, you start popping:
value1 = ebp = esp after the assembler pushed the first ebp
value2 = value2
ebp = value1
Then ret 8 modifies esp such that the original ebp and return address values become useless as if you had popped them into some register.
Then, the assembler inserts the LEAVE code which pops the new stack top to ebp and then tries to return to the next value on the stack == CRASH.
Look at your generated code with a disassembler. If you are using MASM32 and its Qeditor, one of the available tools is for disassembling the EXE file having the same name as your source code.
Raymond
Awesome Raymond, thanks for the help. You actually gave me my answer with your first comment. I didn't realize that the assembler automatically does:
push ebp
mov epb, esp
So, before the highest value I had considered to go with ret was 8 (b/c of the two dwords) and possibly 12 (b/c of ebp), I had never considered going with 16.
So basically, all I had to was change:
ret 8
to
ret 16
Now it works fine, thanks a lot!
Edit--- Nevermind, I jumped ahead of myself. After I changed the ret, I tried pushing the variables before I called the procedure and it is still crashing the program. I tried this with and without popping the variables. Crash, crash, crash... everytime. The only time I can get the program to run correctly is when the variables are pushed at the beginning of the procedure. I just can't understand why.
As long as you understand how the stack functions, simply do the same thing as I did in my explanation with the content of the stack and you most probably will find out where and why the program crashes.
The other option is to trace your program with a debugger to see how the content of the stack is being handled. This a good way to learn.
Raymond
As Raymond says, try parsing the code with a debugger like OllyDbg (http://www.ollydbg.de/). You can use it to load the app, then press F8 repeatedly to step through the code. It will show you all the registers and stack contents and their changes for each instruction.
Yes, I had originally tried that. I use a debugger for every program that I get stuck on. The strange is when I change the code, it causes the program to crash before it does anything. I do the first step into on the debugger and that's where it crashes. So basically, if I change it to push before the call, the program crashes before it even asks you to input the numbers.