Hi Community,

This is a snippet for easy clearing local (stack) variables. It will work correctly if called from a subroutine with pushed registers: ebp,esi,edi and ebx
global ClearStack

ClearStack:

? ? mov eax,esp? ? ? ? ?; transfer esp to eax
? ? add eax,16? ? ? ? ? ; add 16, skips the pushed EIP, esi,edi,ebx
? ? xor edx,edx? ? ? ? ?; Sets edx to zero
.again:
? ? cmp eax,ebp? ? ? ? ?; if eax equals ebp - we're done
? ? je .fin
? ? mov dword ,edx ; clear 4 bytes
? ? add eax,4
? ? jmp .again
.fin:
? ? ret


so, instead
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
? ? LOCAL? wc:WNDCLASSEX
? ? LOCAL? msg:MSG

    push esi,edi,ebx
? ? mov? ? wc.cbClsExtra,NULL ; <- removed
? ? mov? ? wc.cbWndExtra,NULL ; <- removed
...

the code should looks like
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
? ? LOCAL? wc:WNDCLASSEX
? ? LOCAL? msg:MSG

    push esi,edi,ebx
? ? invoke ClearStack
...

Posted on 2005-07-07 12:48:49 by sapero
Mhm, did you actually test this? Your example won't work...

If you don't push ebx, esi and edi, (like in your example above), you should be substracting 4 from esp... you need to add one parameter to the ClearStack procedure then, to know how much to substract from esp.
Posted on 2005-07-07 19:12:35 by QvasiModo
pxor mm0,mm0
movq qword , mm0; to clear 2 dwords
or
pxor xmm0,xmm0
movdqu dqword,xmm0 ; to clear 4 dwords
Posted on 2005-07-07 22:51:09 by r22
Yes, it works, I always call this function from subroutines where are local structures for api functions
Added "push esi,edi,ebx" to examples (those registers are pushed automatically/always in my subs)
Also the stack frame must be present (enter x,y or push ebp...)

the complete example (nasm syntax) compile for console
%include "asm.inc"
extern ClearStack

main:
? ? call testme
? ? end

testme: ;--------------------
? ? enter 32,0
? ? push? ebx, edi, esi

? ? cdecl printf, strBefore ; print local string
? ? call? doPrint

? ? call? ClearStack? ? ? ? ; clear stack
? ? cdecl printf, strAfter? ; and print again
? ? call? doPrint

? ? cdecl printf, strq
? ? cdecl _getch? ? ? ; wait key
? ? pop? esi, edi, ebx
? ? leave
? ? ret


doPrint: ;--------------------
? ? lea? ?esi,
? ? mov? ?edi,32>>2
? .b
? ? cdecl printf, "0x%X, ", dword
? ? add? ?esi,4
? ? sub? ?edi,1
? ? jnz? .b
? ? ret

;--------------------

strBefore db "--- String before ClearStack()---",13,10,0
strAfter? db 8,8,32,13,10,"--- String after? ClearStack()---",13,10,0
strq? ? ? db 8,8,32,13,10,0

the cdecl macro works like invoke + add esp, <4*num.params>
Posted on 2005-07-08 04:26:31 by sapero
No it doesn't, you're not pushing the registers in the first example you posted. And in any case, I still think it's best to pass an argument (at least in a register) so you don't force users to preserve registers that maybe didn't wanted to preserve...
Posted on 2005-07-08 09:24:39 by QvasiModo
This is dumb. How often do you need to clear all the local variables? And you could just as well use this:
push DwordCount
pop ecx
clr:
push 0
loop clr

This is 7 bytes rather than the 8 bytes required (not counting push ebx, esi and edi) when using your function.
Posted on 2005-07-09 06:55:56 by Sephiroth3

This is 7 bytes rather than the 8 bytes required (not counting push ebx, esi and edi) when using your function.

But is it faaa-aaa-aaaast? ;-)
Posted on 2005-07-09 07:33:43 by f0dder
In the above example, I feel that invoking his ClearStack is not worth it at all. All you need to do is clear the data in 2 dword, and by calling ClearStack you end up clearing the data in all your local variables (which takes more time than 2 simple mov).

Also if the routine does not preserve ebx,edi,esi (as they might not use it), it ends up not clearing some of the local variable.

Just my 2 cents.
Posted on 2005-07-09 07:50:31 by roticv
I think it could be used in the few cases when you need to clear several kilobytes of data... maybe. :?
Posted on 2005-07-11 11:21:17 by QvasiModo
My stand on this issue is that if you want to clear a few kb, you would be using movq + mmx registers instead of the normal mov. It would be faster that way.  ;)
Posted on 2005-07-12 07:09:33 by roticv
I wrote a simple macro to clean local variables, can be used (almost) anywhere within a procedure.
	; this macro clear (zeros) all local variables
; !!! destroys edi
; argument is the number of "uses" to skip
ZeroLocals MACRO UsesNum
xor eax, eax
mov edi, esp
if UsesNum ne 0
add edi, UsesNum*4
endif
mov ecx, ebp
sub ecx, edi
shr ecx, 2
rep stosd
endm
Posted on 2005-07-12 13:33:20 by masquer