Sorry for the newbie question......

What exactly happens when we say
ret

in our progs? Does it modify the esp? If so, how so? How does it know how much to inc/dec by? As an added question, if I put 4 bytes on the stack and want to bring the stack pointer back would I need to add or sub 4 to get it back? Thanks for taking the time to explain this.
Posted on 2001-11-14 14:55:21 by lackluster
when a Call is processed, EIP+lenght of Call instruction is placed on stack (dword ptr ESP)...
when RET is processed, dword ptr is read and the flow of the code continues there.
Posted on 2001-11-14 16:33:04 by DZA
lackluster,

There are two instructions that work as a pair in x86 hardware, CALL pushes the return address onto the stack and then jumps to the address, RET returns the EIP (instruction pointer) back to the next instruction AFTER the original CALL instruction using the address pushed onto the stack by the CALL instruction.



call label
next instruction

; further down the code

label:
; assembler instructions
ret ; return to next instruction after the call


Regards,

hutch@movsd.com
Posted on 2001-11-14 17:32:06 by hutch--
With MASM (and TASM), it depends on whether RET is within a PROC or not.

Outside of PROCs, RET (with no argument) pops exactly one DWORD in 32-bit mode. That popped value is stored in EIP, effectively causing a jump. This undoes a CALL instruction (this is its intended usage.)

When RET appears within a PROC-ENDPROC block of code, it's treated as a macro. What it pops depends on the calling convention selected, the number of arguments declared, and the amount of local stack space created.
Posted on 2001-11-14 18:28:59 by tank
Just adding to Tank's post...
Usually, or at least under the circumstances I've checked, the macros work thru the frame pointer ebp. & stack locals use it as a reference.
Posted on 2001-11-14 18:33:19 by rafe

When RET appears within a PROC-ENDPROC block of code, it's treated as a macro. What it pops depends on the calling convention selected, the number of arguments declared, and the amount of local stack space created.


Could this be why my progs shimmy-sham around with my local vars? It seems they're no good the second time around. I'm thinking perhaps the ret removes these vars leaving me with the address that is to be returned to eip.
Posted on 2001-11-14 18:57:32 by lackluster
PROC allocates LOCALs on the stack by changing ESP. The RET macro will undo this by changing ESP. PROC sets the EBP register to point to the subroutine's LOCALs. The RET macro restores EBP to its old value. (TASM has a NOLANGUAGE keyword that suppresses all this "stack frame" code.) All direct accesses to LOCALs are via EBP.

When you return to the point after INVOKE or CALL, the ESP is set to a value that allows overwriting of the LOCALs created in the subroutine. All you need to do is call another subroutine that allocates LOCALs -- the new LOCALs can overwrite the previous LOCALs.

I don't know if interrupts in Windows uses the current thread stack. If so, this would be another possible way to alter deallocated LOCAL vars.
Posted on 2001-11-14 20:15:10 by tank
Local varible exist on the stack only during the duration of the PROC! They do not occupy global space. Here is an example:
MyProc PROC A1:DWORD

LOCAL B2:DWORD,C3:DWORD

mov edx,C3
mov eax,B2 ; you can't predict this value here!
mov C3,112358
push A1
pop B2
ret
MyProc ENDP

; you can never know what will be in eax, edx in the following...
invoke MyProc 10
invoke MyProc 12
invoke MyProc 14
Look at the code in a debugger, or produce a listing of the assembly: /Fllist.txt -- and you'll see the code produced by the HLL stuff in MASM.
Posted on 2001-11-14 21:47:35 by bitRAKE