News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Problem pushing parameters before calling a procedure

Started by FlyingDreadnaught, April 01, 2006, 03:35:23 AM

Previous topic - Next topic

FlyingDreadnaught

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

raymond

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
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

FlyingDreadnaught

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.

raymond

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
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Mark Jones

As Raymond says, try parsing the code with a debugger like OllyDbg. 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.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

FlyingDreadnaught

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.