News:

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

PUSH/POP Style Parameters

Started by pmpnfrsh, February 06, 2005, 03:49:41 AM

Previous topic - Next topic

pmpnfrsh

Hey ppl

I am fairly new to MASM, and i am trying to re-write the "hello world" application using PUSH/POP parameters rather than invoke.

I started off with the WndProc function, rewriting:

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

as

WndProc proc

LOCAL hWnd:HWND
LOCAL uMsg:UINT
LOCAL wParam:WPARAM
LOCAL lParam:LPARAM

pop hWnd
pop uMsg
pop wParam
pop lParam
...


However with these new changes, CreateWindow fails. Can anyone tell me why this might be happening.

Thanks in Advance!

raymond

QuoteHowever with these new changes, CreateWindow fails.

Obviously.

Anyone who is starting with assembler should become immediately familiar with a good debugger. That will be your best friend for the remainder of your life.

If you run your program in a debugger, you would find that the first item you pop would be whatever would have been on the stack at the address which the assembler has reserved for your LOCAL variable lParam. The 2nd item you pop would be whatever would have been on the stack at the address which the assembler has reserved for your LOCAL variable wParam. etc...

All that may be garbage if you try and use that data to call other procedures.

By using a debugger, you will also learn what happens with the ESP/EBP registers when you enter a procedure producing a "stack frame".

You can always read about all those things, but seeing it happen will remain anchored in your mind much faster.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

pmpnfrsh

OK i checked it out using a debugger. It never actually got to the "pop" code. I think RegisterClassEx rejected lpfnWndProc, and that's why CreateWindow failed. mb iduno.


So i'm guessing because i defined WndProc without the parameters, they were not pushed onto the stack and/or RegisterClassEx rejected it.

What is the correct syntax?

"WndProc proc" is clearly wrong, and

"WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM" is using MASM's high-level macros i want to avoid

raymond

Quote"WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM" is using MASM's high-level macros i want to avoid

That is not a high-level macro. It's the standard way of setting up a procedure so you can have direct access to the required parameters passed on the stack. Those parameters are already in a reserved space of the stack. You can refer to those parameters in your source code with the variable names you defined with the procedure (but only within that procedure block).

If you need to pass them as parameters to other procedures, you simply push them as any other parameter.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

pmpnfrsh

Is it not true that, at the lowest level, the parameters are retrived from the stack using POP's?

Is there a way i perform these POP's myself, rather than allowing MASM to take care of it automatically?

donkey

Ofcourse the parameters are not only retrieved with POP. They can also be directly addressed using their relative offset from the current stack pointer or base pointer. For example if you know that a value is the second DWORD pushed onto the stack it would be counter productive to pop both just to look at it, you would use the value of ESP and add 4 to it,then look directly at that memory address. Popping it would require alot more time and is almost always suboptimal if not completely impractical and certainly not considerred "low level" in any sense.

The PROC parameters are actually replaced in the source with stack-relative offsets in the compiled code, you can ofcourse do this manually if you like but it can be tricky. I posted the way to calculate them on the old site. The only thing that is remotely considerred a macro about the PROC directive is that the RET opcode is a pseudo macro in that it will calculate the ammount of correction the stack needs in order to balance. You should also be aware that it is the caller that is putting the stack out of balance not the callee, so if you use C calling convention the RET is always RET 0.

http://www.old.masmforum.com/viewtopic.php?t=1641&start=16
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

pmpnfrsh

Ok i see what a mistake i have made...

The reason i ask is that my latest project involves directly editing the opcodes without help of a compiler. So this means i have no variables, and the start of a function is just an address.

There is just one thing i need to confirm on:

Quote from: donkey on February 06, 2005, 09:03:08 AM
RET opcode is a pseudo macro in that it will calculate the ammount of correction the stack needs in order to balance.
http://www.old.masmforum.com/viewtopic.php?t=1641&start=16

Say i push some parameters onto the stack, call a function, and inside that function access the parameters using EBP.

Is it true I do not need to pop the parameters off the stack, but rather the RET opcode will balance the stack out?
If so, all my problems are solved.
Cheers

Vortex

pmpnfrsh,

All those parameters are not local variables, what are trying to achieve?

donkey

QuoteIs it true I do not need to pop the parameters off the stack, but rather the RET opcode will balance the stack out?
Yes, you can specify the numberof bytes to remove from the stack as part of the RET opcode. You can also balance it by directly modifying ESP/EBP though that is extremely touchy as you must preserve the return address at the top of the stack then adjust the stack and restore the original return address. It is much easier and more optimal to just have RET do it for you. Note ofcourse that RET alone does not do this, you are required to encode the number of bytes you want it to pull off the stack for example RET 10h for the WndProc.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

nobby_trussin

Hi, i've been following this post and have a general question about how the windows API functions return and deal with the stack. As mentioned in previous messages, the ret instruction can be given a value for number of bytes to be popped off the stack and if you debug the windows API functions such as CreateFile () (in kernel32.dll) for example, the function returns with ret 1Ch thus restoring the stack.

my question is, why is this not always the case? for example if you call C functions in assembler such as printf(), you MUST restore the stack yourself after the function returns (printf () returns with a simple ret instruction).

Surely when the function is called, it pops the parameters off the stack to retrieve them in the first place.

Hope you can clear this one up for me :U

nobby_trussin

well, i bet you don't get this often -  i'm replying to my own message and answering my own question. apparently, it's because the windows api functions use the __stdcall calling convetion whereby the called function cleans the stack before it exits. This is opposed to the obsolete __pascal calling convention where the caller must clean the stack after the function exits. This would explain why the functions like printf() were leaving the stack cleaning to me.

Ahh, the penny drops :)

Ratch

#11
To all who give a damn,

The following link is a good example of a subroutine that accepts a variable number of parameters and returns with a clean stack.  When finished, the subroutine cleans up after itself, not the calling program.  Ratch


http://www.masmforum.com/simple/index.php?topic=170.30   See reply #44