1 ; SCCSID = @(#)locate.asm 4.3 85/09/13
4 ; Loader for EXE files under 86-DOS
6 ; 05/21/82 Added rev number
8 ; 07/01/82 A little less choosy about size matches
10 ; 10/08/82 Modified to use new 2.0 system calls for file i/o
12 ; 10/27/82 Added the DOS version check
14 ; 8/30/83 Fixed command line parsing
16 ; 10-12-83 More fixes to command line parsing
18 ; 10/17/83 Use Printf for messages
19 ; Ver 2.5 MZ Fix LOCATE sss D: problem
20 ; 04/09/87 Add PARSER and MESSAGE RETRIEVER
23 ; The following switch allows use with the "old linker", which put a version
24 ; number where the new linker puts the number of bytes used in the last page.
25 ; If enabled, this will cause a test for 0004 at this location (the old linker
26 ; version number), and if equal, change it to 200H so all of the last page
30 OLDLINK EQU
0 ;1 to enable, 0 to disable
34 ; INCLUDE DOSSYM.INC ; also versiona.inc
35 ; INCLUDE E2BMACRO.INC
42 DATA SEGMENT PUBLIC BYTE
47 file1_ext db ".EXE",00h
48 file2_ext db ".BIN",00h
53 file1 db (64+13) dup(?
)
54 fnptr dw offset file1
; Ptr to filename in file1
57 file2 db (64+13) dup(?
)
58 f2cspot dw offset file2
; Ptr to spot in file2, file1 maybe added
61 dma_buf db 80h
dup(0) ; DMA transfer buffer
66 ;The following locations must be defined for storing the header:
68 RUNVAR
LABEL BYTE ;Start of RUN variables
72 SIZ
LABEL WORD ;Share these locations
84 RUNVARSIZ EQU
$-RUNVAR
88 STACK SEGMENT WORD STACK
89 DB (362 - 80h
) + 80H
DUP (?
) ; (362 - 80h) is IBMs ROM requirement
90 ; (New - Old) == size of growth
101 ASSUME
CS:CODE,SS:STACK
108 PUSH AX ;Push return address to DS:0
114 MOV BX,WORD PTR DS:[2] ;Get size of memory
123 ;-----------------------------------------------------------------------;
126 ; The rules for the arguments are:
128 ; If no extention is present, .EXE is used.
130 ; If no drive is present in file2, use the one from file1
131 ; If no path is specified, then use current dir
132 ; If no filename is specified, use the filename from file1
133 ; If no extention is present in file2, .BIN is used
137 ;----- Get the first file name
138 call kill_bl
; p = skipblanks (p);
139 jnc sj01
; if (p == NULL)
142 MESSAGE msgNoFile
;AC000;
144 mov di,offset file1
; d = file1;
146 lodsb ; while (!IsBlank(c=*p++)) {
150 cmp al,'\' ; if (c == '\\' || c == ':') {
155 mov fnptr,di ; fnptr = ptr to slash
156 inc fnptr ; fnptr advanced past slash to fname
157 xor DX,DX ; per1 = NULL;
159 cmp al,'.' ; if (c == '.')
161 mov DX,DI ; per1 = p-1;
169 mov byte ptr es:[di],00h ; *d = 0;
170 call kill_bl ; if (End(p))
172 cmp byte ptr [file1+1],':' ; Drive spec on first file?
174 mov ax,word ptr file1 ; get drive stuff
175 mov word ptr file2,ax
179 jmp no_second ; goto No_second;
183 ;----- Get the second file name
184 mov di,offset file2 ; d = file2
185 cmp byte ptr [si+1],':' ; Drive spec on second file?
187 cmp byte ptr [file1+1],':' ; Drive spec on first file?
189 push ax ; Suck drive spec from file1
190 mov ax,word ptr file1
195 lodsb ; while (!IsBlank(c=*p++)) {
199 cmp al,'\' ; if (c == '\\')
201 xor ah,ah ; per2 = FALSE;
203 cmp al,'.' ; if (c == '.')
205 mov ah,-1 ; per2 = TRUE;
211 mov byte ptr es:[di],00h ; *d = 0;
212 mov ah,Set_DMA
; Use find_first to see if file2 is
213 mov dx,offset dma_buf
; a directory. If it isn't, go to
214 push es ; chex_ext. If it is, put a back-
215 pop ds ; slash on the end of the string,
216 int 21h
; set f2cspot to point to the spot
217 mov ah,Find_First
; right after the backslash, and
218 mov dx,offset file2
; fall through to no_second so that
219 mov cx,-1 ; file1's name will be added to file2.
222 test dma_buf
+21,00010000b
226 CMP BYTE PTR ES:[DI-1],':'
227 JNZ Check_Ext
; if char is not a : then skip
228 JMP SetSecond
; presume drive:
236 ;----- Copy file1 to file2
242 mov si,fnptr
; s = ptr to fname in file1;
243 mov di,f2cspot
; d = spot in file2 to cat file1;
244 mov dx,per1
; dx = ptr to ext dot in file1;
247 sj6: ; while (TRUE) {
248 cmp SI,dx ; if (s == per1)
256 mov byte ptr [di],00h ; *d = 0;
258 ;----- Check that files have an extension, otherwise set default
264 cmp per1
,0 ; if (per1 == NULL) {
266 mov di,offset file1
; d = file1;
267 mov si,offset file1_ext
; s = ".EXE";
268 call strcat
; strcat (d, s);
270 cmp per2
,-1 ; if (per2 != NULL) {
272 mov di,offset file2
; d = file2;
273 mov si,offset file2_ext
; s = ".BIN";
274 call strcat
; strcap (d, s);
275 jmp short file2_ok
; }
277 ;-----------------------------------------------------------------------;
280 mov ax,(open
SHL 8) + 0 ;for reading only
281 INT 21H
;Open input file
287 MESSAGE msgNoFile
;AC000;
290 MESSAGE msgNoConvert
;AC000;
292 MESSAGE msgOutOfMemory
;AC000;
295 MOV DX,OFFSET RUNVAR
;Read header in here
296 MOV CX,RUNVARSIZ
;Amount of header info we need
300 INT 21H
;Read in header
302 CMP [RELPT
],5A4DH
;Check signature word
304 MOV AX,[HEADSIZ
] ;size of header in paragraphs
305 ADD AX,31 ;Round up first
306 CMP AX,1000H
;Must not be >=64K
310 SHL AX,CL ;Header size in bytes
328 SHR AX,1 ;Convert to pages
329 MOV DX,[PAGES
] ;Total size of file in 512-byte pages
330 SUB DX,AX ;Size of program in pages
331 CMP DX,80H
;Fit in 64K?
334 SHL DX,1 ;Convert pages to bytes
335 MOV AX,[LASTP
] ;Get count of bytes in last page
336 OR AX,AX ;If zero, use all of last page
340 CMP AX,4 ;Produced by old linker?
341 JZ WHOLEP
;If so, use all of last page too
344 SUB DX,200H
;Subtract last page
345 ADD DX,AX ;Add in byte count for last page
349 SHR DX,CL ;Convert bytes to paragraphs
351 ADD DX,BP ;Size + start = minimum memory (paragr.)
352 CMP DX,BX ;Enough memory?
354 MESSAGE msgNoConvert
;AC000;
360 JMP WRTERR
;Must not have SS, SP, or CS to init.
362 OR AX,AX ;If IP=0, do binary fix
364 CMP AX,100H
;COM file must be set up for CS:100
371 mov dx,100h
;chop off first 100h
373 mov al,1 ;seek from current position
382 SUB [SIZ
],AX ;And count decreased size
383 CMP [RELCNT
],0 ;Must have no fixups
386 XOR BX,BX ;Initialize fixup segment
387 ;See if segment fixups needed
391 MESSAGE msgFixUp
;AC000;
392 MOV AH,STD_CON_STRING_INPUT
394 INT 21H
;Get user response
395 MOV SI,OFFSET INBUF
+2
396 MOV BYTE PTR [SI-1],0 ;Any digits?
404 AND AL,5FH
;Convert to upper case
419 CMP BYTE PTR [SI-1],0DH ;Is last char. a CR?
422 XCHG BX,BP ;BX has LOAD, BP has fixup
433 INT 21H
;Read in up to 64K
437 Jnc HAVEXE
;Did we get it all?
438 MESSAGE msgReadError
;AC000;
440 CMP [RELCNT
],0 ;Any fixups to do?
442 MOV AX,[RELTAB
] ;Get position of table
459 MOV DX,OFFSET RELPT
;4-byte buffer for relocation address
461 MOV DX,OFFSET RELPT
;4-byte buffer for relocation address
466 INT 21H
;Read in one relocation pointer
471 MOV DI,[RELPT
] ;Get offset of relocation pointer
472 MOV AX,[RELSEG
] ;Get segment
473 ADD AX,BX ;Bias segment with actual load segment
475 ADD ES:[DI],BP ;Relocate
476 DEC [RELCNT
] ;Count off
491 XOR DX,DX ;Address 0 in segment
498 Jc WRTERR
;Must be zero if more to come
507 MESSAGE msgOutOfMemory
;AC000;
510 MESSAGE msgFileCreateError
;AC000;
516 ;----- concatenate two strings
517 strcat proc
near ; while (*d)
522 atend: ; while (*d++ = *s++)
530 ;----- Find the first non-ignorable char, return carry if CR found
533 sj10: ; while ( *p != 13 &&
535 CMP AL,13 ; IsBlank (*p++))
541 cmp al,0dh ; return *p == 13;
558 cmp al,';' ; semicolon
562 cmp al,10 ; line feed
564 cmp al,'=' ; equal sign
569 ; Take a default message pointer in DX and convert it to access-denied iff
570 ; the extended error indicates so. Leave all other registers (except AX)
573 Procedure TriageError
,near
574 retnc
; no carry => do nothing...
576 SaveReg
<BX,CX,SI,DI,BP,ES,DS,AX,DX>
577 MOV AH,GetExtendedError
579 RestoreReg
<CX,BX> ; restore original AX
580 MESSAGE msgNoAccess
;AC000;
581 CMP AX,65 ; network access denied?
582 JZ NoMove
; Yes, return it.
586 RestoreReg
<DS,ES,BP,DI,SI,CX,BX>