Now i can done it so:
lea BX,$exit
mov CS:[BX+1],AX
$exit:
BYTE 0CAh ;opcode(retf)
WORD 0
but may be exist opcode(ret AX) like exist call AX
My target is the routine like printf which ax param is number of stack params.
Quote from: Rockphorr on December 27, 2010, 07:06:18 AM
Now i can done it so:
lea BX,$exit
mov CS:[BX+1],AX
$exit:
BYTE 0CAh ;opcode(retf)
WORD 0
Yes. But be aware that self-modifying code on recent cpus may slow down execution significantly!
Quote
but may be exist opcode(ret AX) like exist call AX
No. But you may "simulate" such an instruction if you've got a free register:
pop cx
add sp,ax
jmp cx
This sequence "destroys" the flags, though.
Quote from: japhethNo. But you may "simulate" such an instruction if you've got a free register:
pop cx
add sp,ax
jmp cx
But he uses a far return which complicates things a bit.
Quote from: japhethBut be aware that self-modifying code on recent cpus may slow down execution significantly!
Is that an issue with real mode code?
mov cs:[pcount],ax
...
db 0cah
pcount dw 0
This type of code will have problems in a "PROC USES EBX" situation though, since no "ret" appears.
if you want to preserve the flags, use LEA instead of ADD :U
also, to preserve CX contents as well...
pop [sp+ax+2] ;not sure this works - lol - i know it won't work on 8088
lea sp,[sp+ax]
ret
you may have to play with it a bit, but you get the idea
for a FAR PROC, you'll need 2 POP's
looks like a new toy for lingo - lol
OPTION PROLOGUE:None
OPTION EPILOGUE:None
SomeProc PROC Parm1:DWORD,Parm2:DWORD,Parm3:DWORD
mov ecx,[esp+12]
pop [esp+12]
pop eax
pop edx
;
;
;
;
;
ret
SomeProc ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
anyways - you could apply something similar in 16-bit code...
where you make the adjustment at the beginning of the routine instead of at the end
Quote from: dedndave on December 27, 2010, 12:20:45 PM
if you want to preserve the flags, use LEA instead of ADD :U
also, to preserve CX contents as well...
pop [sp+ax+2] ;not sure this works - lol - i know it won't work on 8088
lea sp,[sp+ax]
ret
This won't work, since neither SP nor AX are valid base- or index-registers.
And worse, you can't use the 32-bit counterparts either:
movzx esp,sp
movzx eax,ax
pop [esp+eax+2] ;not sure this works - lol - i know it won't work on 8088
lea esp,[esp+eax]
ret
because the highword of ESP is trashed "randomly" in 16-bit code under Windows.
thanks Andreas
certainly, he could do something similar to this
OPTION PROLOGUE:None
OPTION EPILOGUE:None
SomeProc PROC FAR Parm1:WORD,Parm2:WORD,Parm3:WORD
mov dx,[sp+6] ;get Parm2
mov cx,[sp+8] ;get Parm3
pop [sp+6] ;RET offset to Parm2
pop [sp+6] ;RET segment to Parm3
push cx ;maybe not needed - if you only need to grab Parm3 once
push dx ;maybe not needed - if you only need to grab Parm2 once
;
;
;
;
;
lea sp,[sp+6] ;discard 3 parms below RETF address
ret ;RETF
SomeProc ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
or this
OPTION PROLOGUE:None
OPTION EPILOGUE:None
SomeProc PROC FAR Parm1:WORD,Parm2:WORD,Parm3:WORD
mov dx,[sp+6] ;get Parm2
mov cx,[sp+8] ;get Parm3
pop [sp+6] ;RET offset to Parm2
pop [sp+6] ;RET segment to Parm3
pop ax
;
;AX = Parm1
;CX = Parm3
;DX = Parm2
;
;
;parms are already removed from stack
;
ret ;RETF
SomeProc ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
another approach, that might be a bit cleaner, is to use cdecl calling convention, making the caller responsible for stack clean-up :P