*/
Are you blogging on PH? Get your free blog.
*/

View \CHAIN.ASM

Chain Facility for Turbo Pascal Version 5.0

Submitted By: WEBMASTER
Rating: starstarstarstarstar (Rate It)


;*******************************************************
;                    CHAIN.ASM 5.00
;        Copyright (c) TurboPower Software 1987.
;                 All rights reserved.
;*******************************************************

;Set the following define to 1 and reassemble CHAIN
;if you need to run under DOS 2.X
DOS2X = 0

DSEG    SEGMENT WORD PUBLIC

        EXTRN   CloseFilesBeforeChaining:BYTE   ;Variable in CHAIN.PAS
        EXTRN   PrefixSeg:WORD                  ;Variable in SYSTEM

DSEG    ENDS

CSEG    SEGMENT BYTE PUBLIC

        ASSUME  CS:CSEG,DS:DSEG

        PUBLIC  Chain4
        PUBLIC  SetIntVec
        EXTRN   RestoreVectors:NEAR             ;Routine to restore vectors

;The following values must be exact
;They'll need changing if anything after label CodeToRelocate changes
CodeLen        EQU     02Ch                     ;Bytes of code to relocate
MaxCmdLen      EQU     052h                     ;Maximum length of command line

;Although more reliable, the following generates several NOPs in object code
;CodeLen = offset Dummy-offset CodeToRelocate   ;Length of code in PSP
;MaxCmdLen = 07Eh-CodeLen                       ;Maximum length of command line

FirstHandle    EQU     5                       ;First file handle to close

;**************************************************************** SetIntVec
; procedure SetIntVec(Num : Byte; Vec : pointer);
;   set interrupt Num to point to Vec

SetIntVec PROC NEAR
        MOV     BX,SP                           ;Stack frame
        MOV     CX,DS                           ;Save DS
        MOV     AH,25h                          ;Set vector
        MOV     AL,SS:[BX+6]                    ;AL = Num
        LDS     DX,SS:[BX+2]                    ;DS:DX = Vec
        INT     21h
        MOV     DS,CX                           ;Restore DS
        RET     6
SetIntVec ENDP

;**************************************************************** Chain4
; function Chain4(Path, CmdLine : string) : word;
;   Turbo 4 equivalent of chaining

;Parameters
PathArg        EQU     DWORD PTR [BP+10]       ;File to chain to
CmdLine        EQU     DWORD PTR [BP+6]        ;Command line to pass

;Local variables
CsInit          EQU     WORD PTR [BP-30+16h]    ;Fields within EXE header
IpInit          EQU     WORD PTR [BP-30+14h]    ; ...
StackPtr        EQU     WORD PTR [BP-30+10h]
StackSeg        EQU     WORD PTR [BP-30+0Eh]
MinHeap        EQU     WORD PTR [BP-30+0Ah]
EXEPages        EQU     WORD PTR [BP-30+04h]
EXEHeader      EQU     WORD PTR [BP-30]        ;EXE header from file
Path            EQU     BYTE PTR [BP-94]        ;ASCIIZ path string

Chain4  PROC    FAR

        PUSH    BP
        MOV     BP,SP                           ;Set up stack frame
        SUB     SP,94                           ;Make space for locals

;Validate pathname and convert to ASCIIZ
        PUSH    DS                              ;Save DS for later
        PUSH    SS
        POP     ES                              ;ES = SS
        LEA     DI,Path                         ;ES:DI => ASCIIZ path
        MOV     BX,DI                           ;Save offset of ASCIIZ
        LDS     SI,PathArg                      ;DS:SI => file path in Turbo string
        ASSUME  DS:nothing
        CLD                                     ;Forward
        LODSB                                   ;Get length byte
        CMP     AL,63                           ;Longer than 63 characters?
        JB      StoreASCIIZ
        MOV     AL,63                           ;Truncate it
StoreASCIIZ:
        MOV     CL,AL                           ;CX = length
        XOR     CH,CH
        REP     MOVSB                           ;Copy to local Path
        XOR     AL,AL                           ;Make ASCIIZ
        STOSB

;Assure file exists
        PUSH    SS
        POP     DS                              ;DS = SS
        MOV     DX,BX                           ;DS:DX => ASCIIZ path
        MOV     AX,3D00h                        ;Open file read-only
        INT     21h
        JNC     FileFound                       ;OK, file was found

ErrorPOP     DS                              ;Restore DS
        ASSUME  DS:DSEG
Error1: MOV     SP,BP                           ;Return with error code in AX
        POP     BP                              ;Restore BP
        RET     8                               ;Remove parameters from stack

;Read file header
FileFound:
        MOV     BX,AX                           ;BX = file handle
        LEA     DX,ExeHeader                    ;DS:DX => ExeHeader
        MOV     CX,28                           ;Read 28 bytes
        MOV     AH,3Fh                          ;DOS read file
        INT     21h
        JC      Error                           ;Error if carry set
        CMP     AX,2                            ;At least 2 bytes read?
        MOV     AX,30                           ;Prepare for Read Fault error
        JB      Error                           ;Error if 2 bytes not read

;Determine how much memory program needs
        CMP     ExeHeader,5A4Dh                 ;Is it EXE format?
        JE      ExeFileSize                     ;Yes, treat it as such

;Get non-EXE file size
        MOV     AX,4202h                        ;Seek to end of file
        XOR     CX,CX
        XOR     DX,DX
        INT     21h
        JC      Error                           ;Error if carry set
        MOV     CX,4                            ;Divide bytes by 16
NextShiftR:
        SHR     DX,1                            ;Shift a LongInt right
        RCR     AX,1
        LOOP    NextShiftR
        JMP SHORT CloseFile                     ;DX:AX has paragraphs needed

;Get EXE image size
ExeFileSize:
        MOV     AX,EXEPages                     ;Get pages in EXE image
        XOR     DX,DX
        MOV     CX,5                            ;Multiply by 32
NextShiftL:
        SHL     AX,1                            ;Shift a LongInt left
        RCL     DX,1
        LOOP    NextShiftL                      ;DX:AX has paragraphs
        ADD     AX,MinHeap                      ;Add minimum data/stack/heap
        ADC     DX,0

;Close file (DOS will reopen it)
CloseFile:
        MOV     CX,AX                           ;Save paragraphs in CX
        MOV     AH,3Eh                          ;Close file
        INT     21h
        JC      Error                           ;Error if carry set

;See if more than 640K bytes requested
        MOV     AX,8                            ;Prepare for insufficient memory
        OR      DX,DX                           ;DX must be zero
        JNZ     Error                           ;Error if more than 640K

;Determine available memory space
        POP     DS                              ;Restore DS
        ASSUME  DS:DSEG
        MOV     ES,PrefixSeg                    ;Main program segment
        MOV     AH,4Ah                          ;Setblock

IF DOS2X                                        ;Runs under DOS 2.X or 3
        MOV     BX,CX
        ADD     BX,1000h
        INT     21h                             ;BX = Required space+64K bytes

ELSE                                            ;Runs only under DOS 3 or later
        MOV     BX,0FFFFh                       ;Ask for everything
        INT     21h                             ;BX has available paragraphs
;Assure sufficient memory available for overlay
        MOV     AX,BX
        SUB     AX,10h                          ;Leave space for PSP
        CMP     AX,CX                           ;Sufficient space?
        MOV     AX,8                            ;Prepare for insufficient memory
        JB      Error1                          ;Error if less
ENDIF

;Allocate all available space
        MOV     AH,4Ah                          ;Ask again for what we can get
        INT     21h
        JC      Error1                          ;Error if carry set now

;Prepare to move stack to top of memory
        MOV     AX,ES                           ;Base of program
        ADD     AX,BX                           ;Add all available paragraphs
        SUB     AX,1000h                        ;Room for full stack segment
        MOV     CS:TmpSS,AX                     ;Store temporary SS for later

;Close secondary file handles (don't touch StdIn,StdOut,StdErr,StdPrn)
        CMP     CloseFilesBeforeChaining,0      ;Should we close files?
        JZ      RestoreInts                     ;No, skip this
        MOV     BX,FirstHandle                  ;Start with handle 5
        MOV     CX,20-FirstHandle               ;20 handles total
NextHandle:
        MOV     AH,3Eh                          ;DOS close file
        INT     21h
        INC     BX                              ;Ignore errors
        LOOP    NextHandle

;Restore interrupt vectors taken over by SYSTEM library
RestoreInts:
        PUSH    ES
        CALL    RestoreVectors
        POP     ES

;Set up command line for chained program
        LDS     SI,CmdLine                      ;DS:SI points to command line
        MOV     DI,80h                          ;ES:DI => command line in PSP
        LODSB                                   ;Get length byte
        CMP     AL,MaxCmdLen                    ;Is is too long?
        JB      StoreCmdLine                    ;No, don't truncate
        MOV     AL,MaxCmdLen                    ;Truncate
StoreCmdLine:
        STOSB                                   ;Store length byte
        MOV     BX,DI                           ;Save start of command line
        MOV     CL,AL
        XOR     CH,CH
        REP     MOVSB                           ;Copy parameter to command line
        MOV     AL,0Dh                          ;Terminate with <Enter>
        STOSB

;Initialize FCB's for new program
        PUSH    ES
        POP     DS                              ;DS = ES
        MOV     SI,BX                           ;DS:SI => command line to parse
        MOV     DI,005Ch                        ;ES:DI => FCB1
        MOV     AX,2901h                        ;Init FCB1
        INT     21h
        MOV     DI,006Ch                        ;ES:DI => FCB2
        MOV     AX,2901h                        ;Init FCB2
        INT     21h

;Save initialization data for new program
        MOV     BX,ES                           ;Store prefix seg in BX
        MOV     CS:NewCS,BX                     ;Assume COM file
        MOV     CS:NewSS,BX
        ADD     BX,10h                          ;BX = base segment of image
        CMP     ExeHeader,5A4Dh                 ;Is it EXE format?
        JNE     MoveCode                        ;No, COM file already initialized
        MOV     AX,CsInit                       ;Get initial CS from EXE header,
        ADD     AX,BX                           ;   relocate segment,
        MOV     CS:NewCS,AX                     ;   save it for later
        MOV     AX,IpInit                       ;Initial IP
        MOV     CS:NewIP,AX
        MOV     AX,StackSeg                     ;Initial SS
        ADD     AX,BX
        MOV     CS:NewSS,AX
        MOV     AX,StackPtr                     ;Initial SP
        MOV     CS:NewSP,AX

;Move code into PSP
MoveCode:
        MOV     CX,CodeLen                      ;Bytes to move
        MOV     DI,100h                         ;DI => end of new code
        SUB     DI,CX                           ;ES:DI => destination of new code
        MOV     CS:TmpIP,DI                     ;Store address to jump to
        MOV     CS:TmpCS,ES
        PUSH    CS
        POP     DS                              ;DS = CS
        MOV     SI,offset CodeToRelocate        ;DS:SI => code to relocate
        REP     MOVSB                           ;Copy the code to PSP

;Prepare for EXEC call
        MOV     AX,BX                           ;AX = Base segment
        STOSW
        STOSW                                   ;Initialize EXEC block
        PUSH    SS
        POP     DS                              ;DS = SS
        LEA     DX,Path                         ;DS:DX => Path of file
        MOV     BX,100h                         ;ES:BX => EXEC block
        MOV     AX,4B03H                        ;Load Overlay
        CLI
        MOV     SS,CS:TmpSS                     ;Put stack at top
        MOV     SP,0FFFEh                       ;  of memory
        STI
        DB      0EAh                            ;JMP FAR to code in PSP
TmpIP   DW      0                               ;Patched in with offset
TmpCS   DW      0                               ;Patched in with segment
TmpSS   DW      0                               ;Temporary stack segment

;-----------------------------------------------------------------------------
;Code relocated to and executed in PSP
CodeToRelocate:
        INT     21h                             ;Call DOS EXEC
        JNC     GoodLoad                        ;Check for error
        INT     20h                             ;Error is rare
                                                ; just halt if EXEC failed
GoodLoad:
        MOV     DX,CS                           ;Get base of program
        MOV     DS,DX                           ;Initialize DS
        MOV     ES,DX                           ;Initialize ES
        MOV     AH,4Ah                          ;DOS SetBlock
        MOV     BX,0FFFFh                       ;Ask for everything
        INT     21h                             ;BX has available paragraphs
        ADD     BX,DX                           ;Top of memory
        MOV     DS:[0002h],BX                   ;Store in PSP that Turbo uses
        CLI                                     ;Interrupts off
        MOV     SS,DS:[0FEh]                    ;Initialize stack
        MOV     SP,DS:[0FCh]
        STI                                     ;Interrupts on again
        DB      0EAh                            ;JMP FAR to start of code
NewIP   DW      100h                            ;Patched in with start offset
NewCS   DW      0                               ;Patched in with start segment
NewSP   DW      0FFFEh                          ;Patched in with new SP
NewSS   DW      0                               ;Patched in with new SS

Chain4  ENDP

Dummy   LABEL   BYTE                            ;Used to measure code to move

CSEG    ENDS

        END

corner
© 1996-2008 CommunityHeaven LLC. All rights reserved. Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
North American business development: Nicolai Wadstrom. Publisher: Lars Hagelin.