📄 st.asm
字号:
XOR SI, SI ; the move always starts on a paragraph boundary
XOR DI, DI ; zero both SI and DI
REP MOVSB ; move DS:SI to ES:DI
; update counters and segments
SUB DX, BX ; BX contains paragraphs that were moved
MOV AX, ES
ADD AX, BX ; increment ES by the same amount
MOV ES, AX
MOV AX, DS
ADD AX, BX ; increment DS by the same amount
MOV DS, AX
JMP SHORT move_again
done_move:
ENDIF
; Zero BSS, STACK and FAR_BSS
MOV AX, SEG BEG_BSS
MOV ES, AX
MOV DX, SEG _HEAP
SUB DX, AX
zero_again:
CMP DX, 0 ; DX contains paragraphs to move...
JZ done_zero
CMP DX, 0F00H ; we can only zero 64K at a time
JA big_zero
MOV CX, DX
JMP SHORT small_zero
big_zero:
MOV CX, 0F00H ; F00H paragraphs = F000H bytes = 60K
small_zero:
MOV BX, CX ; save paragraphs in BX
SHL CX, 1 ; paragraphs * 16 = bytes
SHL CX, 1
SHL CX, 1
SHL CX, 1 ; zero CX bytes
XOR AX, AX
MOV DI, AX
REP STOSB
; update counters and segments
SUB DX, BX ; BX contains paragraphs that were moved
MOV AX, ES
ADD AX, BX ; increment ES by the same amount
MOV ES, AX
JMP SHORT zero_again
done_zero:
; Set up DGROUP (DS = SS = DGROUP)
PUSH SS
POP DS
; Record where the stack resides
; Microsoft C needs to know SP in 2 places
IF COMPILER LT TC2
MOV word ptr [_abrktb], SP
ENDIF
MOV [_atopsp], SP
; Initialize Floating Point Packages (if required)
IF FLOAT ; {
; Display to screen the intended FP package
IF COMPILER GE TC2
IF FLOAT EQ INLINE
out1 <* Floating Point (Inline -f87)>
ENDIF
IF FLOAT EQ EMULATED
out1 <* Floating Point (Emulator -f)>
ENDIF
ELSE
IF FLOAT EQ INLINE
out1 <* Floating Point (Inline /FPi87)>
ENDIF
IF FLOAT EQ EMULATED
out1 <* Floating Point (Emulator /FPi)>
ENDIF
IF FLOAT EQ ALTERNATE
out1 <* Floating Point (Alternate /FPa)>
ENDIF
ENDIF
; Set INT 21H vector to our pseudo-handler
XOR BX,BX
MOV ES,BX
MOV BX,21H * 4
CLI
MOV AX,WORD PTR ES:[BX] ; save the old INT 21H
MOV WORD PTR old21, AX ; for later restore
MOV AX,WORD PTR ES:[BX+2]
MOV WORD PTR old21+2,AX
MOV WORD PTR ES:[BX],OFFSET CS:__mini_21
MOV WORD PTR ES:[BX+2],CS
STI
; Point INT 11H to our handler (we can use INT 21H from above)
MOV AX,3511H ; get int11 interrupt vector
INT 21H
MOV WORD PTR old11,BX ; save the old INT 11H
MOV WORD PTR old11+2,ES ; for later restore
PUSH DS
MOV AX,2511H
MOV DX,OFFSET CS:__mini_11
PUSH CS
POP DS ; DS:DX points to INT 11H handler
INT 21H
POP DS
; set INT 07H to point to our special INT (for V25s and 188s)
IF CPUTYPE
PUSH DS
MOV AX,2507H
MOV DX,OFFSET CS:__mini_07
PUSH CS
POP DS ; DS:DX points to INT 11H handler
INT 21H
POP DS
ENDIF ; CPUTYPE
; set INT 19H to point to V25/V35 IBRK Interrupt handler
IF CPUTYPE EQ V25
MOV AX,2513H
MOV DX,OFFSET _DATA:V25_IO_Interrupt
INT 21H ; DS:DX points to V25_IO_Interrupt handler
ENDIF ; CPUTYPE
; Initialize Floating Point for Microsoft C 5.0, 5.1 and 6.0
IF COMPILER LT TC2
c_callm _cinit
push SS
pop DS
; Initialize Floating Point for Borland/Turbo C++
ELSE
; Borland Turbo C++ compilers only
IF COMPILER GE TCPP
public StartExit
mov si,offset DGROUP:InitStart ;si = start of table
mov di,offset DGROUP:InitEnd ;di = end of table
call StartExit
PUSH SS
POP DS
; Initialize Turbo C 2.0
ELSE
push cs
call ds:[__emu1st]
ENDIF
ENDIF
; We are done w/ INT 21H and INT 11H, reset vectors
PUSH DS
LDS DX, old11
MOV AX, 2511H
INT 21H
POP DS
PUSH DS
LDS DX, old21
MOV AX, 2521H
INT 21H
POP DS
ELSE
out1 <* No floating point>
; Initialize C++ for MSC 7.0
IF COMPILER EQ MSC7
c_callm _cinit
ENDIF
; Initialize constructors for Borland C++
IF COMPILER GE TCPP ; {
public StartExit
mov si,offset DGROUP:InitStart ;si = start of table
mov di,offset DGROUP:InitEnd ;di = end of table
call StartExit
PUSH SS
POP DS
ENDIF ; } // Borland C++ compilers
ENDIF ; } // FLOAT
; trap INT 21H to cause an exit() if INT 21H is called
IF INT_21_CHK ; {
out1 <* Trapping INT 21H>
XOR BX,BX
MOV ES,BX
MOV BX,21H * 4
MOV WORD PTR ES:[BX],OFFSET CS:_int_21_fail
MOV WORD PTR ES:[BX+2],CS
ENDIF ; } // INT_21_CHK
; Set up heap (for use by malloc)
MOV _heap_seg, SEG _HEAP ; after FAR_BSS
MOV _heap_eseg, HEAPEND ; HEAPEND defined in ST.INC
; Call main() -- the real user program
PUSH SS
POP ES
STI
c_callm main
; main() has returned, call exit()
MOV AX,ERR_MAINRET
PUSH AX
c_callm exit
; []---------------------------------------------[]
; | |
; | EXIT CODE |
; | |
; []---------------------------------------------[]
IFE USEREXIT
; exit has alternate labels
_abort:
__exit:
PUBLIC _abort, __exit
c_func exit
PUSH BP
MOV BP, SP
MOV AX, P[BP] ; error code
MOV exit_status,AX
exit1: STI
JMP exit1 ; infinite loop with interrupts enabled so
c_endp exit ; that RDEB can break out of it
ELSE
; exit has alternate labels
c_func exit
PUBLIC _abort, __exit
_abort:
__exit:
PUSH BP
MOV BP,SP
MOV AX,P[BP] ; error code
MOV exit_status,AX
exit1: STI
c_callm my_exit
c_endp exit ; that RDEB can break out of it
ENDIF
; []---------------------------------------------[]
; | |
; | STACK AND OVERFLOW CHECKING |
; | |
; []---------------------------------------------[]
;
; Borland Turbo C, C++ only
;
; TC checks the stack in each function with inline
; code. It calls this overflow if there is an overflow.
; Compare this with MSC where it calls a "check stack"
; routine from every function.
;
IF COMPILER GE TC2
PUBLIC OVERFLOW@, F_OVERFLOW@
OVERFLOW@ PROC FAR
F_OVERFLOW@:
MOV AX,ERR_OVERFLOW
PUSH AX
c_callm exit
OVERFLOW@ ENDP
;
; Microsoft C only
;
; This "check stack" routine makes sure we haven't
; overflowed and optionally checks for null ptr
; assignment.
;
ELSE
c_labelP _chkstk ; stack checking
c_labelP _aNchkstk ; another chkstk label for MSC 6.0
c_labelP _aFchkstk ; another chkstk label for MSC 6.0
IF NULL_PTR_CHK
out1 <* Null Ptr Chk>
XOR BX,BX ; checksum the copyright message
MOV CX,29H
MOV DL,0
chksum:
ADD DL,[BX]
INC BX
LOOP chksum
CMP DL,8BH ; value of all bytes added together
JZ _chkstk2
; someone has modified the data at DS:0
MOV AX,ERR_NULLPTR
PUSH AX
c_callm exit
_chkstk2:
ENDIF
; remove return address from stack
IF largeCODE
POP CX ; get return offset
POP DX ; get return segment
ELSE
POP CX ; get return offset
ENDIF
MOV BX,SP
SUB BX,AX ; new position (make room for locals)
CMP BX,[STKHQQ] ; SP - AX : STKHQQ (for heap/stack)
JB stk_ovfl ; Check for over flow
MOV SP,BX ; set new stack pointer
; go back into function which called us
IF largeCODE
chkproc PROC FAR
PUSH DX ; push segment
PUSH CX ; push offset
RET ; far return to dx:cx
chkproc ENDP
ELSE
JMP CX ; return to cx
ENDIF
stk_ovfl:
MOV AX,82H ; stack overflow error
PUSH AX
c_callm exit
ENDIF
;
; Microsoft C only
;
IF COMPILER LT TC2
c_label _cintDIV,NEAR
MOV AX,91H ; Divide by Zero
PUSH AX
CALL exit
c_label _amsg_exit,NEAR
MOV AX,92H ; amsg_exit
PUSH AX
CALL exit
ENDIF
; []----------------------------------------------[]
; | |
; | INTERRUPT TRAPPING |
; | |
; []----------------------------------------------[]
;
; we have gotten an unsupport DOS call, fail immediately
IF INT_21_CHK OR FLOAT
PUBLIC _int_21_fail
_int_21_fail:
STI ; re-enable interrupts
MOV BX,DGROUP
MOV DS,BX ; make sure we have a valid ds
MOV _exit_21func,AX ; save the function #
POP AX
MOV WORD PTR _exit_21addr,AX ; and CS:IP (address) of
POP AX
MOV WORD PTR _exit_21addr+2,AX ; the offending DOS call
MOV BX,ERR_NO21 ; exit status for unsupported DOS call
PUSH BX
c_callm exit
ENDIF
;
; Floating point initialization requires a miniature
; INT 21H handler. It supports 3 functions:
;
; 25H (set vector), 30H (get version), 35H (get vector).
;
IF FLOAT
public __mini_21
__mini_21 PROC FAR
; reenable interrupts
STI
; INT21H, function 30H - Get DOS Version
CMP AH,30H
JNZ m21_25
MOV AX, DOS_VERSION
IRET
; INT21H, function 25H - Get Interrupt Vector
m21_25: CMP AH,25H
JNZ m21_35
CMP AL,5H
JB m21_25i
PUSH ES
PUSH BX
; get pointer to vector
XOR BX,BX
MOV ES,BX
MOV BL,AL
SHL BX,1
SHL BX,1
; set the vector
CLI
MOV ES:[BX],DX
MOV ES:[BX+2],DS
STI
POP BX
POP ES
m21_25i:
IRET
; INT21H, function 35H - Set Interrupt Vector
m21_35: CMP AH,35H
JNZ m21_do_nothing
; get pointer to vector
XOR BX,BX
MOV ES,BX
MOV BL,AL
SHL BX,1
SHL BX,1
; set the vector
LES BX,dword ptr ES:[BX]
IRET
m21_do_nothing:
IRET
__mini_21 ENDP
ENDIF
; []----------------------------------------------[]
; | |
; | FLOATING POINT SUPPORT |
; | |
; []----------------------------------------------[]
IF FLOAT
; fake BIOS call to get equipment list
PUBLIC __mini_11
__mini_11 proc far
push BX
push BX
push BX
push DS
push BP
mov BP,SP
mov BX, SS:[BP+10] ; DS:BX = CS:IP at time of Interrupt
mov DS, SS:[BP+12]
sub bx, 2
cmp word ptr DS:[BX], 011CDH
jnz goto_next11 ; if did a "int 11H" to get here
pop BP
pop DS
pop BX
pop BX
pop BX
IF FLOAT EQ INLINE
MOV AX, 10b ; xxxx xx1x = 80x87 coprocessor present
ELSE
MOV AX, 0 ; xxxx xx0x = 80x87 coprocessor absent
ENDIF
iret
; This INT 11H was not software generated - do the
; hardware interrupt instead. This code only comes
; into play
goto_next11:
mov BX, DGROUP
mov DS, BX
mov BX, word ptr old11 ; Get old11 vector
mov [BP+8], BX ; Put old11 Vector on stack
mov BX, word ptr old11+2
mov [BP+10], BX
pop BP
pop DS
pop BX
retf ; Chain to old11 Vector
__mini_11 endp
; handle an INT 07H (generated by the 188 on an ESC instruction)
IF CPUTYPE
PUBLIC __mini_07
__mini_07 proc far
PUSH BX
PUSH BP
PUSH DS
MOV BP,SP
; get pointer to instruction
LDS BX,[BP+6]
CMP BYTE PTR DS:[BX],0DBH ; FINIT 2 byte instruction
JNZ fourbyte
MOV BX,2
JMP SHORT done07
fourbyte:
MOV BX,4 ; FSTCW 4 byte instruction
done07: ADD WORD PTR [BP+6], BX
; we're done - return out
POP DS
POP BP
POP BX
IRET
__mini_07 endp
ENDIF ; CPUTYPE
; user can (and should) supply the FP exception routines
IF USERMATHERR
IF largeCODE
extrn _matherr:far
ELSE
extrn _matherr:near
ENDIF
ELSE
c_func matherr
MOV AX,1
RET
c_endp matherr
ENDIF ; USERMATHERR
ENDIF ; FLOAT
cEndCode
; []----------------------------------------------[]
; | |
; | FLOATING POINT FOR BORLAND C/C++ |
; | |
; []----------------------------------------------[]
; Borland and Turbo C/C++ only (no Microsoft)
IF COMPILER GE TC2 ; {
; For Borland Turbo C++ only...
IF COMPILER GE TCPP ; {
cBegCode
;------------------------------------------------------------------
; Loop through a startup/exit (SE) table,
; calling functions in order of priority.
; DS:SI is assumed to point to the beginning of the SE table
; DS:DI is assumed to point to the end of the SE table
; First 64 priorities are reserved by Borland
;------------------------------------------------------------------
PNEAR EQU 0
PFAR EQU 1
NOTUSED EQU 0ffh
SE STRUC
calltype db ? ; 0=near,1=far,ff=not used
priority db ? ; 0=highest,ff=lowest
addrlow dw ?
addrhigh dw ?
SE ENDS
StartExit PROC NEAR
@@Start: mov ah,0ffh ; start with lowest priority
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -