MS-DOS/v2.0/source/COMMAND.ASM

788 lines
23 KiB
NASM
Raw Normal View History

1983-08-13 01:53:34 +01:00
;
; This version of COMMAND is divided into three distinct parts. First is the
; resident portion, which includes handlers for interrupts 22H (terminate),
; 23H (Cntrl-C), 24H (fatal error), and 27H (stay resident); it also has code
; to test and, if necessary, reload the transient portion. Following the
; resident is the init code, which is overwritten after use. Then comes the
; transient portion, which includes all command processing (whether internal
; or external). The transient portion loads at the end of physical memory,
; and it may be overlayed by programs that need as much memory as possible.
; When the resident portion of command regains control from a user program, a
; checksum is performed on the transient portion to see if it must be
; reloaded. Thus programs which do not need maximum memory will save the time
; required to reload COMMAND when they terminate.
;
; REV 1.17
; 05/19/82 Fixed bug in BADEXE error (relocation error must return to
; resident since the EXELOAD may have overwritten the transient.
; REV 1.18
; 05/21/82 IBM version always looks on drive A
; MSVER always looks on default drive
;
; REV 1.19
; 06/03/82 Drive spec now entered in command line
; 06/07/82 Added VER command (print DOS version number) and VOL command
; (print volume label)
; REV 1.20
; 06/09/82 Prints "directory" after directories
; 06/13/82 MKDIR, CHDIR, PWD, RMDIR added
; REV 1.50
; Some code for new 2.0 DOS, sort of HACKey. Not enough time to
; do it right.
; REV 1.70
; EXEC used to fork off new processes
; REV 1.80
; C switch for single command execution
; REV 1.90
; Batch uses XENIX
; Rev 2.00
; Lots of neato stuff
; IBM 2.00 level
; Rev 2.01
; 'D' switch for date time suppression
; Rev 2.02
; Default userpath is NUL rather than BIN
; same as IBM
; COMMAND split into pieces
; Rev 2.10
; INTERNATIONAL SUPPORT
; Rev 2.11 COMMAND split into more pieces
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
INCLUDE COMSW.ASM
INCLUDE COMEQU.ASM
CODERES SEGMENT PUBLIC
CODERES ENDS
DATARES SEGMENT PUBLIC BYTE
EXTRN COMBAD:BYTE,NEEDCOM:BYTE,DRVMSG:BYTE
EXTRN DEFMSG:BYTE,PROMPT:BYTE,EXECEMES:BYTE,EXEBAD:BYTE
EXTRN TOOBIG:BYTE,NOCOM:BYTE,RBADNAM:BYTE,INT_2E_RET:DWORD
EXTRN NOHANDMES:BYTE,BMEMMES:BYTE,HALTMES:BYTE,FRETMES:BYTE
EXTRN PARENT:WORD,HANDLE01:WORD,LOADING:BYTE,BATCH:WORD
EXTRN TRNSEG:WORD,COMDRV:BYTE,MEMSIZ:WORD,SUM:WORD,EXTCOM:BYTE
EXTRN IO_SAVE:WORD,PERMCOM:BYTE,SINGLECOM:WORD,VERVAL:WORD
EXTRN PIPEFLAG:BYTE,SAVE_PDB:WORD,COMSPEC:BYTE,TRANS:WORD
EXTRN TRANVARS:BYTE,LTPA:WORD,RSWITCHAR:BYTE,RDIRCHAR:BYTE
EXTRN RETCODE:WORD,FORFLAG:BYTE
IF IBMVER
EXTRN SYS_CALL:DWORD,ZEXEC:WORD,EXESEG:WORD,EXESUM:WORD
EXTRN USER_SS:WORD,USER_SP:WORD
ENDIF
DATARES ENDS
ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment
ENVIRONMENT ENDS
INIT SEGMENT PUBLIC PARA
EXTRN CONPROC:NEAR
INIT ENDS
TAIL SEGMENT PUBLIC PARA
TAIL ENDS
TRANCODE SEGMENT PUBLIC PARA
TRANCODE ENDS
TRANDATA SEGMENT PUBLIC BYTE
EXTRN TRANDATAEND:BYTE
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE
EXTRN TRANSPACEEND:BYTE,HEADCALL:DWORD
TRANSPACE ENDS
TRANTAIL SEGMENT PUBLIC PARA
TRANTAIL ENDS
ZEXEC_CODE SEGMENT PUBLIC PARA
ZEXEC_CODE ENDS
ZEXEC_DATA SEGMENT PUBLIC BYTE
ZEXEC_DATA ENDS
RESGROUP GROUP CODERES,DATARES,ENVIRONMENT,INIT,TAIL
TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL
EGROUP GROUP ZEXEC_CODE,ZEXEC_DATA
ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment
PUBLIC ECOMSPEC,ENVIREND,PATHSTRING
ORG 0
ENVARENA DB 10H DUP (?) ; Pad for mem arena
PATHSTRING DB "PATH="
USERPATH LABEL BYTE
DB 0 ; Null path
DB "COMSPEC="
ECOMSPEC DB "/COMMAND.COM"
DB 134 DUP (0)
ENVIREND LABEL BYTE
ENVIRONSIZ EQU $-PATHSTRING
ENVIRONSIZ2 EQU $-ECOMSPEC
ENVIRONMENT ENDS
; START OF RESIDENT PORTION
CODERES SEGMENT PUBLIC
PUBLIC GETCOMDSK2,LODCOM,THEADFIX,CONTCTERM,LOADCOM,INT_2E,LODCOM1
PUBLIC CHKSUM,SETVECT,EXT_EXEC,TREMCHECK,RESTHAND,CONTC,RSTACK
PUBLIC SAVHAND
IF IBMVER
PUBLIC EXECHK,SYSCALL,EXEC_WAIT
ENDIF
ASSUME CS:RESGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN RPRINT:NEAR,ASKEND:NEAR,DSKERR:NEAR
ORG 0
ZERO = $
ORG 100H
PROGSTART:
JMP RESGROUP:CONPROC
DB (80H - 3) DUP (?)
RSTACK LABEL WORD
IF IBMVER
SYSCALL:
CMP AH,EXEC
JZ do_exec
JMP DWORD PTR [SYS_CALL]
do_exec:
PUSH ES
PUSH DS
PUSH BP
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV [user_ss],SS
MOV [user_sp],SP
;
; are we running on RSTACK already?
;
PUSH CS
POP BX ; BX <- CS
PUSH SS
POP AX ; AX <- SS
CMP AX,BX ; IF AX == BX then no stack switch!
JZ Get_mem
MOV SS,BX
ASSUME SS:RESGROUP
MOV SP,OFFSET RESGROUP:RSTACK
Get_mem:
MOV BX,0FFFFH ; allocate all of memory
MOV AH,ALLOC
INT int_command
MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR AX,CL
MOV CX,AX ; Save in CX
CMP BX,AX ; enough for EXEC?
JB EXECMER ; nope... cry
MOV AH,ALLOC
INT int_command
JC EXECMER ; Memory arenas probably trashed
ADD BX,AX
MOV [MEMSIZ],BX
SUB BX,CX
MOV [EXESEG],BX ; exec
MOV ES,AX
MOV AH,DEALLOC
INT int_command
PUSH CS
POP DS
ASSUME DS:RESGROUP
CALL EXECHK
CMP DX,[EXESUM]
JZ HAVEXEC ; EXEC OK
MOV DX,OFFSET RESGROUP:COMSPEC
MOV AX,OPEN SHL 8
INT int_command ; Open COMMAND.COM
JC EXECMER
MOV BX,AX ; Handle
MOV DX,OFFSET RESGROUP:TRANSTART
ADD DX,OFFSET TRANGROUP:EXECSTART - 100H
XOR CX,CX ; Seek loc
MOV AX,LSEEK SHL 8
INT int_command
MOV CX,OFFSET EGROUP:ZEXECCODEEND
MOV DS,[EXESEG]
ASSUME DS:NOTHING
MOV AH,READ
INT int_command
PUSH AX
MOV AH,CLOSE
INT int_command ; Close COMMAND.COM
POP CX
CMP CX,OFFSET EGROUP:ZEXECCODEEND
JNZ EXECMER ; Size matched
CALL EXECHK
CMP DX,[EXESUM]
JNZ EXECMER
HAVEXEC:
MOV [LOADING],0 ; Flag to DSKERR
CALL DWORD PTR [ZEXEC]
JMP SHORT EXECRET
execmer:
LDS SI,DWORD PTR [user_Sp]
MOV [SI.user_AX],exec_not_enough_memory
PUSH [SI.user_F]
POPF
STC
PUSHF
POP [SI.user_F]
execret:
MOV SS,[user_SS]
ASSUME SS:NOTHING
MOV SP,[user_SP]
POP AX ; PUSH ES
POP BX ; PUSH DS
POP CX ; PUSH BP
POP DX ; PUSH DI
POP SI ; PUSH SI
POP DI ; PUSH DX
POP BP ; PUSH CX
POP DS ; PUSH BX
POP ES ; PUSH AX
IRET
EXECHK:
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
PUSH DS
MOV DS,[EXESEG]
MOV CX,OFFSET EGROUP:ZEXECCODEEND
XOR SI,SI
JMP CHECK_SUM
ENDIF
EXEC_ERR: ; Select the correct error message
MOV DX,OFFSET RESGROUP:RBADNAM
CMP AX,exec_file_not_found
JZ GOTEXECEMES
CMP AX,error_access_denied
JZ GOTEXECEMES
MOV DX,OFFSET RESGROUP:TOOBIG
CMP AX,exec_not_enough_memory
JZ GOTEXECEMES
MOV DX,OFFSET RESGROUP:EXEBAD
CMP AX,exec_bad_format
JZ GOTEXECEMES
MOV DX,OFFSET RESGROUP:EXECEMES
GOTEXECEMES:
PUSH CS
POP DS
CALL RPRINT
JMP SHORT NOEXEC
EXT_EXEC:
;
; we are now running in free space. anything we do from here
; on may get trashed. Move the stack (also in free space) to
; allocated space because since EXEC restores the stack,
; somebody may trash what is on the stack.
;
MOV CX,CS
MOV SS,CX
MOV SP,OFFSET RESGROUP:RSTACK
;
; Oops!! We have to make sure that the EXEC code doesn't blop a newstack!
;
;
INT int_command ; Do the EXEC
JC EXEC_ERR ; EXEC failed
EXEC_WAIT:
MOV AH,WAIT
INT int_command ; Get the return code
MOV [RETCODE],AX
NOEXEC:
JMP LODCOM
CONTC:
STI
MOV AX,CS
MOV DS,AX
ASSUME DS:RESGROUP
MOV AH,DISK_RESET
INT int_command ; Reset disks in case files were open
TEST [BATCH],-1
JZ CONTCTERM
JMP ASKEND ; See if user wants to terminate batch
CONTCTERM:
XOR BP,BP ; Indicate no read
MOV [FORFLAG],0 ; Turn off for processing
MOV [PIPEFLAG],0 ; Turn off any pipe
CMP [SINGLECOM],0 ; See if we need to set SINGLECOM
JZ NOSETSING
MOV [SINGLECOM],-1 ; Cause termination on pipe, batch, for
NOSETSING:
CMP [EXTCOM],0
JNZ DODAB ; Internal ^C
JMP LODCOM1
DODAB:
STC ; Tell DOS to abort
ZZY PROC FAR
RET ; Leave flags on stack
ZZY ENDP
BADMEMERR: ; Allocation error loading transient
MOV DX,OFFSET RESGROUP:BMEMMES
FATALC:
PUSH CS
POP DS
CALL RPRINT
CMP [PERMCOM],0
JZ FATALRET
CMP [SINGLECOM],0 ; If PERMCOM and SINGLECOM
JNZ FATALRET ; Must take INT_2E exit
MOV DX,OFFSET RESGROUP:HALTMES
CALL RPRINT
STALL:
JMP STALL ; Crash the system nicely
FATALRET:
MOV DX,OFFSET RESGROUP:FRETMES
CALL RPRINT
FATALRET2:
CMP [PERMCOM],0 ; If we get here and PERMCOM,
JNZ RET_2E ; must be INT_2E
IF IBM
LDS DX,DWORD PTR [SYS_CALL]
ASSUME DS:NOTHING
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) + INT_COMMAND
INT int_command
ENDIF
MOV AX,[PARENT]
MOV WORD PTR CS:[PDB_Parent_PID],AX
MOV AX,(EXIT SHL 8) ; Return to lower level
INT int_command
RET_2E:
PUSH CS
POP DS
ASSUME DS:RESGROUP,ES:NOTHING,SS:NOTHING
MOV [SINGLECOM],0 ; Turn off singlecom
MOV ES,[LTPA]
MOV AH,DEALLOC
INT int_command ; Free up space used by transient
MOV BX,[SAVE_PDB]
MOV AH,SET_CURRENT_PDB
INT int_command ; Current process is user
MOV AX,[RETCODE]
CMP [EXTCOM],0
JNZ GOTECODE
XOR AX,AX ; Internals always return 0
GOTECODE:
MOV [EXTCOM],1 ; Force external
JMP [INT_2E_RET] ;"IRET"
INT_2E: ; Magic command executer
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
POP WORD PTR [INT_2E_RET]
POP WORD PTR [INT_2E_RET+2] ;Get return address
POP AX ;Chuck flags
PUSH CS
POP ES
MOV DI,80H
MOV CX,64
REP MOVSW
MOV AH,GET_CURRENT_PDB
INT int_command ; Get user's header
MOV [SAVE_PDB],BX
MOV AH,SET_CURRENT_PDB
MOV BX,CS
INT int_command ; Current process is me
MOV [SINGLECOM],81H
MOV [EXTCOM],1 ; Make sure this case forced
LODCOM: ; Termination handler
CMP [EXTCOM],0
JZ LODCOM1 ; If internal, memory already allocated
MOV BX,0FFFFH
MOV AH,ALLOC
INT int_command
MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15
MOV CL,4
SHR AX,CL
IF IBM
PUSH AX
MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR AX,CL
POP CX
ADD AX,CX
ENDIF
ADD AX,20H
CMP BX,AX ; Is less than 512 byte buffer worth it?
JNC MEMOK
BADMEMERRJ:
JMP BADMEMERR ; Not enough memory
MEMOK:
MOV AH,ALLOC
INT int_command
JC BADMEMERRJ ; Memory arenas probably trashed
MOV [EXTCOM],0 ; Flag not to ALLOC again
MOV [LTPA],AX ; New TPA is base just allocated
ADD BX,AX
MOV [MEMSIZ],BX
MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15
MOV CL,4
SHR AX,CL
IF IBM
PUSH AX
MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15
MOV CL,4
SHR AX,CL
POP CX
ADD AX,CX
ENDIF
SUB BX,AX
MOV [TRNSEG],BX ; Transient starts here
LODCOM1:
MOV AX,CS
MOV SS,AX
ASSUME SS:RESGROUP
MOV SP,OFFSET RESGROUP:RSTACK
MOV DS,AX
ASSUME DS:RESGROUP
CALL HEADFIX ; Make sure files closed stdin and stdout restored
XOR BP,BP ; Flag command ok
MOV AX,-1
XCHG AX,[VERVAL]
CMP AX,-1
JZ NOSETVER
MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value
INT int_command
NOSETVER:
CMP [SINGLECOM],-1
JNZ NOSNG
JMP FATALRET2 ; We have finished the single command
NOSNG:
CALL SETVECT
IF IBMVER
CALL EXECHK ; Check exe loader
CMP DX,[EXESUM]
JNZ BOGUS_COM
ENDIF
CALL CHKSUM ; Check the transient
CMP DX,[SUM]
JZ HAVCOM ; Transient OK
BOGUS_COM:
MOV [LOADING],1 ; Flag DSKERR routine
CALL LOADCOM
CHKSAME:
IF IBMVER
CALL EXECHK
CMP DX,[EXESUM]
JNZ ALSO_BOGUS
ENDIF
CALL CHKSUM
CMP DX,[SUM]
JZ HAVCOM ; Same COMMAND
ALSO_BOGUS:
CALL WRONGCOM
JMP SHORT CHKSAME
HAVCOM:
MOV AX,CHAR_OPER SHL 8
INT int_command
MOV [RSWITCHAR],DL
CMP DL,'/'
JNZ USESLASH
MOV [RDIRCHAR],'\' ; Select alt path separator
USESLASH:
MOV [LOADING],0 ; Flag to DSKERR
MOV SI,OFFSET RESGROUP:TRANVARS
MOV DI,OFFSET TRANGROUP:HEADCALL
MOV ES,[TRNSEG]
CLD
MOV CX,8
REP MOVSW ; Transfer INFO to transient
MOV AX,[MEMSIZ]
MOV WORD PTR DS:[PDB_block_len],AX ; Adjust my own header
JMP DWORD PTR [TRANS]
; Far call to REMCHECK for TRANSIENT
TREMCHECK PROC FAR
CALL REMCHECK
RET
TREMCHECK ENDP
REMCHECK:
;All registers preserved. Returns zero if media removable, NZ if fixed
; AL is drive (0=DEF, 1=A,...)
IF IBM
PUSH AX
OR AL,AL
JNZ GOTDRV2
MOV AH,GET_DEFAULT_DRIVE
INT int_command
INC AL ;A=1
GOTDRV2:
PUSH BX
MOV BL,AL
INT 11H ;IBM EQUIP CALL
ROL AL,1
ROL AL,1
AND AL,3
JNZ NOT_SINGLE
INC AL
NOT_SINGLE:
INC AL ; AL is now MAX floppy #
CMP BL,AL
POP BX
JBE SETREM ; Is an IBM floppy and so is removable
OR AL,AL ; Know AL is non-zero
JMP SHORT SETNREM
SETREM:
ELSE
PUSH AX
ENDIF
XOR AX,AX ;Zero
IF IBM
SETNREM:
ENDIF
POP AX
RET
; Far call to HEADFIX for TRANSIENT
THEADFIX PROC FAR
CALL HEADFIX
RET
THEADFIX ENDP
HEADFIX:
XOR BX,BX ; Clean up header
MOV CX,[IO_SAVE]
MOV DX,WORD PTR DS:[PDB_JFN_Table]
CMP CL,DL
JZ CHK1 ; Stdin matches
MOV AH,CLOSE
INT int_command
MOV DS:[PDB_JFN_Table],CL ; Restore stdin
CHK1:
INC BX
CMP CH,DH ; Stdout matches
JZ CHKOTHERHAND
MOV AH,CLOSE
INT int_command
MOV DS:[PDB_JFN_Table+1],CH ; Restore stdout
CHKOTHERHAND:
ADD BX,4 ; Skip 2,3,4
MOV CX,FilPerProc - 5 ; Already done 0,1,2,3,4
CLOSELOOP:
MOV AH,CLOSE
INT int_command
INC BX
LOOP CLOSELOOP
RET
SAVHAND:
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
PUSH DS
PUSH BX ; Set stdin to sterr, stdout to stderr
PUSH AX
MOV AH,GET_CURRENT_PDB
INT int_command ; Get user's header
MOV DS,BX
MOV AX,WORD PTR DS:[PDB_JFN_Table]
MOV [HANDLE01],AX ; Save user's stdin, stdout
MOV AL,DS:[PDB_JFN_Table+2]
MOV AH,AL
MOV WORD PTR DS:[PDB_JFN_Table],AX ; Dup stderr
POP AX
POP BX
POP DS
RET
ASSUME DS:RESGROUP
GETCOMDSK2:
CALL GETCOMDSK
JMP LODCOM1 ; Memory already allocated
RESTHAND:
PUSH DS
PUSH BX ; Restore stdin, stdout to user
PUSH AX
MOV AH,GET_CURRENT_PDB
INT int_command ; Point to user's header
MOV AX,[HANDLE01]
MOV DS,BX
ASSUME DS:NOTHING
MOV WORD PTR DS:[PDB_JFN_Table],AX ; Stuff his old 0 and 1
POP AX
POP BX
POP DS
RET
ASSUME DS:RESGROUP,SS:RESGROUP
HOPELESS:
MOV DX,OFFSET RESGROUP:NOCOM
JMP FATALC
GETCOMDSK:
MOV DX,OFFSET RESGROUP:NEEDCOM
GETCOMDSK3:
MOV AL,[COMDRV]
CALL REMCHECK
JNZ HOPELESS ;Non-removable media
CALL RPRINT
MOV DX,OFFSET RESGROUP:DRVMSG
CMP [COMDRV],0
JNZ GETCOM1
MOV DX,OFFSET RESGROUP:DEFMSG
GETCOM1:
CALL RPRINT
MOV DX,OFFSET RESGROUP:PROMPT
CALL RPRINT
CALL GetRawFlushedByte
RET
; flush world and get raw input
GetRawFlushedByte:
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR RAW_CON_INPUT
INT int_command ; Get char without testing or echo
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
INT int_command
return
LOADCOM: ; Load in transient
INC BP ; Flag command read
MOV DX,OFFSET RESGROUP:COMSPEC
MOV AX,OPEN SHL 8
INT int_command ; Open COMMAND.COM
JNC READCOM
CMP AX,open_too_many_open_files
JNZ TRYDOOPEN
MOV DX,OFFSET RESGROUP:NOHANDMES
JMP FATALC ; Fatal, will never find a handle
TRYDOOPEN:
CALL GETCOMDSK
JMP SHORT LOADCOM
READCOM:
MOV BX,AX ; Handle
MOV DX,OFFSET RESGROUP:TRANSTART
XOR CX,CX ; Seek loc
MOV AX,LSEEK SHL 8
INT int_command
JC WRONGCOM1
MOV CX,OFFSET TRANGROUP:TRANSPACEEND - 100H
IF IBM
ADD CX,15
AND CX,0FFF0H
ADD CX,OFFSET EGROUP:ZEXECCODEEND
ENDIF
PUSH DS
MOV DS,[TRNSEG]
ASSUME DS:NOTHING
MOV DX,100H
MOV AH,READ
INT int_command
POP DS
ASSUME DS:RESGROUP
WRONGCOM1:
PUSHF
PUSH AX
MOV AH,CLOSE
INT int_command ; Close COMMAND.COM
POP AX
POPF
JC WRONGCOM ; If error on READ
CMP AX,CX
JZ RET10 ; Size matched
WRONGCOM:
MOV DX,OFFSET RESGROUP:COMBAD
CALL GETCOMDSK3
JMP SHORT LOADCOM ; Try again
CHKSUM: ; Compute transient checksum
PUSH DS
MOV DS,[TRNSEG]
MOV SI,100H
MOV CX,OFFSET TRANGROUP:TRANDATAEND - 100H
CHECK_SUM:
CLD
SHR CX,1
XOR DX,DX
CHK:
LODSW
ADD DX,AX
LOOP CHK
POP DS
RET10: RET
SETVECT: ; Set useful vectors
MOV DX,OFFSET RESGROUP:LODCOM
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set Terminate address
INT int_command
MOV DX,OFFSET RESGROUP:CONTC
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H ; Set Ctrl-C address
INT int_command
MOV DX,OFFSET RESGROUP:DSKERR
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H ; Set Hard Disk Error address
INT int_command
RET
CODERES ENDS
; This TAIL segment is used to produce a PARA aligned label in the resident
; group which is the location where the transient segments will be loaded
; initial.
TAIL SEGMENT PUBLIC PARA
ORG 0
TRANSTART LABEL WORD
TAIL ENDS
; This TAIL segment is used to produce a PARA aligned label in the transient
; group which is the location where the exec segments will be loaded
; initial.
TRANTAIL SEGMENT PUBLIC PARA
ORG 0
EXECSTART LABEL WORD
TRANTAIL ENDS
IF IBMVER
INCLUDE EXEC.ASM
ENDIF
END PROGSTART