News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

LOCAL variables and stack address problem

Started by MrOsamaful, March 03, 2016, 05:59:06 AM

Previous topic - Next topic

MrOsamaful

This is my 1st topic so I would like to say hello to everybody :)

I'm learning MASM programming by myself from a pretty popular book titled Assembly for x86 processors. I wanted to write simple console based program to practice my programming skills but I came across a problem that i can't solve.

I have a function that prints a single row of characters from multi dimensional array, it works good but after returning from the function, stack adresses seems to be messed up because program crashes. The PrintRow function takes one parameter which is Y coordinate in array. Am I using local variables wrong?

Array is 100 bytes long and is divided in 10 * 10 rows. ROW_SIZE const is equal to 10.
Function itself works good, prints single row as it is supposed to do.


PrintRow PROC
LOCAL dwY: DWORD, dwCounter: DWORD, dwPos: DWORD
    mov eax, [ebp + 8]
    mov dwY, eax
    xor eax, eax
    mov dwCounter, eax
    mov dwPos, eax
   L1:
    push dwY
    push dwCounter
    call MapXY
    mov dwPos, eax
    movzx ebx, map[eax]
    invoke crt_printf, offset printChar, ebx
    mov eax, dwCounter
    cmp eax, ROW_SIZE-1
    je L1_END
    inc dwCounter
    jmp L1
L1_END:
leave
ret
PrintRow ENDP


Here is C-equivalent code

void PrintRow(int y)
{
    int i = 0;
    for(i = 0; i < ROW_SIZE; i++)
    {
        int j = MapXY(i, y);
        printf("%1c", map[j]);
    }
}


And here is a link for full code: http://pastebin.com/xySCxxGM

jj2007

Hi & welcome to the forum :icon14:

Your code is far too complicated! Masm creates stack frames for you - no need for enter and leave. Here is one example:

InsertPlayer PROC plX, plY
; enter 0,0
    mov eax, plX ; [ebp + 12]
    mov ebx, plY ; [ebp + 8]
    mov PLAYER_X, ebx
    mov PLAYER_Y, eax
...
; leave
ret
InsertPlayer ENDP


You should install Olly and have a look what your code really does.

For now, try to correct your code: remove the enter and leave parts, add arguments to your procs, and then post the complete source here inside code tags.

MrOsamaful

Thank you jj2007. Removing leave instruction solved the problem. And thank you for showing how MASM handles arguments, I didn't know that  ;)

When I took a look in VS2015 dissambly it clearly shows that MASM added itself second leave instruction so this caused problem. Maybe next time I should use my brain and not rush to the forum  :icon_redface:

Anyway it is very interesting. MASM adds leave instruction by itself only when using it's local variable functionality.



je L1_END
inc dwCounter
jmp L1
L1_END:
leave
ret

This is how that part was translated by MASM.

00DA1198  je          L1+31h (0DA119Fh) 
00DA119A  inc         dword ptr [dwCounter] 
00DA119D  jmp         L1 (0DA116Eh) 
L1_END:
00DA119F  leave 
00DA11A0  leave
00DA11A1  ret 

jj2007

OK, since you are already looking at disassemblies, here a little test case showing essential features of MASM, like arguments and the "uses" way to preserve the non-volatile registers esi edi ebx (->more).

Note that MASM does quite a bit of checks for you. Instead of push push push call MyTest, you should use invoke MyTest, arg1, arg2, arg3. Masm will shout at you if you supply the wrong number of arguments. MyTest must be defined above the invoke, if not, use MyTest PROTO :DWORD, :DWORD, :DWORD to define it.

include \masm32\include\masm32rt.inc ; include the usually needed libraries

.data
HelloW$ db "Hello World", 0

.code
MyTest proc uses esi edi pText, pTitle, MB_X ; three DWORD arguments, esi and edi are preserved on the stack
LOCAL MyLocVar
LOCAL LocBuffer[260]:BYTE
  mov MyLocVar, eax
  ; mov MyLocVar, ax ; error A2022: instruction operands must be the same size
  lea esi, LocBuffer ; use esi as pointer to a local buffer
  invoke lstrcpy, esi, pTitle ; copy data to local buffer
  invoke MessageBox, 0, pText, esi, MB_X
  .if eax==IDYES
; do stuff
  .elseif eax==IDNO
; do stuff
  .endif
  ret
MyTest endp

; ###### the entry point is here, not above ######
start:
  invoke MyTest, chr$("This is the text"), offset HelloW$, MB_YESNOCANCEL
  exit

end start