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 (http://pastebin.com/xySCxxGM)
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 (http://www.ollydbg.de/version2.html) 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.
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
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 (http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm)).
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