The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: Seb on April 02, 2007, 11:28:40 AM

Title: Local variables without a stack-frame
Post by: Seb on April 02, 2007, 11:28:40 AM
Hey there!

How are the local variables manipulated when values are being PUSH:ed/POP:ed in a stack-frameless procedure? I mean, as far as I know, local variables are being allocated like this...


sub esp, 2*4 ; 2 DWORDs
;add esp,-2*4


And then accessed like this...


mov eax, [esp] ; first DWORD
mov ecx, [esp-4] ; second DWORD


But what if I've reserved ESI/EDI and want to access those variables again, how/where do I access them? Something like this?


push esi
push edi

mov eax, [esp-8] ; first DWORD?
mov ecx, [esp-12] ; second DWORD?


Because the PUSH instruction decrement the ESP register, I thought it'd be something like that, but I could be terribly lost in the ocean, which's why I'm asking here.

Regards,
Seb
Title: Re: Local variables without a stack-frame
Post by: PBrennick on April 02, 2007, 01:17:35 PM
seb,
Just remember to balance the stack after you are done.

Paul
Title: Re: Local variables without a stack-frame
Post by: Tedd on April 02, 2007, 04:13:17 PM
You've got it right :wink
You just have to be careful to always keep track of the current level of the stack (and where your variables are in relation to that) and adjust accordingly - everytime you push, add 4 to the adjustment; and the take 4 back for a pop; make special note for function calls (stdcall removes the parameters for you, while c-call doesn't.)
This is exactly the reason a stack-frame is usually set up - ebp then always points directly at your variables and there's no adjustment to make.
Title: Re: Local variables without a stack-frame
Post by: Ratch on April 02, 2007, 04:53:48 PM
seb,


QuoteHow are the local variables manipulated when values are being PUSH:ed/POP:ed in a stack-frameless procedure?
     Your question parallels the argument hutch-- and I just finished.  http://www.masm32.com/board/index.php?topic=4650.0   As long as you asked, let me give you an example of how I routinely do it.  Notice the use of the STRUCT directive.  Ratch



[attachment deleted by admin]
Title: Re: Local variables without a stack-frame
Post by: Seb on April 02, 2007, 09:06:59 PM
Thanks very much for the answers, guys! :U

Ratch, I'll have a look at that thread and the file you attacked, thanks. :thumbu

Regards,
Seb
Title: Re: Local variables without a stack-frame
Post by: Ratch on April 02, 2007, 09:28:01 PM
seb,
     You are welcome.  Ask if you have any questions.  Ratch
Title: Re: Local variables without a stack-frame
Post by: hutch-- on April 02, 2007, 10:41:43 PM
Seb,

The trick is to know what is on the stack at the entry point of your procedure. If for example you pushed 3 DWORD sized args then called the address of your procedure you end up with a stack like this at your procedure entry point.

[esp]  The return address from the most recent CALL.
[esp+4]  The last argument pushed.
[esp+8]  The second argument pushed.
[esp+12]  The first argument pushed.


Now depending on the procedure is how much work you need to do. If it is a simple leaf procedure (one that does not call other procedures) you can simply write or use  local data to the address range below the current location of the stack pointer.


[esp-4]
[esp-8] etc ....


As Tedd has mentioned if you modify the stack with PUSHes you have to correct the ESP register address to reflect this and one of the simple ways in terms of notation is the add another number to the stack address that represents the argument you are referencing.

Arg one is normally [esp+4] but if you have pushed ESI and EDI for example it becomes [esp+12]. You can make this a bit easier to manage by writing the address as [esp+4+8] as the assembler does the displacement arithmetic of "4+8" at assembly time.

Locals become a lot more complex with nested procedure calls with things like recursive function calls and you must be able to correct the stack pointer so that the called procedure does not overwrite the stack local of the caller. In this context a normal stack frame is very reliable and can be nested up to the depth of the stack size of the application without any problems.

You can try your luck with Ratch's method if you can get enough of it to make sense and you can work out how to avoid the hopeless pedantics. The example he posted below is incomplete with missing macros and no description of the architecture but if you can get around these problems you may get something that works.
Title: Re: Local variables without a stack-frame
Post by: Ratch on April 03, 2007, 01:50:00 AM
seb,

quote by hutch--
QuoteYou can try your luck with Ratch's method if you can get enough of it to make sense and you can work out how to avoid the hopeless pedantics. The example he posted below is incomplete with missing macros and no description of the architecture

     The MACROs are easily supplied in the link below.  Hutch's description of how it works is basically correct.  The method should not be described as "without a stack frame", however.  It does use a stack frame, albeit dynamically with ESP instead of static with EBP.   I implement this method with a STRUCT for every subroutine that needs parameters or local storage.  This keeps everything in order and your sanity in check.  The big disadvantage with my method is that any reference to the stack has to be adjusted, as shown the the example I enclosed.  The benefits are that the EBP register is not used.  I can easily supply a example of a cascaded call, that is, a subroutine calls another subroutine and uses the parameters of the previous subroutine directly.  In the end, however, you are the one who has to decide whether a dynamic stack is for you or not.  Ratch



http://www.masm32.com/board/index.php?topic=99.0