News:

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

Local variables without a stack-frame

Started by Seb, April 02, 2007, 11:28:40 AM

Previous topic - Next topic

Seb

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

PBrennick

seb,
Just remember to balance the stack after you are done.

Paul
The GeneSys Project is available from:
The Repository or My crappy website

Tedd

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.
No snowflake in an avalanche feels responsible.

Ratch

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]

Seb

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

Ratch

seb,
     You are welcome.  Ask if you have any questions.  Ratch

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Ratch

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