News:

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

A LEAVE Generated Before RET

Started by msqweasm, May 30, 2011, 12:14:02 PM

Previous topic - Next topic

msqweasm

From the listing file, I found that my RET is turned into LEAVE + RET.   I suspected it was related to epilogue stuff since the RET had no operand, so I used RET 0.  But, it still gives me a LEAVE.  Why is it so?  How do I turn this off?  Isn't RET with an operand suppresses epilogue generation?

BTW, I am playing around with my exotic idea of fetching the EIP into EAX.  I can put the whole fetcheip stuff into a separate proc, but i just want to do it inside my current proc

mytest proc
call fetcheip
; now eax has the eip value
...
....

fetcheip: mov eax, [esp]
ret ;<---- get turned into LEAVE+RET and killed my idea
...
mytest endp

dedndave

that should not happen if you have no parameters on the PROC line

at any rate, for PROC's that do have parameters, you can turn it off with OPTION
doing so leaves the responsibility of addressing parms, pushing/popping registers, and setting the RET pop size to you

;******************************************************

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

ScnMetric PROC  dwFunction:DWORD,lpValue:DWORD

        INVOKE  GetSystemMetrics,[esp+4]  ;dwFunction
        mov     edx,[esp+8]               ;lpValue
        cmp     eax,[edx]
        jae     SMexit

        mov     [edx],eax

SMexit: ret     8

ScnMetric ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

;******************************************************


when you are done, return the PROLOGUE and EPILOGUE settings to their defaults   :P

drizz

If you want a nested function inside proc-endp use pseudo instruction "retn" as "ret" generates proc epilogue code.
You could also turn off prologue/epilogue as Dave wrote, but then you can't use some of the high level features.
The truth cannot be learned ... it can only be recognized.

hutch--

The technique that Dave has shown you is a procedure with no stack frame, without the stack frame you don't need the LEAVE or the alternative and you then have to add the argument byte count to RET to balance the stack on exit if you are using STDCALL.

With a normal procedure in MASM it generates a stack frame which must be balanced on exit, LEAVE is a short and efficient way to do this, it can also be done by restoring ESP from EBP but is slightly longer.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

msqweasm

From masm32\help\masm32.chm :

QuoteOPTION PROLOGUE


Syntax: OPTION PROLOGUE:macroname

OPTION EPILOGUE:macroname


Description

PROLOGUE registers <macroname> as the macro function to be called when a prologue needs to be generated. EPILOGUE registers <macroname> as the macro procedure to be called when a RET or IRET instruction is encountered.

You can revert to the default prologue or epilogue by specifying PrologueDef or EpilogueDef as <macroname>. EPILOGUE code is generated only if the RET or IRET instruction terminating the PROC block has no operand. The RETN, RETF, and IRETF instructions do not cause the assembler to generate epilogue code.

To suppress generation of the prologue or epilogue code, give NONE as the <macroname>.

The assembler expects a macro definition of this form:

macroname MACRO procname, flags, argbytes, localbytes, <reglist>, userparms:VARARG

So does it mean RET 0 should disable epilogue?  And apparently it doesn't :(


mytest proc .... ;may have parameters
   LOCAL ...; may have local vars....
..
call fetcheip
; now eax has the eip value
...
....
JMP continue

   fetcheip: mov eax, [esp]
   ret 0 ;<---- still get turned into LEAVE+RET

continue:
...
ret
mytest endp


My call is actually to some adhoc label inside my proc.  So would it because my RET 0  isn't the last instruction?

dedndave

#5
if you have any parameters on the PROC line, you will get the prologue and epilogue
that means, at minimum, the prologue will be...
        push    ebp
        mov     ebp,esp


and, everywhere you place a RET, it will generate an epilogue...
        leave
        ret     (immed)


if you want, you can force yor own return with
        pop     ebp
        retn    (immed)


the easy way to do what you want to do is to use OPTION to disable the prologue and epilogue

jj2007

Quote from: drizz on May 30, 2011, 12:37:26 PMIf you want a nested function inside proc-endp use pseudo instruction "retn" as "ret" generates proc epilogue code.

Instead of asking the same question again, why don' you just read the posts and test what drizz (correctly) writes...?

raymond

The simplest of ALL options is to move the called code which is not labeled as a proc (which used to be called a "sub-routine" in the old days) OUTSIDE of any proc. The LEAVE will never get generated in those circumstances.

If you don't need to pass parameters on the stack and don't need LOCAL variables, there's no need to declare such a "function" as a proc. This habit most probably comes from C where you call such code as Func(), need to write it as a proc (even if it's only a RET which I have seen :eek), and C then compiles it as a proc.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Synfire

I think probably the easiest way to achieve what your wanting is to just use a delta macro:

getEIP MACRO dst:REQ
   call $+5
   pop dst
ENDM

.....

getEIP eax
mov [context.eip], eax

....


Be forewarned though, if you start out using tricks like this, you'll end up making this difficult for yourself late on. A lot of anti-viruses wrongfully detect anything like this (or what you were doing) as malicious code because that's the most common place for it's use.

mineiro

Quote from: msqweasm on May 30, 2011, 12:14:02 PM
BTW, I am playing around with my exotic idea of fetching the EIP into EAX.  I can put the whole fetcheip stuff into a separate proc, but i just want to do it inside my current proc
Do some debug with these macros to see if can help you in your jorney.

getip macro
LOCAL arg1
push arg1
pop eax
arg1:
ENDM


getup macro dst:=<eax>
LOCAL arg1,arg2
arg2:
push arg1
pop dst
;insert some code here
; mov ecx,dword ptr [arg1]
sub dst,arg1-arg2
arg1:
endm


fetchip macro
call $+5
mov eax,[esp] ;4ever loop
jmp eax
endm


.code
   getip   ;eax = IP when this one return
   getup   ;eax = Ip of getup
   getup   ebx   ;ebx = IP of getup
fetchip   ;use only while debuggrin this, you get in a forever loop

jj2007

Another variant of getting the EIP...

include \masm32\include\masm32rt.inc

.data
AppName db "The EIP of start:", 0

.code
@@:
start: push @B
pop eax
MsgBox 0, hex$(eax), addr AppName, MB_OK
exit
end start

dedndave

#11
        call    @F
@@:     pop     eax

hutch--

Dave,

You will find that JJs version is a better design, it does not mess up the CALL / RET pairing.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

of course   :P

how 'bout this code, then...
        mov     eax,@F
@@:

or
        mov     eax,$

jj2007

Quote from: hutch-- on June 07, 2011, 07:42:15 AM
You will find that JJs version is a better design, it does not mess up the CALL / RET pairing.

Dave is more forward-looking, Hutch. His version produces 00401005, mine is stuck at 00401000...