dos_compilers/Mix Power C v1/EXEC.ASM
2024-07-01 15:26:34 -07:00

693 lines
18 KiB
NASM

;
; Copyright (c) Mix Software 1988
;
;
; Call a program & return to caller
;
; _spawn(progpath,command,envp);
;
; progpath is the address of the program's path name
; command is the command line to pass
; envp is the pointer to the environment
;
IDT _SPAWN
DEF _SPAWN
DEF _spawn
DREF $$PSP
DREF $$TOPSEG
FREF _FMAX
;PARM1 EQU 6
;PARM2 EQU PARM1+2
;PARM3 EQU PARM2+2
;
_spawn equ $
_SPAWN PUSH BP
MOV BP,SP
CALLFAR _FMAX ; find top of usable memory
MOV BX,AX
SUB BX,[$$PSP] ; Size in use
MOV ES,[$$PSP] ; Shrink memory
MOV AX,>4A00
INT >21
MOV AX,DS
MOV ES,AX
MOV DI,EXEBLK
MOV AX,[BP][%PARM3]
STOSW
MOV AX,[BP][%PARM2]
STOSW
MOV AX,DS
STOSW
MOV AX,>5C
STOSW
MOV AX,[$$PSP]
STOSW
MOV AX,>6C
STOSW
MOV AX,[$$PSP]
STOSW
PUSH DS
MOV AX,SS
SEGCS
MOV [SAVESS],AX
MOV AX,SP
SEGCS
MOV [SAVESP],AX
MOV BX,EXEBLK
MOV DX,[BP][%PARM1]
MOV AX,>4B00
INT >21
SEGCS
MOV CX,[SAVESS]
SEGCS
MOV DX,[SAVESP]
MOV SS,CX
MOV SP,DX
POP CX
MOV DS,CX
POP BP
JB EXIT
XOR AX,AX
EXIT PUSH AX
MOV ES,[$$PSP] ; Restore memory to original size
SEGES
MOV BX,[$$TOPSEG]
SUB BX,[$$PSP] ; original size
MOV AX,>4A00
INT >21
POP AX
RETSEG
SAVESS DW 0-0
SAVESP DW 0-0
;
DORG 0
EXEBLK DW 0 ; Segment of environment
DW >80 ; Command tail
DW 0 ; Command tail segment
DW >5C ; First FCB
DW 0 ; FCB segment
DW >6C ; Second FCB
DW 0 ; FCB segment
END
;
; included if _p_overlay is used
;
IDT _p_chn1
DDEF _p_chain
DDEF _p_chenv
LDDEF _p_overlay
REF _chain
REF _chainev
DORG 0
_p_overlay DW 2
_p_chain DW _chain
_p_chenv DW _chainev
END
;
; included if _p_overlay is not used
;
IDT _p_chain
DDEF _p_chain
DDEF _p_chenv
DORG 0
_p_chain DW 0
_p_chenv DW 0
END
;
; Chain routines for C compiler
;
; _chain(handle,cmdline);
;
; handle is the file handle of the .com or .exe file
; cmdline is the command line to pass to the program
;
IDT _CHAIN
DEF _CHAIN
DEF _chain
FREF _EXELDR
DREF $$PSP
DREF $$ENVIR
;PARM1 EQU 6
;PARM2 EQU PARM1+2
;PARM3 EQU PARM2+2
;PARM4 EQU PARM3+2
_chain equ $
_CHAIN PUSH BP
MOV BP,SP
MOV ES,[$$PSP]
CMP [BP][%PARM2],0
JZ NOCMD
MOV SI,[BP][%PARM2]
MOV DI,>80
MOV CX,128/2
CLD
REP
MOVSW
MOV DI,>100
JMPS LOAD
NOCMD SEGES
MOV [>80],>0D00
LOAD MOV DI,>0010
ADD DI,[$$PSP]
MOV BX,[BP][%PARM1]
MOV ES,[$$PSP]
CALLFAR _EXELDR
EXIT MOV AX,-1
POP BP
RETSEG
END
;
; Chain routines for C compiler
;
; _chainev(handle,cmdline,envir);
;
; handle is the file handle of the .com or .exe file
; cmdline is the command line to pass to the program
; envir is the segment address of the environment
;
IDT _CHAINEV
DEF _CHAINEV
DEF _chainev
FREF _EXELDR
DREF $$PSP
DREF $$ENVIR
;PARM1 EQU 6
;PARM2 EQU PARM1+2
;PARM3 EQU PARM2+2
;PARM4 EQU PARM3+2
FCBSIZE EQU 38
_chainev equ $
_CHAINEV PUSH BP
MOV BP,SP
MOV ES,[$$PSP]
CMP [BP][%PARM2],0
JZ NOCMD
MOV SI,[BP][%PARM2]
MOV CX,128/2
MOV DI,>80
CLD
REP
MOVSW
MOV DI,>100
JMPS ENVIR
NOCMD SEGES
MOV [>80],>0D00
ENVIR MOV SI,[BP][%PARM3]
TEST SI,SI
JZ NOENVIR
CMP SI,[$$ENVIR]
JZ NOENVIR
MOV ES,SI
XOR DI,DI
MOV AL,%0
MOV CX,-1
CLD
FINDLEN SEGES
CMP %[DI],%0 ; end of table?
JZ ENDENV
REPNZ
SCASB
JMPS FINDLEN
ENDENV NOT CX ; CX is size of the environment
ADD CX,%2 ; Terminating zero & round up
AND CX,>FFFE ; Make size even
SHR CX,1 ; Size in words
MOV ES,[$$PSP]
MOV DS,[BP][%PARM3]
XOR SI,SI
MOV DI,>100+XBLKSIZE+XCODESZ
ADD DI,15
AND DI,>FFF0
PUSH DI ; Environment origin
REP
MOVSW
MOV AX,SS
MOV DS,AX
POP DX
MOV CL,4
SHR DX,CL
ADD DX,[$$PSP]
JMPS LOAD
NOENVIR MOV DX,[$$ENVIR]
MOV DI,>100+XBLKSIZE+XCODESZ
LOAD PUSH DI
PUSH DX
MOV DS,[$$PSP]
MOV ES,[$$PSP]
MOV DI,>5C ; Parse default fcb
MOV SI,>81
MOV AX,>2900
INT >21
SUB SP,FCBSIZE ; Parse 2nd fcb
MOV DI,SP ; use stack for buffer
MOV AX,SS
MOV ES,AX
MOV AX,>2900
INT >21
MOV AX,SS
MOV DS,AX
MOV SI,SP
MOV DI,>6C ; Copy 2nd fcb
MOV ES,[$$PSP]
MOV CX,>80->6C
REP
MOVSB
ADD SP,%FCBSIZE
;
MOV SI,XCODE ; Code to shrink memory & exe
MOV DI,>100
MOV AX,CS
MOV DS,AX
MOV CX,XCODESZ+XBLKSIZE
REP
MOVSB
SEGES ; Set segments in parameter block
MOV [>100+CMDSEG],ES
SEGES
MOV [>100+FCB1SEG],ES
SEGES
MOV [>100+FCB2SEG],ES
POP DX
SEGES
MOV [>100+ENVSEG],DX
POP DI ; End of retained memory
ADD DI,>000F ; round to segment for release
MOV CL,4
SHR DI,CL
MOV BX,DI
PUSH ES
MOV AX,XCODE1-XCODE+>100
PUSH AX
MOV AX,>4A00
RETSEG
;
XCODE DW 0 ; Segment of environment
DW >80 ; Command tail
DW 0 ; Command tail segment
DW >5C ; First FCB
DW 0 ; FCB segment
DW >6C ; Second FCB
DW 0 ; FCB segment
XBLKSIZE EQU $-XCODE
ENVSEG EQU >0
CMDSEG EQU >4
FCB1SEG EQU >8
FCB2SEG EQU >C
;
;
; Address independent code to shrink memory and
; execute the program.
;
; BX = size of memory block
;
XCODE0 EQU $
ERR MOV DX,ERRMSG
MOV AX,CS
MOV DS,AX
MOV AH,>09
INT >21
MOV AX,>4C01
INT >21
ERRMSG DB >0D,>0A,'Load error',>0D,>0A,'$'
XCODE1 INT >21
JB ERR
MOV DX,[BP][%PARM1] ; File name
MOV AX,SS
MOV DS,AX
MOV AX,CS
MOV ES,AX
MOV BX,>100
MOV AX,>4B00
INT >21 ; Load and execute program
XCODE2 JB ERR ; Unable to load
MOV AX,CS
MOV SS,AX
MOV SP,XCODE2-XCODE+>100
MOV AX,>4D00 ; Get return code
INT >21
MOV AH,>4C
INT >21 ; Back to DOS
XCODESZ EQU $-XCODE0
END
;
; exe and com file loader
;
; BX = file handle for the file
; DI = segment address for load
; ES = segment address of psp
;
HDRSIZE EQU >1A
FCBSIZE EQU 38
BUFSZ EQU 512
HANDLE EQU 0
PSP EQU 2
ORG EQU 4
LOADORG EQU 6
STACKRES EQU HDRSIZE+8
EXESIG EQU 8
EXELENM EQU EXESIG+>2 ; Size of file mod 512
EXELEN EQU EXESIG+>4 ; Size of file div 512
EXERELCT EQU EXESIG+>6 ; Count of relocation items
EXEHDRSZ EQU EXESIG+>8 ; Size of header in paragraphs
EXEMIN EQU EXESIG+>A ; Minimum paragraphs needed
EXEMAX EQU EXESIG+>C ; Maximum paragraphs desired
EXESS EQU EXESIG+>E ; Stack segment
EXESP EQU EXESIG+>10 ; Stack pointer
EXECKSUM EQU EXESIG+>12 ; Word checksum
EXEIP EQU EXESIG+>14 ; Starting ip value
EXECS EQU EXESIG+>16 ; Starting code segment
EXEREL EQU EXESIG+>18 ; Offset of first relocation item
;
IDT _EXELDR
DEF _EXELDR
_EXELDR PUSH BP
SUB SP,STACKRES
MOV BP,SP
MOV [BP][%HANDLE],BX
MOV [BP][%ORG],DI
MOV [BP][%PSP],ES
MOV AX,ES
MOV DS,AX
MOV DI,>5C ; Parse default fcb
MOV SI,>81
MOV AX,>2900
INT >21
SUB SP,FCBSIZE ; Parse 2nd fcb
MOV DI,SP ; use stack for buffer
MOV AX,SS
MOV ES,AX
MOV AX,>2900
INT >21
MOV AX,SS
MOV DS,AX
MOV SI,SP
MOV DI,>6C ; Copy 2nd fcb
MOV ES,[BP][%PSP]
MOV CX,>80->6C
REP
MOVSB
ADD SP,%FCBSIZE
MOV CX,HDRSIZE
LEA DX,[BP][%EXESIG]
MOV AX,>3F00
INT >21 ; Read initial header
CMP [BP][%EXESIG],>5A4D ; test for .exe signature
JZ LOADEXE
;
; Load .com file
;
LOADCOM MOV DI,[BP][%ORG] ; Load address
SUB DI,>10
CMP DI,[BP][%PSP]
JNZ LDERR ; com file must load at >100
MOV AX,CS
MOV DS,AX ; Copy header for .COM file
MOV SI,COMEXE
MOV AX,SS
MOV ES,AX
LEA DI,[BP][%EXELENM]
MOV CX,(EXECS-EXELENM)/2
REP
MOVSW
MOV AX,[BP][%PSP]
MOV [BP][%EXESS],AX
MOV [BP][%EXECS],AX
JMPS LOADEXE
; ; mock exe header for .com files
COMEXE DW >100 ; size mod 512
DW >80 ; size in blocks
DW 0 ; relocation count
DW 0 ; header size
DW 1 ; min paragraphs
DW -1 ; max paragraphs
DW 0-0 ; stack segment
DW >FFFE ; stack pointer
DW 0 ; checksum
DW >100 ; instruction pointer
LDERR MOV AX,-1
LDEXIT LEA SP,[BP][%STACKRES]
POP BP
RETSEG
MEMERR MOV AX,-2
JMPS LDEXIT
;
; .exe file loader
; SS:BP points to the parameters
;
LOADEXE MOV DX,[BP][%EXELEN] ; Length of file
MOV AX,[BP][%EXELENM]
CMP AX,0 ; Full page?
JZ FULLPAGE
DEC DX
FULLPAGE MOV CL,5
SHL DX,CL ; Convert to paragraphs
DEC CL
SHR AX,CL
ADD DX,AX ; DX = size in paragraphs
SUB DX,[BP][%EXEHDRSZ] ; - size of header
AND [BP][%EXELENM],>000F ; fraction
JZ EVEN01
INC DX
EVEN01 MOV [BP][%EXELEN],DX ; code size in paragraphs
MOV ES,[BP][%PSP]
MOV BX,[BP][%EXEMAX]
CMP BX,LOADSZP ; minimum needed for loader
JAE USEMAX
MOV BX,LOADSZP
USEMAX ADD BX,DX
JNB SETMEM
MOV BX,-1
SETMEM MOV AH,>4A ; set memory size
PUSH BX
INT >21
JB TRYMAX
POP BX
JMPS MEMSET
TRYMAX POP AX
MOV AH,>4A ; Get maximum available
PUSH BX
INT >21
POP BX
JB HAVEMEM ; Try what we already have
MEMSET ADD BX,[BP][%PSP]
SEGES
MOV [2],BX
HAVEMEM MOV AX,[BP][%EXELEN]
ADD AX,[BP][%ORG]
MOV [BP][%LOADORG],AX ; Segment address for loader
MOV DX,[BP][%EXEMIN] ; Minimum memory above code
CMP DX,LOADSZP
JAE USEMIN
MOV DX,LOADSZP
USEMIN ADD AX,DX ; Minimum memory to load
SEGES
CMP AX,[2]
JA MEMERR ; Not enough memory
;
; Move the loader code and branch to it
; Copies the control point and argument block to the
; program's target address before moving the loader. This
; protects against the loader's target conflicting with
; the stack space or code space for the executing program.
;
; SS:BP = location of argument block
;
;
MOVEGO MOV SI,FINAL ; Final move instructions
MOV ES,[BP][%ORG]
XOR DI,DI
MOV AX,CS
MOV DS,AX
MOV CX,EFINAL-FINAL
CLD
REP
MOVSB
MOV SI,BP ; Data block
MOV BP,DI
MOV AX,SS
MOV DS,AX
MOV CX,STACKRES
REP
MOVSB
ADD DI,>100 ; Temporary stack space for
MOV DX,ES ; move routine
MOV SS,DX
MOV SP,DI ; Relocate stack
PUSH [BP][%LOADORG] ; Address of final target
XOR AX,AX
PUSH AX
PUSH DX ; Return to move routine
PUSH AX
MOV DX,CS
MOV DS,DX
MOV SI,EXELOAD
MOV CX,LOADRSZ
MOV DX,DI
REP ; Move loader to low memory
MOVSB
MOV SI,DX
MOV AX,ES
MOV DS,AX
MOV ES,[BP][%LOADORG]
XOR DI,DI
MOV CX,LOADRSZ
RETSEG ; Branch & move loader high
FINAL REP
MOVSB ; Move loader above program
RETSEG ; Transfer to loader
EFINAL EQU $
;
;
; Relocatable .EXE file loader
; BP points to argument block
;
EXELOAD MOV AX,SS ; Copy stack to local storage
MOV DS,AX
MOV SI,BP
MOV AX,CS
MOV ES,AX
MOV DI,EXESTK-EXELOAD
MOV BP,DI
MOV CX,STACKRES
CLD
REP
MOVSB
MOV DX,EXESTK+256
MOV SS,AX
MOV SP,DX
MOV BX,[BP][%HANDLE]
MOV DS,[BP][%PSP]
MOV DX,[BP][%EXEHDRSZ] ; Seek file past header
XOR AX,AX
MOV CX,4
HDRSZ SHL DX,1
RCL AX,1
LOOP HDRSZ
MOV CX,AX
MOV BX,[BP][%HANDLE]
MOV AX,>4200
INT >21 ; Seek to beginning of file
JB EXEERR1
MOV DS,[BP][%ORG]
READEXE MOV CX,[BP][%EXELEN]
JCXZ DONEREAD
CMP CX,>7FF
JBE ONEREAD
MOV CX,>7FF0
SUB [BP][%EXELEN],>7FF
JMPS READ1
ONEREAD CMP [BP][%EXELENM],0
JZ EVEN02
DEC CX
EVEN02 MOV AX,CX
MOV CL,4
SHL AX,CL
ADD AX,[BP][%EXELENM]
MOV CX,AX
MOV [BP][%EXELEN],0
READ1 MOV AX,>3F00
XOR DX,DX
INT >21
JB EXEERR1
CMP AX,CX
JNZ EXEEND
MOV AX,DS
ADD AX,>7FF
MOV DS,AX
JMPS READEXE
EXEEND CMP [BP][%EXESIG],>5A4D
JNZ EXEERR1 ; EXE file too short
GOCOM1 JMP GOCOM ; .COM file
EXEERR1 JMP EXEERR
;
; Seek to relocation table
; Read relocation data into buffer & apply
;
DONEREAD CMP [BP][%EXESIG],>5A4D
JNZ GOCOM1
CMP [BP][%EXERELCT],0
JZ GOEXE
MOV DX,[BP][%EXEREL]
XOR CX,CX ; Seek to relocation table
MOV BX,[BP][%HANDLE]
MOV AX,>4200
INT >21
JB EXEERR1
READTBL MOV CX,[BP][%EXERELCT]
JCXZ GOEXE ; End of relocation table
CMP CX,BUFSZ/4
JBE ONEBLOCK
MOV CX,BUFSZ/4
ONEBLOCK SUB [BP][%EXERELCT],CX
SHL CX,1
SHL CX,1
MOV BX,[BP][%HANDLE]
MOV AX,SS
MOV DS,AX
MOV AH,>3F
LEA DX,[BP][%EXEREL+2]
INT >21 ; Read a block of relocations
JB EXEERR1
CMP AX,CX
JNZ EXEERR
SHR CX,1
SHR CX,1
LEA SI,[BP][%EXEREL+2]
MOV DX,[BP][%ORG]
RELOC MOV DI,[SI] ; Apply relocations
MOV AX,[SI][%2]
ADD AX,DX
MOV ES,AX
SEGES
ADD [DI],DX
ADD SI,%4
LOOP RELOC
JMPS READTBL
;
; Load registers from header & transfer to program
;
GOEXE MOV BX,[BP][%HANDLE]
MOV AH,>3E
INT >21
MOV AX,[BP][%PSP]
MOV DS,AX
MOV ES,AX
MOV AX,[BP][%ORG]
MOV DX,AX
ADD AX,[BP][%EXESS]
ADD DX,[BP][%EXECS]
MOV BX,[BP][%EXESP]
MOV CX,[BP][%EXEIP]
MOV SS,AX
MOV SP,BX
PUSH DX
PUSH CX
RETSEG
;
GOCOM MOV BX,[BP][%HANDLE]
MOV AH,>3E
INT >21
MOV AX,[BP][%PSP]
MOV DS,AX
MOV ES,AX
MOV BX,>FFFE
MOV [BX],0
MOV SS,AX
MOV SP,BX
PUSH AX
MOV AX,>100
PUSH AX
RETSEG
;
;
EXEERR MOV DX,ERRMSG
MOV AH,>09
INT >21
MOV AX,>4C01
INT >21
ERRMSG DB >0D,>0A,'Load error',>0D,>0A,'$'
LOADRSZ EQU $-EXELOAD
LOADSZP EQU (LOADRSZ+BUFSZ+256)/16
EXESTK EQU $
END