A near return pops one word into IP. A far return pops IP and then CS, undoing the two pushes of a far CALL. With an operand, RET n first pops the return address and then adds n to SP, throwing away n bytes of arguments the caller pushed before the CALL. n counts bytes, so two word arguments need RET 4. No flags change.
| Form | Encoding | Pops |
|---|---|---|
| RET (near) | C3h | IP |
| RET n (near) | C2h + 16-bit n | IP, then SP + n |
| RETF | CBh | IP, CS |
| RETF n | CAh + 16-bit n | IP, CS, then SP + n |
Inside a PROC, MASM turns RET into the near or far form to match the procedure's distance. RETN and RETF always mean what they say. The Pascal convention lets the callee remove its arguments with RET n:
MOV AX, 3PUSH AX ; one word argumentCALL TRIPLE1 ; returns AX = 9; RET 2 removed the argumentADD AL, "0" ; digit -> characterMOV DL, ALMOV AH, 02h ; DOS: print the character in DLINT 21hTRIPLE1 PROC NEARPUSH BPMOV BP, SPMOV AX, [BP+4] ; the argumentADD AX, AXADD AX, [BP+4] ; 3 times itPOP BPRET 2 ; pop IP, then SP + 2TRIPLE1 ENDP
RETF pops whatever is on the stack, which allows a trick: push CS yourself, then make a near CALL, and the stack holds the CS:IP pair a far return expects. Handy in a .COM program, which cannot link a far CALL to its own code:
PUSH CS ; a far return address by hand: CS first...CALL FARSUB1 ; ...then the near CALL pushes IPADD AL, "0" ; digit -> characterMOV DL, ALMOV AH, 02h ; DOS: print the character in DLINT 21hFARSUB1 PROC NEARMOV AL, 5RETF ; pops IP, then CSFARSUB1 ENDP
Pitfalls
If SP is not where it was at entry, RET pops a wrong address. A far return from a near call (or the reverse) unbalances the stack by one word. In 32-bit code on the 386 and later, returns pop 4-byte offsets.