📄 abs.asm
字号:
TITLE ABSOLUTE - helper for assembly routines
;***
; ABSOLUTE - Helper for calling BASIC interpreter assembly routines
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
; Just used to clear information from the stack to various registers and
; memory locations.
;
;******************************************************************************
INCLUDE switch.inc
INCLUDE rmacros.inc
useSeg _BSS
useSeg ER_TEXT
useSeg RT_TEXT
INCLUDE seg.inc
sBegin _BSS
externW b$seg ;def seg segment
sEnd _BSS
sBegin RT_TEXT
assumes CS,RT_TEXT
;***
; ABSOLUTE - Call absolute address
;
;Purpose:
; Routine which can be directly called from the basic level which
; in turn calls an absolute address.
;
; Under DOS, we push the address of the function on the stack
; and RET to it. This gives a protection violation under OS/2
; Protect mode, so we set up a variable to hold the address
; and do a JSR indirect to the address. On return, we have
; to release the Segment descriptor that we created.
;
;Entry:
; The actual number of parameters is variable, and depends on the
; routine that ABSOLUTE will in turn call. The LAST parameter pushed
; MUST be the DSoffset of an integer variable containing the offset
; of the routine to be called. The current DEF SEG is used as the
; segment for the call.
;Exit:
; IF OM_DOS3
; Whatever the called routine elects. We do NOT return to basic
; code from here.
; IF OM_DOS5
; Whatever the called routine elects. We do not save any of
; the registers around the call. After the call we trash AX,CX
; so we would need to modify this to make a Function ABSOLUTE.
;
;Uses:
; This routine follows convention, but does no saving or checking of
; the code actually called.
;
;Notes:
; The called routine receives control with all parameters passed to ABSOLUTE,
; except the offset integer, on the stack in Pascal convention. The return
; address present is back to the BASIC level code which CALLed ABSOLUTE.
;
; Stack on call to ABSOLUTE:
;
;
; \ Variable number of parameters \
; | to routine to be CALLed |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | Near pointer to I2 var containing |
; | the offset of the routine to CALL |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; |CS |
; + Far return address to caller of ABSOLUTE +
; [SP] -> |IP |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
;
; Stack on transfer to called routine:
;
; \ Variable number of parameters \
; | to routine to be CALLed |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; |CS |
; + Far return address to caller of ABSOLUTE +
; [SP] -> |IP |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
;
;
;
; Under OS/2 Protect mode things get complicated. We have to return to
; this routine in order to deallocate the Segment Descriptor that we
; have created. However, to insure that error handling works, we must
; have a BP Stack Frame on the stack for this procedure. In order to
; do this, we have to move all the parameters to the absolute function
; down three words on the stack so that we can stuff our CS:IP BP values.
;
; To get the size of the parameters, we assume that there has been nothing
; pushed on the stack since the last BASIC frame. We calculate the size
; of the basic frame, then move everything from that point to the end of
; the parameters down so that we can insert our stack frame.
;
;
;******************************************************************************
cProc ABSOLUTE,<FAR,PUBLIC>
cBegin
POP AX ;return offset
POP DX ;return segment
POP BX ;get pointer to routine address
PUSH DX ;restore return address
PUSH AX
PUSH [b$seg] ; stack DEF SEG segment
PUSH [BX] ; stack routine offset
cEnd
sEnd RT_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -