I found this thread which says it can't be done:
http://www.asmcommunity.net/board/index.php?topic=6356&highlight=local

Perhaps it is "should not be done". If so why?


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

_TEXT SEGMENT
FramelessProc PROC PUBLIC parm1:PTR DWORD,parm2:PTR DWORD
local foo:dword
local bar:dword
align 4
mov eax,[foo]
mov [bar],edi

ret 8
FramelessProc endp
_TEXT ENDS

OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF

This works:


mov eax,[foo]
0040100B 8B 45 90 mov eax,dword ptr [foo]
mov [bar],edi
0040100E 89 7D 8C mov dword ptr [bar],edi

The address of both foo and bar are in stack space. I also check against proc with stack frames and the code looks the same.

So whats the deal?

Thanks.
Posted on 2003-03-10 21:43:05 by ThoughtCriminal
iirc LOCALs are addressed as negative offsets from ebp, which after a stack frame entry has been set up for you like so:

[size=12]  push ebp

mov ebp, esp
sub esp, 8[/size]


bar and foo are and but without a stack frame ebp could be anything.
Posted on 2003-03-10 22:44:27 by iblis
i think i understand good this, but if the vars.. local and the other are not (maybe not) have a good direction or address from ebp, how you can deal with a local var??, you say manually, but how??, is more fast or what against ebp-4 .. etc with the respective stack frame??

and what is more fast:
enter o,o i think this is only one opcode

or

push ebp
mov ebp, esp ;two opcodes and some thiks. of micro?? or what



manually i think with normal pushes and pops?? or substracting manually to the esp???? and then you call like ebp-some ??

sorry, but i need know :)
Posted on 2003-03-10 23:59:49 by rea
hgb, on new processors it is faster to adjust the stack and then use MOV instruction:

sub esp, 16
nop
mov , eax
mov , ebx
mov , ecx
mov , edx
Posted on 2003-03-11 00:07:28 by bitRAKE
then i need to work carefully by this way, if i add a push for example after i setup "the locals vars", then this push is gonna make me refer uncorrectly to the locals if i try refer to they..

i supose like this

mov , eax
mov , ebx
mov , ecx
mov , edx
push esi
;some operations, but add 4 more to the others varsnow the bar need be esp+4.. etc
pop esi


and now a new questions, then is a good exchange "kill" the use of push?? and pop?? instead use mov (if you know how to add and how many to substract to the stack??

if is yes, in what caes is best push pop against mov.. also, i have another thing, i know for load the efective addres of for example a variable in ebp-4 also i use (this is with a stack frame):

lea eax,

but if i know the size i can code to (to avoid the use of lea)

mov eax, ebp
sub eax, some ;in this case some is 4
what is more fast the lea, or the mov eax, ebp and th sub??

and "translated to without stack frame" i think is some near equal instead lea:

mov eax, esp
add esp, some ;4 or other

*added :D

only a thing, some or the variable i refer like some is definied by a macro, then is a direct number i know, no is a var in data or some, then
add eax, some is translated to add eax, 4 (in this case) and equal for sub eax, some


in advance thanks

have a nice day.
Posted on 2003-03-11 00:32:53 by rea
It can work with ebp, but you have to be careful.



WinMainCRTStartup label dword
align 4
COLOR=red]esp = 12FFC4[/COLOR]

invoke GetModuleHandle, NULL [004011C2 6A 00 push 0
004011C4 FF 15 18 30 40 00 call dword ptr [__imp__GetModuleHandleA@4 (403018h)]
mov hInstance,eax
004011CA A3 19 60 40 00 mov dword ptr [hInstance (406019h)],eax
invoke main,eax,NULL,SW_SHOWDEFAULT [COLOR=red]call our main[/COLOR]
004011CF 6A 0A push 0Ah
004011D1 6A 00 push 0
004011D3 50 push eax
004011D4 E8 07 00 00 00 call main (4011E0h)
invoke ExitProcess,eax
004011D9 50 push eax
004011DA FF 15 1C 30 40 00 call dword ptr [__imp__ExitProcess@4 (40301Ch)]

main proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdShow:DWORD
004011E0 55 push ebp [COLOR=red]esp = 12FFB4[/COLOR]
004011E1 8B EC mov ebp,esp [COLOR=red]esp = 12FFB0[/COLOR]
004011E3 83 C4 A0 add esp,0FFFFFFA0h [COLOR=blue]get locals from value of ebp[/COLOR]
LOCAL msg:MSG
LOCAL rect:RECT
LOCAL hwnd:HWND
LOCAL wc:WNDCLASSEX

mov wc.cbSize,SIZEOF WNDCLASSEX

ebp need ot be preseverd and the stack needs to be balanced.

Now in our frameless proc:


invoke FramelessProc, parm1,parm2 [COLOR=red]esp = 12FF50,ebp = 12FFB0[/COLOR]
[COLOR=red]esp != 12FFC4 because this was called from the main proc, so the local defined in main still exist on the stack[/COLOR]

FramelessProc PROC PUBLIC parm1:PTR DWORD,parm2:PTR DWORD
local dummy[27]:dword[COLOR=red] adjust ebp local offset to esp-4[/COLOR]
local foo:DWORD[COLOR=red] allocare a dword on the stack[/COLOR]
local bar:CHR[COLOR=red] allocate a structure on the stack[/COLOR]
align 4

mov eax,[foo][COLOR=red] DWORDs always use mov, even with a stack frame[/COLOR]
0040100B 8B 45 90 mov eax,dword ptr [foo]
mov dword ptr[bar.Char],edi[COLOR=red] but STRUCTs always use an offset from ebp[/COLOR]
0040100E 89 7D 84 mov dword ptr [ebp-7Ch],edi [COLOR=red]ebp = 12FFB0[/COLOR]

ret 8
FramelessProc endp

This is a little more complicated than if my main was also frameless.
ebp should be preserved.
No code is genertated, unlike with a stack frame. The fixups are all done at assemble or link time.
If you want DWORD local to work off of ebp, make a dword STRUCT.
local dummy[-1] will work. The local macro only seems to set up offsets from ebp.
I'm not really sure why you would want to do this when work fine.

Thanks.
Posted on 2003-03-11 02:00:27 by ThoughtCriminal
sub esp, 16
nop
mov , eax
mov , ebx
mov , ecx
mov , edx


bitRAKE - that 'nop' has been bothering me since I saw it hours ago

I've read enough of your posts to doubt that you put it there for fun:)

I'm pretty sure I've run similar code without the 'nop' on P2 & P3 without problems but I'd appreciate clarification

Regards
eGo
Posted on 2003-03-11 13:22:39 by eGo
eGo, I only mean that another instruction should be placed where the NOP is to remove forward dependancies. It is only a NOP in so far as it does not use ESP.
Posted on 2003-03-11 13:48:43 by bitRAKE
MASM can't automatically use esp for locals as esp can change throughout the routine, while ebp will stay the same.
It's possible to automate some things with macros but there are some things you need to watch out for, not everything can be automated..

Thomas

Posted on 2003-03-11 13:48:48 by Thomas
One way to not use EBP is to have a global variable for each PROC that defines the stack depth within the PROC:
	OPTION PROLOGUE:NONE

OPTION EPILOGUE:NONE


_push MACRO var:REQ, nam:=<>
push var

Test123_DEPTH = Test123_DEPTH + 4

IFNB <nam>
&nam CATSTR <[esp][Test123_DEPTH][>, %(-Test123_DEPTH), <]>
ENDIF
ENDM

Test123_DEPTH = 0

Test123 PROC A_:DWORD, B_:DWORD, C_:DWORD
_A EQU <[esp + 4*1 + Test123_DEPTH]>
_B EQU <[esp + 4*2 + Test123_DEPTH]>
_C EQU <[esp + 4*3 + Test123_DEPTH]>


mov eax, _A
_push eax, _D ; give it a name, too :)
_push eax, _E
_push eax, _F
_push eax, _G
_push eax, _H

mov eax, _A

mov ecx, _D
mov ecx, _E
mov ecx, _F
mov ecx, _G
mov ecx, _H

add esp, Test123_DEPTH
ret 12
Test123 ENDP
If you create a custom EPILOGUE/PROLOUE then the _push/_pop/etc... macros can be adjusted automatically and the %PROC%_DEPTH variable can be created automatically. Look at this in a debugger and you'll see that the expected code is generated!
Posted on 2003-03-11 14:26:32 by bitRAKE
bitRAKE:
These are the kind of macros I'm working on. I've looked into custom pro/epilogue macros but I don't think they are very useful for esp-based frames since you still can't use locals or parameters declared in masm directly, so you end up doing everything twice, once for masm (which feeds the right parameters to the pro/epilogue macros so you can calculate the Test123_DEPTH) and again to automatically declare constants like you did manually (_A, _B, _C etc.). You can't deduce _A, _B etc. from the parameter names since they are not passed to the macros.
So my macros will not use an pro/epilogue macro (just 'none' like you used), I'm thinking about a wrapper around the proc statement so you won't have to declare the parameters twice (once for masm and once for the macros).

Besides, there's more to it than replacing push and pop with the right macros, although it depends on the complexity of the function. For example, conditional pushes will be counted wrong, since the assembler always evaluates the macro statements, but at execution time, the push might not execute. It also assumes the flow of execution is the same as the flow of the source code (top to bottom). You can't use invoke either since every parameter push modifies the stack. But a _push macro is always handy, just use it with care.

Esp-stack frames aren't hard but you have to know what you're doing, I will explain this all in my article.

Thomas
Posted on 2003-03-11 15:04:04 by Thomas
The parameters can be passed to the PROLOGUE macro, but like you said, must do everything twice:


Test123 PROC <_A, _B, _C>, A_:DWORD, B_:DWORD, C_:DWORD
Test123 ENDP
Posted on 2003-03-11 15:11:18 by bitRAKE
That doesn't look very pretty :) But a wrapper is easily made. I also find out MASM aligns locals to its own size (up to dwords of course since quadword alignment of the stack is not guaranteed). The macros I'm creating should be able to do this too, maybe even take custom alignment values, sometimes alignment of quadwords or data on cache lines can be useful. Of course for alignment > 4 bytes a dynamic adjustment is needed, depending on the value of esp on function entry.

Thomas
Posted on 2003-03-11 15:23:11 by Thomas

That doesn't look very pretty
True, but it reduces the above code to:
Test123 PROC <_A, _B, _C>, A_:DWORD, B_:DWORD, C_:DWORD


mov eax, _A
_push eax, _D ; give it a name, too
_push eax, _E
_push eax, _F
_push eax, _G
_push eax, _H

mov eax, _A

mov ecx, _D
mov ecx, _E
mov ecx, _F
mov ecx, _G
mov ecx, _H

ret
Test123 ENDP
Posted on 2003-03-11 15:53:25 by bitRAKE

MASM can't automatically use esp for locals as esp can change throughout the routine, while ebp will stay the same.
It's possible to automate some things with macros but there are some things you need to watch out for, not everything can be automated..

Thomas


I agree totally with what you said.

If you want to use LOCAL with frameless proc, it would be best if ALL procs used were frameless. Then ebp should remian a constant. It is easier than doing the fixup (LOCAL dummy[27]), because a stack frame was used in another proc. Using LOCALS in a frameless proc can be done, but I regard it as a curiosity. Using esp is easier IMHO.


Posted on 2003-03-12 01:05:25 by ThoughtCriminal
Originally posted by ThoughtCriminal
If you want to use LOCAL with frameless proc, it would be best if ALL procs used were frameless. Then ebp should remian a constant. It is easier than doing the fixup (LOCAL dummy[27]), because a stack frame was used in another proc. Using LOCALS in a frameless proc can be done, but I regard it as a curiosity. Using esp is easier IMHO.

I don' t really get what your saying here.. Why should ebp remain constant? Locals are not a curiosity for me. For example, my PNGlib has one very big function to decode the image data. I used an esp-stack frame (with some fixup constants like bitRAKE used too) so I could use the ebp register (I was very short on registers) but I still needed quite some data for lookup tables and other values that were less often used, but required nonetheless. Those data were put in locals.

I'm interrested to see what you write. I use esp as a stack frame all the time. I'm curious why you would need a macro for it. I don't use macros at all. Here is how I do it:(Got this idea from looking at asm dumps from C++ code)


.686p
.model flat,stdcall
option casemap:none
option dotname

LclHeapAlloc proto :PTR DWORD,:PTR DWORD
fix$ = 8

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

;-------------------------------------------------------------------------------
;Allocates space on the heap
;-------------------------------------------------------------------------------

_heapstruc$ = 4 ;//Address of the heap description stucture
.HeapBase = 0
.HeapTop = 4
.HeapPtrPre = 8
.HeapPtrCur = 12
.HeapPtrNxt = 16

_allocsize$ = 8 ;//Size of allocation to make

_TEXT SEGMENT
LclHeapAlloc PROC PUBLIC heapstruc$:PTR DWORD,allocsize$:PTR DWORD
align 4
nop
mov eax,_heapstruc$[esp]
mov edx,[eax+.HeapPtrCur]
mov [eax+.HeapPtrPre],edx
mov edi,_allocsize$[esp]

lea edx,[edx+edi+4]
mov [eax+.HeapPtrCur],edx

ret fix$
LclHeapAlloc endp
_TEXT ENDS

OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF

end

I just use a bunch of numeric equates with $ at the end of a stack variable and . before a structure member.

Well for such a simple proc you don't need macros, but what happens if you push something onto the stack? You will need to adjust all following references to parameters by +4. If you don't use macros for this you'll have to do it manually, and each time you change the stack somewhere you need to adjust all the references after it again. This doesn't matter in a 10 line proc (although it easily causes errors) but it surely does in a 300 line one.

Thomas
Posted on 2003-03-12 01:40:09 by Thomas


I don' t really get what your saying here.. Why should ebp remain constant? Locals are not a curiosity for me. For example, my PNGlib has one very big function to decode the image data. I used an esp-stack frame (with some fixup constants like bitRAKE used too) so I could use the ebp register (I was very short on registers) but I still needed quite some data for lookup tables and other values that were less often used, but required nonetheless. Those data were put in locals.

Only if you want to use the LOCAL marco with a proc that have no stack frame. I had to use LOCAL dummy[27] to move the ebp offset to the right place on the stack, because I still had the locals from my main proc in scope( LOCAL wc:WNDCLASSEX...etc.). If you have stack a stack frame the code is generated to adjust ebp to the right place. It just a suggestion really, that if one wants to use LOCAL with no stack frame proc, it would be cleaner to use no procs with a stack frame. Then you dont have to do hacky stuff like LOCAL dummy[27] to adjust thing. It neat to know that this can be done, but I think I will stay with using .



Well for such a simple proc you don't need macros, but what happens if you push something onto the stack? You will need to adjust all following references to parameters by +4. If you don't use macros for this you'll have to do it manually, and each time you change the stack somewhere you need to adjust all the references after it again. This doesn't matter in a 10 line proc (although it easily causes errors) but it surely does in a 300 line one.

Thomas

Good point. I try to keep thing small and simple so that I dont have to push and pop in the middle of a proc to often. I'm not sure of any non-hacky way to do that just yet without macros. Looking forward to your article. I've stayed away from macros, but this does interest me.

Thanks.
Posted on 2003-03-12 02:47:44 by ThoughtCriminal

In the past there was some discussion about stacks and all here:
http://www.asmcommunity.net/board/index.php?topic=5214
Posted on 2003-03-12 04:03:27 by Maverick
in this moment i am reading the other post, but with the little idea that in the first day i get, in that day i modificate my macro (in nasm) and yea, it looks very similar to the macro that put privalov, also i only check if are in the context of the funct or not, if not, i dont need add deed in stack, also, with calls (that use push) i sub the total params to the variable, i dont wanna a mistake.. for the pop that dont are placed there, for example a call hola, uno, dos, tres, cuatro it will be 4 push and the variable tjhat old the deep will be added 4 more, but i in the macro of call i take the carefully to see that that the value of the "deep" variable dont get alterations
macro i coded

stdp = 0 ; stack depth variable

macro push arg
{ push arg
stdp = stdp+1 }

macro pop arg
{ pop arg
stdp = stdp-1 }


looks similar, but nowt are equals, the start idea is the same, also the macro that have nguga in his package is not the same i have in my own, later when i can code correcltiy (and test) done i will update for nguga ;)



also i think it can work best, i am adding some things, and yea it can be done automatically, also i need requestion, what is more fast refering to the lea.. and the stack

in nasm dont need the use of addr or offset for know dirs or easy directions, but also, i cant push a ebp-4 this is not a really efective address, if i know how many is the size, then what is more fast??


with stack frame

lea eax,

or

mov eax, ebp
sub eax, 8

using the esp

lea eax,

or

mov eax, esp
add eax, 8

at the end if you understand eax will have the same value with the lea and with the combination of the mov (betwen two registers) and a sub (to a register with a inmediate value)

also i think, the macro i code, now have more adventage, also i recoded the macro called CONST in the nagoa package, and i get 1 instructions less (one jump), but the size of the exe are nearly equals :D

also i need requestion, is right use less pops and pushes??, instead i will use mov???

for example, i can make a macro for calls that dont use push, also i know how i think :D and use only movs instead, this will be more fast???

call hola, uno, dos, tres, cautro

will be i think
mov dword, cuatro
mov dword, tres
mov dword, dos
mov dword, uno
mov dword, eip ;lol, you understand what i am saying :D (how is the best way for obtain the eip???
jmp hola ;call :D jua jua

and in the funct you can get for example
funct hola, uno, dos, tres, cautro ;start with esp+20
local some,4 ;a handle in ebp+24 and can use sizef :D
endfunct


also a end thing, the use of the stack frames is not only for locals, also ahve the adventaje for the trace of functions calls, with the use of esp i think you can't get the same use and lost this capacity..
Posted on 2003-03-12 07:20:51 by rea
hgb, the best way to get EIP is with CALL. LOL :)
Posted on 2003-03-12 07:34:02 by bitRAKE