An old post that was recently revived got me thinking...
http://www.asmcommunity.net/board/showthread.php?threadid=322

In this case, could we not handle the stack ourselves while retaining the ability to use invoke.

The code hutch posted was:


Test_If proc var:DWORD

.if var == 0
mov edx, 10
shr edx, 3
.elseif var == 1
mov edx, 20
shl edx, 2
.elseif var == 2
mov edx, 30
ror edx, 1
.endif

add edx, 100
shr edx, 3

mov eax, edx

ret

Test_If endp


But this means it messes around with the stack far too much for such a simple problem. "var" is only used the once in the equation (well several comparisions... but nothing else), so why not do the following:


Test_If proc
pop eax
.if eax == 0
mov edx, 10
shr edx, 3
.elseif eax == 1
mov edx, 20
shl edx, 2
.elseif eax == 2
mov edx, 30
ror edx, 1
.endif

add edx, 100
shr edx, 3

mov eax, edx

ret

Test_If endp


Then forge a PROTO for it so invoke will work as per normal....
But it doesn't work :(
Is there a way to get it to work?

Mirno
Posted on 2001-08-10 09:31:35 by Mirno
mirno, just move the stack variable into EAX instead of popping it
(which will give you EBP anyway). If you want to turn off the stack
frame setup, look in the masm32 reference... keywords will be
prologue and epilogue.

I guess you could also "just" set up a "blank label" (no proc), and
use the TYPE keyword...
Quoting X-Calibre (quoting comrade), INVOKE (TYPE MessageBox) PTR eax, NULL, ADDR text, ADDR caption, MB_OK

... that's for using invoke for messagebox, if you have the address
of messagebox in EAX. Of course you will have to set up a MessageBox
protoype, but that's no pain to do :).
Posted on 2001-08-10 10:20:27 by f0dder
The Prologue & Epilogue stuff got exactly what I needed thanks!

I ended up with these two macros


NO_PRO MACRO
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
ENDM

DEF_PRO MACRO
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
ENDM


They'll disable the standard prologue & epilogue, and re-enable them. So if you place them before the PROC statement, and after ENDP, you can't use the local variables but you can pop the args off the stack!

So in the example I gave at the top you get:


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
Test_If proc
1 58 pop eax
.if eax == 0
1 0B C0 * or eax, eax
1 75 0A * jne @C0001
1 BA 0000000A mov edx, 10
1 C1 EA 03 shr edx, 3
.elseif eax == 1
1 EB 1B * jmp @C0003
* @C0001:
1 83 F8 01 * cmp eax, 001h
1 75 0A * jne @C0004
1 BA 00000014 mov edx, 20
1 C1 E2 02 shl edx, 2
.elseif eax == 2
1 EB 0C * jmp @C0006
* @C0004:
1 83 F8 02 * cmp eax, 002h
1 75 07 * jne @C0007
1 BA 0000001E mov edx, 30
1 D1 CA ror edx, 1
.endif
* @C0007:
* @C0006:
* @C0003:

1 83 C2 64 add edx, 100
1 C1 EA 03 shr edx, 3

1 8B C2 mov eax, edx

2 C3 ret
Test_If endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef


(no "push ebp | mov ebp, esp", and no "leave" at the end).

Mirno

**** Oops :o you still need the epilogue.....
**** I haven't checked this properly, I'm at work
**** but I will tonight, and post the results on monday!
**** It seems to be OK with only PROLOGUE disabled.
Posted on 2001-08-10 11:01:29 by Mirno

So if you place them before the PROC statement, and after ENDP, you can't use the local variables but you can pop the args off the stack!


Which is why (in many cases) "just" moving the stack variable into
EAX will be a better approach than popping it off the stack :).
But ok, disabling pro/epilogue can be very useful at times.
Posted on 2001-08-10 11:08:23 by f0dder
Do you mean:

mov eax, (what ever the var would be)
invoke Test_If

Because that cannot be called from another language!
But other than that, it would be easer to make a "Test_If" macro yes!

It was really more of a learning/exploring exercise for me :)

Mirno
Posted on 2001-08-10 11:13:37 by Mirno
I mean.. inside the test_if function, your first instruction would be


mov eax, [var]


and then you'd have the same code as hutch's original post, except
you test EAX instead of
Posted on 2001-08-10 11:18:29 by f0dder
Mirno,

If you passing parameters only in registers,
then forget INVOKE and simply CALL your sub like this:



Mov eax,variable

CALL Test_If

jmp overTest_If

Test_If:

mov edx, 10
shr edx, 3
.elseif eax == 1
mov edx, 20
shl edx, 2
.elseif eax == 2
mov edx, 30
ror edx, 1
.endif

add edx, 100
shr edx, 3

mov eax, edx

retn ; MASM will generate C3h for RET and no Prolog and Epilog

overTest_If:



Hope I did understand the question.
Posted on 2001-08-11 04:40:17 by forge
You can just say
test_if proc FORCENOFRAME, Var

this will disable the stack frame. But still Var is not at it's at . Your code is actually popping the return address to eax!
Posted on 2001-08-11 07:34:05 by gfalen
Mirno,
gfalen is right about pop eax -
after call esp is always pointing to return address (addr of
the instruction next to call)
gfalen,
Long time ago I tried FORCENOFRAME option but
wasn't able to make it work right with proto and invoke,
so I just use OPTION PROLOG and OPTION EPILOG when
I need to create procs without frame but with possibility
to write proto with any number of parameters I need to
check with invoke. But, of course, I need manually apply
parameter to retrn to correct the stack.
And wasn't that smart as Mirno :)
I couldn't think of simple macro, I just wrote it manually :)

it looks like this (now with Mirno macros):


NO_PRO MACRO
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
ENDM

DEF_PRO MACRO
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
ENDM

SomeProc proto :DWORD
.code

....
invoke SomeProc,eax
....
NO_PRO
SomeProc proc Par1
mov ecx,Par1
ret 4
SomeProc endp
DEF_PRO

the all code of SomeProc will result just on 2 machine
instructions:

mov ecx,
ret 4

But I think you know all about this, I just don't get it how
to use FORCENOFRAME to achive the same effect.

The Svin.
Posted on 2001-08-13 01:27:59 by The Svin
Thanks for your input guys!

Over the weekend, I tested all my code (I've got a debugger at home :D ). I realised what was going on with the stack, I'd never thought of how call/ret worked until now!

I also benchmarked the code. It'll save 2-3 clocks. Not a lot really, but on such trivial cases it is actually a fair portion of the execution time!
Its also a hassle keeping a track of where on the stack things are...
I guess I'll stick with the standard Prologue & Epilogue unless I'm trying to strangle every last cycle out of a function!

Still it was a usefull learning experience.

Mirno
Posted on 2001-08-13 05:37:36 by Mirno