4 ;*****************************************************************************
5 ; Loader for EXE files under 86-DOS
7 ; 05/21/82 Added rev number
9 ; 07/01/82 A little less choosy about size matches
11 ; 10/08/82 Modified to use new 2.0 system calls for file i/o
13 ; 10/27/82 Added the DOS version check
15 ; 8/30/83 Fixed command line parsing
17 ; 10-12-83 More fixes to command line parsing
19 ; 10/17/83 Use Printf for messages
20 ; Ver 2.5 MZ Fix LOCATE sss D: problem
21 ; 04/09/87 Add PARSER and MESSAGE RETRIEVER
23 ;*****************************************************************************
27 MSG_UTILNAME
<EXE2BIN
> ;AN000;
29 subttl Main
Code Area
;AN000;
33 ; The following switch allows use with the "old linker", which put a version
34 ; number where the new linker puts the number of bytes used in the last page.
35 ; If enabled, this will cause a test for 0004 at this location (the old linker
36 ; version number), and if equal, change it to 200H so all of the last page
39 OLDLINK EQU
0 ;1 to enable, 0 to disable
41 CODE SEGMENT PARA
PUBLIC 'CODE' ;AN000;
43 DATA SEGMENT PARA
PUBLIC 'DATA' ;AN000;
45 STACK SEGMENT PARA
PUBLIC 'STACK' ;AN000;
47 ZLOAD
SEGMENT PARA
PUBLIC 'ZLOAD' ;AN000;
50 DATA SEGMENT PARA
PUBLIC 'DATA' ;AN000;
52 MSG_SERVICES
<MSGDATA
> ;AN000;
54 Command_Line_Buffer db 128 dup(0) ;AN000;
55 Command_Line_Length equ
$ - Command_Line_Buffer
;AN000;
57 Fatal_Error db 0 ;AN000;
66 file1_ext db ".EXE",00h
67 file2_ext db ".BIN",00h
74 noupdate equ
-1 ;AN000;
76 file1 db (64+13) dup(?
)
77 fnptr dw offset file1
; Ptr to filename in file1
80 file2 db (64+13) dup(?
)
81 f2cspot dw offset file2
; Ptr to spot in file2, file1 maybe added
84 dma_buf db 80h
dup(0) ; DMA transfer buffer
89 ;The following locations must be defined for storing the header:
91 RUNVAR
LABEL BYTE ;Start of RUN variables
95 SIZ
LABEL WORD ;Share these locations
107 RUNVARSIZ EQU
$-RUNVAR
109 DBCS_Vector_Off dw 0 ;AN000;
110 DBCS_Vector_Seg dw 0 ;AN000;
117 STACK SEGMENT PARA
PUBLIC 'STACK'
118 DB (362 - 80h
) + 80H
DUP (?
) ; (362 - 80h) is IBMs ROM requirement
119 ; (New - Old) == size of growth
125 ZLOAD
SEGMENT PARA
PUBLIC 'ZLOAD'
134 ;*****************************************************************************
136 ;*****************************************************************************
140 INCLUDE DOSSYM
.INC ; also versiona.inc ;AN000;
141 INCLUDE SYSCALL.INC ;AN000;
142 INCLUDE E2BMACRO
.INC ;AN000;
143 INCLUDE E2BEQU
.INC ;AN000;
144 INCLUDE E2BTABLE
.INC ;AN000;
145 INCLUDE E2BPARSE
.INC ;AN000;
151 CODE SEGMENT PARA
PUBLIC 'CODE'
152 assume
cs:CODE,ds:DATA,es:NOTHING
,SS:STACK ;AN000;
154 psp_ptr dw 1 dup(?
) ;AN000;
156 ;*****************************************************************************
157 ; SysDisplayMsg Declarations
158 ;*****************************************************************************
161 MSG_SERVICES
<LOADmsg
> ;AN000;
162 MSG_SERVICES
<DISPLAYmsg
,CHARmsg
> ;AN000;
163 MSG_SERVICES
<EXE2BIN
.CLA
,EXE2BIN
.CLB
> ;AN000;
164 MSG_SERVICES
<EXE2BIN
.CL1
,EXE2BIN
.CL2
> ;AN000;
165 MSG_SERVICES
<EXE2BIN
.CTL
> ;AN000;
171 ;*****************************************************************************
172 ; External Routine Declarations
173 ;*****************************************************************************
176 public SysDispMsg
;AN000;
177 public SysLoadMsg
;AN000;
180 ;*****************************************************************************
181 ;Routine name: Main_Init
182 ;*****************************************************************************
184 ;Description: Main control routine for init section
186 ;Called Procedures: Message (macro)
189 ; Validate_Target_Drive
196 ;Change History: Created 6/22/87 DM
198 ;*****************************************************************************
200 procedure Main_Init
near ; ;AN000;
202 ASSUME
DS:NOTHING
; THIS IS WHAT dos GIVES YOU ;AN000;
203 ASSUME
ES:NOTHING
;AN000;
206 mov psp_ptr
,ds ;AN000;
208 PUSH AX ;Push return address to DS:0 ;AN000;
210 MOV AX,SEG
DATA ;SET UP ADDRESSABILITY TO ;AN000;
211 MOV DS,AX ; THE DATA SEGMENT ;AN000;
212 ASSUME
DS:DATA ;TELL ASSEMBLER WHAT I JUST DID ;AN000;
214 mov Fatal_Error
,No
;Init the error flag ;AN000;
215 call Init_Input_Output
;Setup messages and parse ;AN000;
216 cmp Fatal_Error
,Yes
;Error occur? ;AN000;
217 ; $IF NE ;Nope, keep going ;AN000;
219 call LOCATE
;Go do the real program ;AN000;
223 Dos_call Exit
;AN000;
224 int 20h
;If other exit fails ;AN000;
226 Main_Init endp
;AN000;
228 ;*****************************************************************************
229 ;Routine name: Init_Input_Output
230 ;*****************************************************************************
232 ;Description: Initialize messages, Parse command line, allocate memory as
233 ; needed. If there is a /FS switch, go handle it first as
234 ; syntax of IFS format may be different from FAT format.
236 ;Called Procedures: Preload_Messages
237 ; Parse_For_FS_Switch
241 ;Change History: Created 6/22/87 DM
243 ;Input: PSP command line at 81h and length at 80h
246 ;Output: Fatal_Error = YES/NO
248 ;*****************************************************************************
250 procedure Init_Input_Output
near ;AN000;
252 call Preload_Messages
;Load up message retriever ;AN000;
253 cmp Fatal_Error
,YES
;Quit? ;AN000;
254 ; $IF NE ;Nope, keep going ;AN000;
256 call Parse_Command_Line
;Parse in command line input ;AN000;
261 Init_Input_Output endp
;AN000;
263 ;*****************************************************************************
264 ;Routine name: Preload_Messages
265 ;*****************************************************************************
267 ;Description: Preload messages using common message retriever routines.
269 ;Called Procedures: SysLoadMsg
272 ;Change History: Created 6/22/87 DM
274 ;Input: Fatal_Error = NO
276 ;Output: Fatal_Error = YES/NO
278 ;*****************************************************************************
280 procedure Preload_Messages
near ;AN000;
282 call SYSLOADMSG
;Preload the messages ;AN000;
283 ; $IF C ;Error? ;AN000;
285 call SYSDISPMSG
;AN000;
286 mov fatal_error
, YES
;AN000;
290 Preload_Messages endp
;AN000;
293 ;*****************************************************************************
294 ;Routine name: Parse_Command_Line
295 ;*****************************************************************************
297 ;Description: Parses command line.
299 ;Called Procedures: Message (macro)
302 ;Change History: Created 6/22/87 DM
304 ;Input: Fatal_Error = NO
306 ;Output: Fatal_Error = YES/NO
308 ;*****************************************************************************
311 Procedure Parse_Command_Line
;AN000;
314 mov ds,psp_ptr
;AN000;
315 ASSUME
DS:NOTHING
;AN000;
316 mov si,Command_Line_Parms
;AN000;
317 mov ax,seg command_line_table
;AN000;
320 ASSUME
ES:NOTHING
;AN000;
321 mov di,offset Command_Line_Table
;AN000;
328 call Sysparse
;AN000;
329 cmp ax,No_Error
;AN000;
346 mov ax,seg rb_string1_off
;AN000;
348 ASSUME
DS:NOTHING
;AN000;
349 mov si,offset rb_string1_off
;AN000;
350 mov ax,ds:[si] ;AN000;
354 mov ax,ds:[si+2] ;AN000;
356 ASSUME
DS:NOTHING
;AN000;
359 mov ax,seg file1
;AN000;
361 ASSUME
ES:NOTHING
;AN000;
362 mov di,offset file1
;AN000;
369 mov ax,seg rb_string2_off
;AN000;
371 ASSUME
DS:NOTHING
;AN000;
372 mov si,offset rb_string2_off
;AN000;
373 mov ax,ds:[si] ;AN000;
377 mov ax,ds:[si+2] ;AN000;
379 ASSUME
DS:NOTHING
;AN000;
382 mov ax,seg file2
;AN000;
384 ASSUME
ES:NOTHING
;AN000;
385 mov di,offset file2
;AN000;
394 ASSUME
ES:NOTHING
;AN000;
396 ASSUME
DS:NOTHING
;AN000;
403 cmp ax,No_Error
;AN000;
408 cmp ax,End_of_Parse
;Check for parse error ;AN000;
412 mov ax,es:parse_ptr
;AN001;
413 mov es:parsoff
,ax ;AN001;
414 mov es:parseg
,ds ;AN001;
415 mov byte ptr ds:[si],0 ;AN001;
417 parse_message
;Must enter file name ;AN000;
418 mov es:Fatal_Error
,YES
;Indicate death! ;AN000;
423 ASSUME
ES:NOTHING
;AN000;
425 ASSUME
DS:DATA ;AN000;
429 Parse_Command_Line endp
;AN000;
431 ;*****************************************************************************
435 ;*****************************************************************************
438 procedure LOCATE
near
441 ASSUME
ES:NOTHING
; THIS IS THE WAY IT GETS HERE! ;AN000;
442 mov ax,es ; ES -> PSP ;AN000;
443 mov ds,ax ; DS -> PSP ;AN000;
444 ASSUME
DS:NOTHING
;AN000;
449 assume
es:data ;AN000;
451 MOV BX,WORD PTR DS:[2] ;Get size of memory
454 ;-----------------------------------------------------------------------;
457 ; The rules for the arguments are:
459 ; If no extention is present, .EXE is used.
461 ; If no drive is present in file2, use the one from file1
462 ; If no path is specified, then use current dir
463 ; If no filename is specified, use the filename from file1
464 ; If no extention is present in file2, .BIN is used
468 ;----- Get the first file name
471 ASSUME
ES:DATA ;AN000;
473 ASSUME
DS:DATA ;AN000;
476 mov si,offset file1
; d = file1;
477 mov per11
,0 ; assume no extension on file1;AC000;
479 ;******************************************************************************
482 lodsb ; while (!IsBlank(c=*p++)) {
485 call dbcs_check
; see if a dbcs character ;AN000;
486 jc dbcs_1
; dbcs character, go load another char ;AN000;
487 cmp al,'\' ; if (c == '\\' || c == ':') {
489 mov per11,update ;AC000;
490 mov fnptr,si ; fnptr = ptr to slash
492 cmp al,':' ; if (c == '\\' || c == ':') {
494 mov per11,update ;AC000;
495 mov fnptr,si ; fnptr = ptr to slash
497 cmp al,'.' ; if (c == '.')
499 mov per11,noupdate ; set file1 to have extension ;AN000;
522 lodsb ; load another character and got to ;AN000;
523 jmp short sj0 ; the start again. ;AN000;
525 ;******************************************************************************
529 ;----- Get the second file name
531 mov di,offset file2 ; d = file2
533 ;******************************************************************************
536 cmp word ptr [di],00 ; check to see if first character of
537 je sj32 ; file2 is a null. ;AN000;
538 mov si,offset file2 ; set pointer to file2
540 ;******************************************************************************
543 lodsb ; If file2 first character is not a
545 cmp al,0 ; null, this loop will check to see
546 JZ maycopy ; the file has an extension assigned;AN000;
547 call dbcs_check ; to it. If not it will set per2 to ;AN000;
548 jc dbcs_2 ; go load another byte ;AN000;
549 mov per22,noupdate ; ;AN000;
550 cmp al,'\' ; 0 so that in check_ext, the .BIN
551 jnz checkper6
; will be added to the filename.
552 mov per2
,update
; ;AC000;
553 mov per22
,update
; ;AN000;
555 cmp al,':' ; if (c == '\\' || c == ':') {
557 mov per22
,update
; ;AN000;
558 checkper4: ; there is an extension already.
561 mov per2
,noupdate
; ;AC000;
585 lodsb ;load another character and got to ;AN000;
586 jmp short sj31
;the start again. ;AN000;
588 ;******************************************************************************
590 maycopy: ; Check to see if the ;AN000;
591 cmp per22
,noupdate
; Last thing copied was either a ;AN000;
592 je SJ5
; driver letter or "\". ;AN000;
594 mov di,f2cspot
;AN000;
597 ; There is no second filename so
599 mov per2
,update
; set per2 to 0 to get default .BIN ;AN000;
600 ; extension in check_ext.
602 ;******************************************************************************
605 lodsb ; This loop is executed when there is ;AN000;
606 cmp al,0 ; no file2 specified on the command ;AN000;
607 JZ SJ5
; line. It will copy the file1 name ;AN000;
608 call dbcs_check
; check for dbcs character ;AN000;
609 jc dbcs_3
; got a dbcs character, go copy. ;AN000;
610 cmp al,'.' ; extension. The defult extension ;AN000;
611 je sj5
; of .BIN will be added in check_ext. ;AN000;
613 jmp short copy1to2
;AN000;
615 stosb ; Got a dbcs character. Copy ;AN000;
616 lodsb ; two characters and then go to ;AN000;
617 stosb ; next character in filename. ;AN000;
618 jmp short copy1to2
;AN000; ;AN000;
620 ;******************************************************************************
623 ; mov byte ptr es:[di],00h ; *d = 0;
624 mov ah,Set_DMA
; Use find_first to see if file2 is
625 mov dx,offset dma_buf
; a directory. If it isn't, go to
626 int 21h
; set f2cspot to point to the spot
627 mov ah,Find_First
; right after the backslash, and
628 mov dx,offset file2
; fall through to no_second so that
629 mov cx,-1 ; file1's name will be added to file2.
632 test dma_buf
+21,00010000b
641 mov per22,update ;AN000;
647 ;----- Check that files have an extension, otherwise set default
649 cmp per11,noupdate ; if (per1 == NULL) { ;AC000;
651 mov di,offset file1 ; d = file1;
652 mov si,offset file1_ext ; s = ".EXE";
653 call strcat ; strcat (d, s);
655 cmp per2,noupdate ; if (per2 != NULL) { ;AC000;
657 mov di,offset file2 ; d = file2;
658 mov si,offset file2_ext ; s = ".BIN";
659 call strcat ; strcap (d, s);
660 jmp short file2_ok ; }
662 ;-----------------------------------------------------------------------;
665 mov ax,(open SHL 8) + 0 ;for reading only
666 INT 21H ;Open input file
676 ASSUME DS:nothing ;AN000;
677 MESSAGE msgNoConvert ;AC000;
684 ASSUME DS:DATA ;AN000;
685 MOV DX,OFFSET RUNVAR ;Read header in here
686 MOV CX,RUNVARSIZ ;Amount of header info we need
690 INT 21H ;Read in header
693 CMP [RELPT],5A4DH ;Check signature word
695 MOV AX,[HEADSIZ] ;size of header in paragraphs
696 ADD AX,31 ;Round up first
697 CMP AX,1000H ;Must not be >=64K
701 SHL AX,CL ;Header size in bytes
720 SHR AX,1 ;Convert to pages
721 MOV DX,[PAGES] ;Total size of file in 512-byte pages
722 SUB DX,AX ;Size of program in pages
723 CMP DX,80H ;Fit in 64K? (128 * 512 = 64k)
726 SHL DX,1 ;Convert pages to bytes
727 MOV AX,[LASTP] ;Get count of bytes in last page
728 OR AX,AX ;If zero, use all of last page
732 CMP AX,4 ;Produced by old linker?
733 JZ WHOLEP ;If so, use all of last page too
736 SUB DX,200H ;Subtract last page
737 ADD DX,AX ;Add in byte count for last page
741 SHR DX,CL ;Convert bytes to paragraphs
743 ADD DX,BP ;Size + start = minimum memory (paragr.)
744 CMP DX,BX ;Enough memory?
753 ASSUME DS:NOTHING ;AN000;
754 MESSAGE msgOutOfMemory ;AN000;
762 ASSUME DS:DATA ;AN000;
764 JMP BADEXE ;AC000; For ptm P475;
766 OR AX,AX ;If IP=0, do binary fix
768 CMP AX,100H ;COM file must be set up for CS:100
775 mov dx,100h ;chop off first 100h
777 mov al,1 ;seek from current position
787 SUB [SIZ],AX ;And count decreased size
788 CMP [RELCNT],0 ;Must have no fixups
791 XOR BX,BX ;Initialize fixup segment
792 ;See if segment fixups needed
797 ASSUME DS:NOTHING ;AN000;
798 MESSAGE msgFixUp ;AN000;
802 ASSUME DS:DATA ;AN000;
803 MOV AH,STD_CON_STRING_INPUT
805 INT 21H ;Get user response
806 MOV SI,OFFSET INBUF+2
807 ;;dcl;; MOV BYTE PTR [SI-1],0 ;Any digits?
808 cmp BYTE PTR [SI-1],0 ;Any digits? ;AC000;
816 AND AL,5FH ;Convert to upper case
831 CMP BYTE PTR [SI-1],0DH ;Is last char. a CR?
834 XCHG BX,BP ;BX has LOAD, BP has fixup
842 ASSUME DS:NOTHING ;AN000;
846 INT 21H ;Read in up to 64K
849 ASSUME DS:DATA ;AN000;
851 Jnc HAVEXE ;Did we get it all?
859 ASSUME DS:DATA ;AN000;
860 CMP [RELCNT],0 ;Any fixups to do?
862 MOV AX,[RELTAB] ;Get position of table
880 MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
882 MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
887 INT 21H ;Read in one relocation pointer
892 MOV DI,[RELPT] ;Get offset of relocation pointer
893 MOV AX,[RELSEG] ;Get segment
894 ADD AX,BX ;Bias segment with actual load segment
896 ASSUME ES:NOTHING ;AN000;
897 ADD ES:[DI],BP ;Relocate
898 DEC [RELCNT] ;Count off
913 ASSUME DS:NOTHING ;AN000;
914 XOR DX,DX ;Address 0 in segment
920 ASSUME DS:DATA ;AN000;
922 Jc WRTERR ;Must be zero if more to come
933 ASSUME DS:NOTHING ;AN000;
937 ;*******************************************************************************
940 ASSUME DS:DATA ;AN000;
941 MOV AH,CLOSE ; Close the file here ;AN000;
943 mov bx,[handle2] ; ;AN000;
945 jc CloseError ; If error let extend messages get it;AN000;
947 mov ah,UNLINK ; Delete the file because it did ;AN000;
948 MOV DX,OFFSET file2 ; not get written correctly. ;AN000;
950 jc CloseError ; If error let extend messages get it;AN000;
952 ASSUME DS:NOTHING ; ;AN000;
953 message msgNoDiskSpace ; Put out insufficient disk space ;AN000;
954 jmp getout ; message ;AN000;
955 RET ; return to main_init ;AN000;
957 ;*******************************************************************************
963 public DosError ;AN000;
965 mov es:FileNameSegment,ds ; save for opens, creates, ;AN000;
966 mov es:FileNameOffset,dx ;AN000;
968 mov bx,0 ; get the extended error code ;AN000;
972 mov si,offset ds:Sublist_msg_exterror ;AC001;
973 extend_message ;AN001;
978 ASSUME DS:NOTHING ;AN000;
985 ;----- concatenate two strings
986 strcat proc near ; while (*d)
991 atend: ; while (*d++ = *s++)
999 ;----- Find the first non-ignorable char, return carry if CR found
1002 sj10: ; while ( *p != 13 &&
1004 CMP AL,13 ; IsBlank (*p++))
1010 cmp al,0dh ; return *p == 13;
1029 cmp al,';' ; semicolon
1033 cmp al,10 ; line feed
1035 cmp al,'=' ; equal sign
1040 procedure copyfs
near
1044 ; $do ; while we have filespec ;AN000;
1046 lodsb ; move byte to al ;AN000;
1047 cmp al,0 ; see if we are at ;AN000;
1050 ; $leave e ; exit while loop ;AN000;
1052 stosb ; move byte to path_name ;AN000;
1053 ; $enddo ; end do while ;AN000;
1063 procedure dbcs_check
near
1065 push ds ;Save registers ;AC000;
1066 push si ; " " " " ;AC000;
1067 push ax ; " " " " ;AC000;
1068 push ds ; " " " " ;AC000;
1069 pop es ;Establish addressability;AC000;
1070 cmp byte ptr es:DBCS_VECTOR
,Yes
;Have we set this yet? ;AC000;
1071 push ax ;Save input character ;AC000;
1072 ; $IF NE ;Nope ;AN000;
1074 mov al,0 ;Get DBCS environment vectors;AC000;
1075 DOS_Call Hongeul
; " " " " ;AC000;
1076 mov byte ptr es:DBCS_VECTOR
,YES
;Indicate we've got vector;AC000;
1077 mov es:DBCS_Vector_Off
,si ;Save the vector ;AC000;
1079 mov es:DBCS_Vector_Seg
,ax ; ;AC000;
1080 ; $ENDIF ; for next time in ;AC000;
1082 pop ax ;Restore input character;AC000;
1083 mov si,es:DBCS_Vector_Seg
;Get saved vector pointer;AC000;
1085 mov si,es:DBCS_Vector_Off
; ;AC000;
1086 ; $SEARCH ;Check all the vectors ;AC000;
1088 cmp word ptr ds:[si],End_Of_Vector
;End of vector table? ;AC000;
1089 ; $LEAVE E ;Yes, done ;AC000;
1091 cmp al,ds:[si] ;See if char is in vector;AC000;
1092 ; $EXITIF AE,AND ;If >= to lower, and ;AC000;
1094 cmp al,ds:[si+1] ; =< than higher range ;AC000;
1095 ; $EXITIF BE ; then DBCS character ;AC000;
1097 stc ;Set CY to indicate DBCS;AC000;
1098 ; $ORELSE ;Not in range, check next;AC000;
1101 add si,DBCS_Vector_Size
;Get next DBCS vector ;AC000;
1102 ; $ENDLOOP ;We didn't find DBCS chaR;AC000;
1105 clc ;Clear CY for exit ;AC000;
1106 ; $ENDSRCH ; ;AC000;
1108 pop ax ;Restore registers ;AC000;
1109 pop si ; " " " " ;AC000;
1110 pop ds ;Restore data segment ;AC000;
1114 dbcs_check endp
;AN000;
1121 end main_init
;AC000;