The MASM Forum Archive 2004 to 2012

Miscellaneous Forums => 16 bit DOS Programming => Topic started by: Rockphorr on December 27, 2010, 07:06:18 AM

Title: make ret AX instruction
Post by: 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


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.
Title: Re: make ret AX instruction
Post by: japheth on December 27, 2010, 07:41:23 AM
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.
Title: Re: make ret AX instruction
Post by: sinsi on December 27, 2010, 08:24:23 AM
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.
Title: Re: make ret AX instruction
Post by: 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

you may have to play with it a bit, but you get the idea
for a FAR PROC, you'll need 2 POP's
Title: Re: make ret AX instruction
Post by: dedndave on December 27, 2010, 01:01:40 PM
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
Title: Re: make ret AX instruction
Post by: japheth on December 27, 2010, 08:42:02 PM
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.
Title: Re: make ret AX instruction
Post by: dedndave on December 27, 2010, 08:57:28 PM
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
Title: Re: make ret AX instruction
Post by: dedndave on December 27, 2010, 09:05:29 PM
another approach, that might be a bit cleaner, is to use cdecl calling convention, making the caller responsible for stack clean-up   :P