according to :
http://www.powerbasic.com/support/pb...t=35065&page=3

Code:
'Purpose:
'            Fast call to global subrotine (no stack frame overhead)
'Restriction:
'            All global procedures must be allocated in the body of PBMAIN after EXIT FUNCTION
'            Before using fast procedure, we need fill out Global variables which point
'            to start address of procedure in the begining of PBMAIN and don't change never that value.
'            (Or change it with purpose ;) if that procedure responsible for activation restricted shareware,
'             then you can switch execution to another fake prorotype of procedure)
'Features:
'            Since parameters of fast global procedure is global, it possible speed up
'            execution of procedure by assign values directly anywhere in the program,
'            then not needed to call macro GetParamProc01.
'            Then MACROs can be simplified to:
'             MACRO CALLproc01
'                ! mov ebx, pADDR01 ' pADDR01 initialized in PBMAIN as global dword
'                ! call ebx
'             END MACRO
'             MACRO GetParamProc01(param1proc01, param2proc01)
'             END MACRO
'             MACRO END_PROC01
'                ! ret
'             END MACRO
'
'            Example: param1proc01 = 123 : param2proc01=VARPTR(some UDT as proc01UDT)
'                     CALLproc01
'            In that case our procedure became GLOBAL GOSUB
'
'
#COMPILE EXE
#DIM ALL
'
'======================================macro4Proc01 =======================
MACRO CALLproc01(param1,param2)
   ! push param2
   ! push param1
   ! mov ebx, pADDR01 ' pADDR01 initialized in PBMAIN as global dword
   ! call ebx
END MACRO
'
MACRO GetParamProc01(param1proc01,param2proc01)
   ! mov ebx, dword ptr [esp+4]
   ! mov param1proc01, ebx ; extract first param
   ! mov ebx, dword ptr [esp+8]
   ! mov param2proc01, ebx ; extract second param
END MACRO
'
MACRO END_PROC01
   ! ret 8 ' two parameters, so we need to clear up stack [2 (param) * 4 (dword size) = 8]
END MACRO
'===============================================================
'
TYPE proc01UDT
  sz  AS ASCIIZ*128
  lng AS LONG
END TYPE
'
'-----------------------------------------
SUB CallProcedureFromSubrotine()
    LOCAL u1 AS proc01UDT
    LOCAL  dw2, lpU1 AS DWORD
    '
    'init params for passing to procedure
    dw2 = &haa55aa55aa???
    lpU1 = VARPTR(u1)
    u1.sz = "Receive call from subroutine, not PBMAIN"
    u1.lng = 567&
    '
    CALLproc01(dw2, lpU1)'Call fast global procedure
END SUB
'=============================================
FUNCTION PBMAIN () AS LONG
          '------------------------------------------------
          GLOBAL pADDR01 AS DWORD    ' do it once in pbmain
          pADDR01 = CODEPTR(proc01)  ' for each procedure
          '------------------------------------------------
          LOCAL u AS proc01UDT
          LOCAL  dw1, lpUDT AS DWORD
          '
          'init params for passing to procedure
          dw1 = &hf1f2f3f4???
          lpUDT = VARPTR(u)
          u.sz = "Receive call from PBMAIN, where procedure allocated"
          u.lng = 1234&
          '
          CALLproc01(dw1, lpUDT)       'Call fast global procedure
          CallProcedureFromSubrotine() 'Call fast global procedure from child subrotine
          '
          ? "done"
EXIT FUNCTION '=============================
'
proc01: 'CALLproc01(BYVAL param1proc01 as DWORD, BYCOPY param2proc01 as AS proc01UDT PTR)
      GLOBAL param1proc01,param2proc01 AS DWORD
      GLOBAL lpUDT_proc01 AS proc01UDT PTR
      '
      GetParamProc01(param1proc01,param2proc01)
      '
      lpUDT_proc01 = param2proc01
      '
      ? "Recevied param1 = 0x"+HEX$(param1proc01)+$CRLF+$CRLF+_
        "param2 as pointer to proc01UDT and return :"+$CRLF+_
        "UDT data: sz = "[email protected]_proc01.sz+$CRLF+_
        "UDT data: lng= "+STR$(@lpUDT_proc01.lng),,"Procedure01 respond:"
END_PROC01
END FUNCTION