TITLE C - Initiate execution of a Lattice C program SUBTTL Copyright 1982 by Lattice, Inc. NAME C INCLUDE DOS.MAC ; ; MASM doesnt like these things. NOP them all. ; .8087 ; FNINIT equ NOP ; ; FNSTSW macro arg ; or arg,0ffffh ; endm ; ;** ; ; name C -- initiate execution of C program ; ; description This is the main module for a C program on the ; MS-DOS implementation. It initializes the segment ; registers, sets up the stack, and calls the C main ; function _main with a pointer to the remainder of ; the command line. ; ; Also defined in this module: the exit entry point ; XCEXIT, and the stack overflow entry XCOVF. ; ;** IF S8086 PGROUP GROUP BASE,PROG,TAIL BASE SEGMENT WORD PUBLIC 'PROG' DW 0 BASE ENDS ENDIF IF P8086 BASE SEGMENT WORD DW 1 BASE ENDS ENDIF IF D8086 CGROUP GROUP BASE,CODE BASE SEGMENT WORD PUBLIC 'CODE' DW 2 BASE ENDS ENDIF IF L8086 BASE SEGMENT WORD DW 3 BASE ENDS ENDIF IF LPROG EXTRN _MAIN:FAR EXTRN RBRK:FAR ECODE EQU 4 ;offset of error code for XCEXIT ELSE ECODE EQU 2 ;offset of error code for XCEXIT ENDIF DGROUP GROUP DATA,STACK ; ; The data segment defines locations which contain the offsets ; of the base and top of the stack. ; DATA SEGMENT PARA PUBLIC 'DATA' EXTRN _STACK:WORD PUBLIC _VER,_TOP,_BASE,_INAME,_ONAME,_PSP,_MBASE,_MNEXT,_MSIZE PUBLIC _ENV,_DOS,_TSIZE,_ESIZE,_SS,_SP,_NDP,_NDPSW,_NDPCW PUBLIC _FPA,_FPERR,_OSERR NULL DW 0 _VER DB "Lattice C 2.1" _DOS DB 0 ; DOS major version number DB 0 ; DOS minor version number _SS DW 0 ; stack segment number _SP DW 0 ; SP reset value _TOP DW 0 ; top of stack (relative to SS) _BASE DW OFFSET DGROUP:SBASE ; base of stack (relative to DS) _INAME DB 32 DUP(0) ; input file name _ONAME DB 32 DUP(0) ; output file name _PSP DW 0 ; program segment prefix pointer DW 0 _MBASE DW 0 ; base of memory pool DW 0 _MNEXT DW 0 ; next available memory location DW 0 _MSIZE DW 0 ; number of bytes left in pool DW 0 _TSIZE DW 0 ; total size in paragraphs _ENV DW 0 ; pointer to environment DW 0 _ESIZE DW 0 ; environment size in bytes _FPA DQ 0 ; floating point accumulator _FPERR DW 0 ; floating point error code _NDP DB 0 ; non-zero if 8087 is installed _NDPSW DW 0FFFFH ; 8087 status word _NDPCW DW 0 ; 8087 control word _OSERR DW 0 ; DOS error code STKERR DB "Fido: Bad stack size",0DH,0AH,"$" NAMERR DB "Fido: Bad redirection",0DH,0AH,"$" MEMERR DB "Fido: Not Enough memory",0DH,0AH,"$" OVFERR DB "Fido: *** STACK OVERFLOW ***",0DH,0AH,"$" DATA ENDS ; ; The stack segment is included to prevent the warning from the ; linker, and also to define the base (lowest address) of the stack. ; STKRSV EQU 128 ; reserved stack size STKMIN EQU 512 ; minimum run-time stack size IF COM STACK SEGMENT 'DATA' ELSE STACK SEGMENT STACK 'DATA' ENDIF SBASE DB STKRSV DUP (?) STACK ENDS TAB EQU 09H ; tab character ; ; The main program must set up the initial segment registers ; and the stack pointer, and set up a far return to the MS-DOS ; exit point at ES:0. The command line bytes from the program ; segment prefix are moved onto the stack, and a pointer to ; them supplied to the C main module _main (which calls main). ; IF S8086 PROG SEGMENT BYTE PUBLIC 'PROG' ASSUME CS:PGROUP ENDIF IF D8086 CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:CGROUP ENDIF IF P8086 _CODE SEGMENT BYTE ASSUME CS:_CODE ENDIF IF L8086 _PROG SEGMENT BYTE ASSUME CS:_PROG ENDIF ASSUME DS:DGROUP IF LPROG EQ 0 EXTRN _MAIN:NEAR EXTRN RBRK:NEAR ENDIF IF COM ORG 0FEH ENDIF C PROC FAR jmp c_over ; ;Ptel specific stuff: Serial number and the patchable ;variables. ; serno dd 0 ;0 means unserialized (checked for) db 'Copyright Tom Jennings 1990, 1989, 1988, 1987, 1986, 1985, 1984',32 db 'Fido Software',32 db 'Box 77731',32 db 'San Francisco CA 94107, USA',32 db 'Fido and FidoNet are registered U.S. trademarks of Tom Jennings',32 db 7,26 ; ;Return the serial number. ; ;n= getserno() ;long n; ; public getserno getserno proc near push bp mov bp,sp mov bx,word ptr cs:serno mov ax,word ptr cs:serno + 2 pop bp ret getserno endp ; ;Return an int from the specified offset from CS. ; public getatcs getatcs proc near push bp mov bp,sp mov bx,[bp + 4] mov ax,cs:[bx] pop bp ret getatcs endp ; ;title Program Identification Block ;name ident ; ; A unique pattern of bytes to be ;placed in the code segment of a program to ;identify it as being written by me. ; ; T. Jennings 20 May 85 ; ; This is actually the first 100 or so bytes ;from the start of the Otrona Attache Z80 BIOS ;from one of the intermediate test versions. It ;is the version of MSDOS that I use. ; db 00h,00h,00h,00h,0F3h,031h,00h,00h,078h,032h,00h,001h,07Bh,032h,001h,001h db 07Ah,032h,002h,001h,079h,032h,003h,001h,0CDh,0CBh,01Ch,0CDh,04Ah,002h,0CDh,087h db 00Ah,021h,06Dh,001h,0CDh,0F9h,00Bh,006h,0FAh,00Eh,00h,0CDh,083h,01Ch,0C2h,042h db 001h,00Dh,0C2h,02Bh,001h,005h,0C2h,02Bh,001h,021h,077h,001h,0CDh,0F9h,00Bh,0C3h db 03Fh,001h,0CDh,089h,01Ch,0FEh,0F0h,0C2h,02Bh,001h,0CDh,0CEh,001h,0D2h,059h,001h db 021h,0A3h,001h,0CDh,0F9h,00Bh,0C3h,056h,001h,03Eh,051h,0CDh,0ACh,00Bh,0CDh,0DEh ; db 00Ch,0CDh,0AAh,003h,021h,0B4h,001h,0CDh,0F9h,00Bh,0C3h,06Ah,001h,057h,061h,069h ; ;Shortened 27 Apr 87 cuz Im out of CSEG ... ; ; ;Start of normal C code. ; c_over: CLI IF COM MOV AX,OFFSET PGROUP:TAIL ; set up DS/SS for .COM file ADD AX,16 MOV CL,4 SHR AX,CL MOV BX,CS ADD AX,BX MOV DS,AX MOV SS,AX MOV SP,OFFSET DGROUP:SBASE+STKRSV ELSE MOV AX,DGROUP ; set up DS/SS for .EXE file MOV DS,AX MOV AX,STACK MOV SS,AX MOV SP,STKRSV ENDIF STI MOV AH,30H ; get DOS version number INT 21H OR AL,AL JNZ M0 MOV AX,1 ; assume 1.00 if null return M0: MOV WORD PTR _DOS,AX MOV _PSP+2,ES ; set up pointer to prog seg prefix ; ; Examine the environment string area ; CMP _DOS,2 JL M01 MOV AX,ES:[2CH] MOV _ENV+2,AX ; set up pointer to environment OR AX,AX JZ M01 ; branch if null PUSH ES ; determine number of bytes CLD LES DI,DWORD PTR _ENV XOR AX,AX MOV CX,7FFFH M0A: REPNZ SCASB JNZ M0B SCASB JNZ M0A INC DI AND DI,0FFFEH MOV _ESIZE,DI M0B: POP ES ; ; Examine command line ; M01: MOV SI,80H ; check command line MOV CL,ES:[SI] XOR CH,CH JCXZ M12 ; branch if null M1: INC SI ; scan for first arg MOV AL,ES:[SI] CMP _DOS,2 JGE M10 CMP AL,'<' JE M2 ; branch if input file name CMP AL,'>' JE M3 ; branch if output file name M10: CMP AL,'=' JE M4 ; branch if stack size CMP AL,' ' JE M11 ; branch if white space CMP AL,TAB JNE M12 ; branch if normal arg M11: DEC CX JG M1 XOR CX,CX M12: JMP M5 ; branch if no args found ; ; Get input file name ; M2: MOV DI,OFFSET DGROUP:_INAME JMP M31 ; ; Get output file name ; M3: MOV DI,OFFSET DGROUP:_ONAME ; ; Save file name in data area ; M31: XOR AH,AH M32: DEC CX JZ M33 INC SI MOV AL,ES:[SI] CMP AL,' ' JZ M33 CMP AL,TAB JZ M33 MOV DS:[DI],AL INC DI INC AH CMP AH,32 JE M34 JMP M32 M33: MOV BYTE PTR DS:[DI],0 JMP M11 M34: MOV DX,OFFSET DGROUP:NAMERR JMP NEAR PTR XCABT ; ; Get stack size from command line ; M4: XOR BX,BX ; get stack size arg M41: DEC CX JZ M42 INC SI MOV AL,ES:[SI] CMP AL,' ' JE M42 CMP AL,TAB JE M42 SUB AL,'0' JL M43 CMP AL,9 JG M43 ADD BX,BX JC M43 MOV DX,BX ADD BX,BX JC M43 ADD BX,BX JC M43 ADD BX,DX JC M43 XOR AH,AH ADD BX,AX JC M43 JMP M41 M42: OR BX,BX JZ M43 ; branch if stack size arg is null MOV _STACK,BX JMP M11 M43: MOV DX,OFFSET DGROUP:STKERR JMP NEAR PTR XCABT ; ; Set up the stack ; IF LDATA EQ 0 M5: MOV AX,_ESIZE ; reserve space for environment ELSE M5: XOR AX,AX ENDIF MOV BX,_STACK ; get stack size SHR BX,1 ; make size even ADD BX,BX CMP BX,STKMIN JA M51 MOV BX,STKMIN ; use default if too small MOV _STACK,BX M51: ADD BX,AX ; add environment size JC M54 ; abort if overflow MOV DX,ES:2 ; compute available paragraphs MOV AX,SS SUB DX,AX TEST DX,0F000H JNZ M52 ; branch if greater than 64Kbytes SHL DX,1 ; convert to bytes SHL DX,1 SHL DX,1 SHL DX,1 JMP M53 M52: MOV DX,0FFF0H ; use largest value IF LDATA M53: CMP DX,BX ; check if stack will fit JA M55 ELSE M53: CMP DX,BX ; check if stack will fit JB M54 ADD BX,_BASE ; adjust S/P model for statics JNC M55 ENDIF M54: MOV DX,OFFSET DGROUP:MEMERR ; abort if insufficient memory JMP NEAR PTR XCABT M55: CLI MOV _TOP,BX ; set top-of-stack MOV SP,BX ; set stack pointer IF LDATA EQ 0 MOV AX,DS MOV SS,AX ENDIF MOV _SS,SS STI ; ;Fill the stack with AE's so we can later measure stack usage. (Which is ;done by finding the first non-AE byte from _BASE; stack used = _STACK ; - (distance from _BASE)) ; push cx push di push es mov di,_BASE ;DI= stack base pointer mov cx,_STACK ;CX= stack size mov ax,ss mov es,ax ;ES:DI= stack base mov al,0aeh ;AL= data pattern cld ;direction= up rep stosb ;stuff it pop es pop di pop cx ; ; Set up memory allocation pointers ; PUSH CX ; save command byte count ADD BX,15 ; compute mem pool base segment number MOV CL,4 SHR BX,CL MOV AX,SS ADD AX,BX MOV _MBASE+2,AX MOV _MNEXT+2,AX MOV BX,ES:2 ; get top segment number SUB BX,AX ; compute memory pool size JBE M54 ; branch if insufficient memory MOV CL,4 ; compute number of bytes ROL BX,CL MOV AX,BX AND AX,15 AND BX,0FFF0H MOV _MSIZE,BX MOV _MSIZE+2,AX CALL RBRK ; reset memory pool OR AX,AX JNZ M54 POP DX ; restore command line length ; ; Put return address at top of stack ; PUSH ES ; return is to 1st word of prog prefix XOR AX,AX PUSH AX MOV BP,SP ; BP contains stack linkage ; ; Move environment to stack for small data models ; IF LDATA EQ 0 LES DI,DWORD PTR _ENV MOV DI,_ESIZE M6: SUB DI,2 JL M61 PUSH ES:[DI] JMP M6 M61: MOV ES,_PSP+2 MOV _ENV,SP MOV _ENV+2,SS ENDIF ; ; copy command line to stack ; MOV BX,DX ; get residual command line length MOV CX,DX ADD BX,4 ;3 bytes additional, 1 for rounding AND BX,0FFFEH ;force even number of bytes SUB SP,BX ;allocate space on stack MOV DI,SP MOV BYTE PTR SS:[DI],'c' ;store dummy program name INC DI JCXZ M8 ;skip if no bytes to move MOV BYTE PTR SS:[DI],' ' INC DI M7: MOV AL,ES:[SI] ;move bytes to stack MOV SS:[DI],AL INC SI INC DI LOOP M7 M8: MOV BYTE PTR SS:[DI],0 ; append null byte ; ; initialize 8087 numeric data processor ; ; FNINIT ; reset ; FNSTSW _NDPSW ; get status ; MOV AX,100 ; this is just for delay ; MOV DX,AX ; IMUL DX ; TEST _NDPSW,0B8BFH ; 8087 will reset all these ; JNZ M81 ; INC _NDP ; indicate ndp present ; ; set up args for _main and call it ; M81: MOV _SP,SP ; save stack pointer reset value MOV AX,SP ; push pointer to command line IF LDATA PUSH SS ENDIF PUSH AX PUSH DS ; make ES same as DS POP ES CALL _MAIN ; call C main CMP _DOS,2 JL M9 ; branch if DOS 1 MOV AX,4C00H ; exit with return code of 0 INT 21H M9: MOV SP,BP ;restore ptr to far return RET ;return to MS-DOS ;** ; ; name XCABT -- Ignominious abort ; ; description This area is entered by direct jump with a message ; pointer in DS:DX. It sends the message to the ; console via DOS function 9 and then aborts. ; ENTRY XCABT MOV AH,9 ; print error message INT 21H MOV ES,_PSP+2 CMP _DOS,2 JL A1 MOV AX,4C01H INT 21H A1: PUSH ES XOR AX,AX PUSH AX RET ;** ; ; name XCOVF -- terminate execution after stack overflow ; ; description This entry point is reached from a C module when its ; entry sequence detects a stack overflow. Control is ; passed to XCOVF by a direct jump. ; ;** ENTRY XCOVF MOV AX,_TOP SUB AX,4 MOV SP,AX ; RESET STACK POINTER MOV DX,OFFSET DGROUP:OVFERR MOV AH,9 INT 21H ; GENERATE ERROR MESSAGE CMP _DOS,2 JL OVF1 MOV AX,4C01H INT 21H ; EXIT WITH ERROR CODE OVF1: RET ; RETURN TO MS-DOS ;** ; ; name XCEXIT -- terminate execution of C program ; ; description This function terminates execution of the current ; program by returning to MS-DOS. The error code ; argument normally supplied to XCEXIT is ignored ; in this implementation. ; ;** ENTRY XCEXIT CMP _DOS,2 JL EXIT1 MOV BP,SP MOV AX,[BP+ECODE] ; GET ERROR CODE MOV AH,4CH INT 21H ; EXIT EXIT1: MOV AX,_TOP SUB AX,4 MOV SP,AX RET C ENDP ;** ; ; Dummy segment to establish top of program for small program models ; IF S8086 TAIL SEGMENT WORD 'PROG' DW -1 TAIL ENDS ENDIF ENDPS END C