mirror of https://github.com/microsoft/MS-DOS.git
514 lines
14 KiB
NASM
514 lines
14 KiB
NASM
|
title LOCATE (EXE2BIN)
|
|||
|
|
|||
|
;Loader for EXE files under 86-DOS
|
|||
|
|
|||
|
;The following switch allows use with the "old linker", which put a version
|
|||
|
;number where the new linker puts the number of bytes used in the last page.
|
|||
|
;If enabled, this will cause a test for 0004 at this location (the old linker
|
|||
|
;version number), and if equal, change it to 200H so all of the last page
|
|||
|
;will be used.
|
|||
|
|
|||
|
;VER. 1.5
|
|||
|
; 05/21/82 Added rev number
|
|||
|
;
|
|||
|
;VER. 1.6
|
|||
|
; 07/01/82 A little less choosy about size matches
|
|||
|
;
|
|||
|
;VER. 2.0 Rev. 1 M.A.Ulloa
|
|||
|
; 10/08/82 Modified to use new 2.0 system calls for file i/o
|
|||
|
;
|
|||
|
; Rev. 2 M.A.Ulloa
|
|||
|
; 10/27/82 Added the DOS version check
|
|||
|
|
|||
|
FALSE EQU 0
|
|||
|
TRUE EQU NOT FALSE
|
|||
|
|
|||
|
OLDLINK EQU 0 ;1 to enable, 0 to disable
|
|||
|
|
|||
|
.xlist
|
|||
|
INCLUDE DOSSYM.ASM
|
|||
|
.list
|
|||
|
|
|||
|
|
|||
|
subttl Main Code Area
|
|||
|
page
|
|||
|
|
|||
|
|
|||
|
code segment byte
|
|||
|
code ends
|
|||
|
|
|||
|
DATA SEGMENT PUBLIC BYTE
|
|||
|
|
|||
|
|
|||
|
EXTRN bad_vers_err:BYTE,NOTFND:BYTE,NOROOM:BYTE,DIRFULL:BYTE
|
|||
|
EXTRN CANTFIX:BYTE,RDBAD:BYTE,FULL:BYTE,PROMPT:BYTE,CRLF:BYTE
|
|||
|
|
|||
|
make db "MAUlloa/Microsoft/V20"
|
|||
|
rev db "2"
|
|||
|
|
|||
|
file1_ext db ".EXE",00h
|
|||
|
file2_ext db ".BIN",00h
|
|||
|
|
|||
|
per1 db 0
|
|||
|
per2 db 0
|
|||
|
|
|||
|
file1 db 64 dup(?)
|
|||
|
handle1 dw 1 dup(?)
|
|||
|
|
|||
|
file2 db 64 dup(?)
|
|||
|
handle2 dw 1 dup(?)
|
|||
|
|
|||
|
|
|||
|
INBUF DB 5,0
|
|||
|
DB 5 DUP(?)
|
|||
|
|
|||
|
;The following locations must be defined for storing the header:
|
|||
|
|
|||
|
RUNVAR LABEL BYTE ;Start of RUN variables
|
|||
|
RELPT DW ?
|
|||
|
LASTP LABEL WORD
|
|||
|
RELSEG DW ?
|
|||
|
SIZ LABEL WORD ;Share these locations
|
|||
|
PAGES DW ?
|
|||
|
RELCNT DW ?
|
|||
|
HEADSIZ DW ?
|
|||
|
DW ?
|
|||
|
LOADLOW DW ?
|
|||
|
INITSS DW ?
|
|||
|
INITSP DW ?
|
|||
|
DW ?
|
|||
|
INITIP DW ?
|
|||
|
INITCS DW ?
|
|||
|
RELTAB DW ?
|
|||
|
RUNVARSIZ EQU $-RUNVAR
|
|||
|
|
|||
|
DATA ENDS
|
|||
|
|
|||
|
STACK SEGMENT WORD STACK
|
|||
|
DB 80H DUP (?)
|
|||
|
STACK ENDS
|
|||
|
|
|||
|
ZLOAD SEGMENT
|
|||
|
ZLOAD ENDS
|
|||
|
LOAD EQU ZLOAD
|
|||
|
|
|||
|
CODE SEGMENT BYTE
|
|||
|
|
|||
|
ASSUME CS:CODE
|
|||
|
|
|||
|
LOCATE PROC FAR
|
|||
|
JMP SHORT LOCSTRT
|
|||
|
|
|||
|
HEADER DB "Vers 2.00"
|
|||
|
|
|||
|
LOCSTRT:
|
|||
|
MOV SI,81H
|
|||
|
PUSH DS
|
|||
|
XOR AX,AX
|
|||
|
PUSH AX ;Push return address to DS:0
|
|||
|
|
|||
|
;Code to print header
|
|||
|
; PUSH DS
|
|||
|
; MOV DX,DATA
|
|||
|
; MOV DS,DX
|
|||
|
; MOV DX,OFFSET HEADER
|
|||
|
; MOV AH,STD_CON_STRING_OUTPUT
|
|||
|
; INT 21H
|
|||
|
; POP DS
|
|||
|
|
|||
|
;----- Check Version Number --------------------------------------------;
|
|||
|
mov ah,Get_Version
|
|||
|
int 21h
|
|||
|
cmp al,2
|
|||
|
jge vers_ok ; version >= 2, enter locate
|
|||
|
push ds
|
|||
|
mov dx,data
|
|||
|
mov ds,dx
|
|||
|
mov dx,offset bad_vers_err
|
|||
|
MOV AH,STD_CON_STRING_OUTPUT
|
|||
|
INT 21H
|
|||
|
pop ds
|
|||
|
ret ;long return to DOS
|
|||
|
|
|||
|
;-----------------------------------------------------------------------;
|
|||
|
vers_ok:
|
|||
|
|
|||
|
|
|||
|
MOV BX,WORD PTR DS:2 ;Get size of memory
|
|||
|
MOV DX,DATA
|
|||
|
MOV ES,DX
|
|||
|
|
|||
|
assume es:data
|
|||
|
|
|||
|
;-----------------------------------------------------------------------;
|
|||
|
|
|||
|
;----- Get the first file name
|
|||
|
call kill_bl
|
|||
|
jnc sj01
|
|||
|
mov ds,dx
|
|||
|
jmp bad_file
|
|||
|
sj01:
|
|||
|
mov di,offset file1
|
|||
|
sj0:
|
|||
|
lodsb ;get character of file name
|
|||
|
cmp al,' '
|
|||
|
je sj2
|
|||
|
cmp al,0dh
|
|||
|
je sj2
|
|||
|
cmp al,'.' ;an extension separator found?
|
|||
|
jne sj1
|
|||
|
mov es:[per1],-1
|
|||
|
sj1:
|
|||
|
stosb
|
|||
|
jmp short sj0
|
|||
|
sj2:
|
|||
|
dec si
|
|||
|
mov byte ptr es:[di],00h ;nul terminate the filename
|
|||
|
call kill_bl
|
|||
|
jc no_second
|
|||
|
|
|||
|
;----- Get the second file name
|
|||
|
mov di,offset file2
|
|||
|
sj3:
|
|||
|
lodsb ;get character of file name
|
|||
|
cmp al,' '
|
|||
|
je sj5
|
|||
|
cmp al,0dh
|
|||
|
je sj5
|
|||
|
cmp al,'.' ;an extension separator found?
|
|||
|
jne sj4
|
|||
|
mov es:[per2],-1
|
|||
|
sj4:
|
|||
|
stosb
|
|||
|
jmp short sj3
|
|||
|
sj5:
|
|||
|
mov byte ptr es:[di],00h ;nul terminate
|
|||
|
jmp short check_ext
|
|||
|
|
|||
|
;----- Copy file1 to file2
|
|||
|
no_second:
|
|||
|
mov ds,dx
|
|||
|
|
|||
|
assume ds:data
|
|||
|
|
|||
|
mov si,offset file1
|
|||
|
mov di,offset file2
|
|||
|
sj6:
|
|||
|
lodsb
|
|||
|
cmp al,'.'
|
|||
|
je sj7
|
|||
|
cmp al,00h
|
|||
|
je sj7
|
|||
|
stosb
|
|||
|
jmp short sj6
|
|||
|
sj7:
|
|||
|
mov byte ptr [di],00h
|
|||
|
|
|||
|
;----- Check that files have an extension, otherwise set default
|
|||
|
check_ext:
|
|||
|
mov ds,dx
|
|||
|
|
|||
|
assume ds:data
|
|||
|
|
|||
|
cmp [per1],-1
|
|||
|
je file1_ok
|
|||
|
mov si,offset file1
|
|||
|
sj8:
|
|||
|
lodsb
|
|||
|
cmp al,00h
|
|||
|
jne sj8
|
|||
|
mov di,si
|
|||
|
mov si,offset file1_ext
|
|||
|
call put_ext
|
|||
|
|
|||
|
file1_ok:
|
|||
|
cmp [per2],-1
|
|||
|
je file2_ok
|
|||
|
mov si,offset file2
|
|||
|
sj9:
|
|||
|
lodsb
|
|||
|
cmp al,00h
|
|||
|
jne sj9
|
|||
|
mov di,si
|
|||
|
mov si,offset file2_ext
|
|||
|
call put_ext
|
|||
|
jmp short file2_ok
|
|||
|
|
|||
|
;----- Fill in the default extent
|
|||
|
put_ext proc near
|
|||
|
dec di
|
|||
|
mov cx,5 ;move extent: period,extent,null
|
|||
|
rep movsb
|
|||
|
ret
|
|||
|
put_ext endp
|
|||
|
|
|||
|
;----- Find the first non-blank
|
|||
|
kill_bl proc near
|
|||
|
cld
|
|||
|
sj10:
|
|||
|
lodsb
|
|||
|
cmp al,' '
|
|||
|
je sj10
|
|||
|
dec si
|
|||
|
cmp al,0dh
|
|||
|
clc
|
|||
|
jne sj11
|
|||
|
stc
|
|||
|
sj11:
|
|||
|
ret
|
|||
|
kill_bl endp
|
|||
|
|
|||
|
file2_ok:
|
|||
|
|
|||
|
;-----------------------------------------------------------------------;
|
|||
|
|
|||
|
mov dx,offset file1
|
|||
|
mov ah,open
|
|||
|
mov al,0 ;ror reading only
|
|||
|
INT 21H ;Open input file
|
|||
|
jc bad_file
|
|||
|
mov [handle1],ax
|
|||
|
jmp exeload
|
|||
|
|
|||
|
bad_file:
|
|||
|
MOV DX,OFFSET NOTFND
|
|||
|
xERROR:
|
|||
|
MOV AH,STD_CON_STRING_OUTPUT
|
|||
|
INT 21H
|
|||
|
RET ;FAR return to MS-DOS
|
|||
|
TOOBIG:
|
|||
|
MOV DX,OFFSET NOROOM
|
|||
|
JMP xERROR
|
|||
|
BADEXE:
|
|||
|
MOV DX,OFFSET CANTFIX
|
|||
|
ERRORJ: JMP xERROR
|
|||
|
|
|||
|
EXELOAD:
|
|||
|
MOV DX,OFFSET RUNVAR ;Read header in here
|
|||
|
MOV CX,RUNVARSIZ ;Amount of header info we need
|
|||
|
push bx
|
|||
|
mov bx,[handle1]
|
|||
|
MOV AH,read
|
|||
|
INT 21H ;Read in header
|
|||
|
pop bx
|
|||
|
CMP [RELPT],5A4DH ;Check signature word
|
|||
|
JNZ BADEXE
|
|||
|
MOV AX,[HEADSIZ] ;size of header in paragraphs
|
|||
|
ADD AX,31 ;Round up first
|
|||
|
CMP AX,1000H ;Must not be >=64K
|
|||
|
JAE TOOBIG
|
|||
|
AND AX,NOT 31
|
|||
|
MOV CL,4
|
|||
|
SHL AX,CL ;Header size in bytes
|
|||
|
|
|||
|
push dx
|
|||
|
push cx
|
|||
|
push ax
|
|||
|
push bx
|
|||
|
mov dx,ax
|
|||
|
xor cx,cx
|
|||
|
mov al,0
|
|||
|
mov bx,[handle1]
|
|||
|
mov ah,lseek
|
|||
|
int 21h
|
|||
|
pop bx
|
|||
|
pop ax
|
|||
|
pop cx
|
|||
|
pop dx
|
|||
|
|
|||
|
XCHG AL,AH
|
|||
|
SHR AX,1 ;Convert to pages
|
|||
|
MOV DX,[PAGES] ;Total size of file in 512-byte pages
|
|||
|
SUB DX,AX ;Size of program in pages
|
|||
|
CMP DX,80H ;Fit in 64K?
|
|||
|
JAE TOOBIG
|
|||
|
XCHG DH,DL
|
|||
|
SHL DX,1 ;Convert pages to bytes
|
|||
|
MOV AX,[LASTP] ;Get count of bytes in last page
|
|||
|
OR AX,AX ;If zero, use all of last page
|
|||
|
JZ WHOLEP
|
|||
|
|
|||
|
IF OLDLINK
|
|||
|
CMP AX,4 ;Produced by old linker?
|
|||
|
JZ WHOLEP ;If so, use all of last page too
|
|||
|
ENDIF
|
|||
|
|
|||
|
SUB DX,200H ;Subtract last page
|
|||
|
ADD DX,AX ;Add in byte count for last page
|
|||
|
WHOLEP:
|
|||
|
MOV [SIZ],DX
|
|||
|
ADD DX,15
|
|||
|
SHR DX,CL ;Convert bytes to paragraphs
|
|||
|
MOV BP,LOAD
|
|||
|
ADD DX,BP ;Size + start = minimum memory (paragr.)
|
|||
|
CMP DX,BX ;Enough memory?
|
|||
|
JA TOOBIG
|
|||
|
MOV DX,OFFSET CANTFIX
|
|||
|
MOV AX,[INITSS]
|
|||
|
OR AX,[INITSP]
|
|||
|
OR AX,[INITCS]
|
|||
|
ERRORNZ:
|
|||
|
jz xj
|
|||
|
JMP ERRORJ ;Must not have SS, SP, or CS to init.
|
|||
|
xj: MOV AX,[INITIP]
|
|||
|
OR AX,AX ;If IP=0, do binary fix
|
|||
|
JZ BINFIX
|
|||
|
CMP AX,100H ;COM file must be set up for CS:100
|
|||
|
JNZ ERRORNZ
|
|||
|
|
|||
|
push dx
|
|||
|
push cx
|
|||
|
push ax
|
|||
|
push bx
|
|||
|
mov dx,100h ;chop off first 100h
|
|||
|
xor cx,cx
|
|||
|
mov al,1 ;seek from current position
|
|||
|
mov bx,[handle1]
|
|||
|
mov ah,lseek
|
|||
|
int 21h
|
|||
|
pop bx
|
|||
|
pop ax
|
|||
|
pop cx
|
|||
|
pop dx
|
|||
|
|
|||
|
SUB [SIZ],AX ;And count decreased size
|
|||
|
CMP [RELCNT],0 ;Must have no fixups
|
|||
|
JNZ ERRORNZ
|
|||
|
BINFIX:
|
|||
|
XOR BX,BX ;Initialize fixup segment
|
|||
|
;See if segment fixups needed
|
|||
|
CMP [RELCNT],0
|
|||
|
JZ LOADEXE
|
|||
|
GETSEG:
|
|||
|
MOV DX,OFFSET PROMPT
|
|||
|
MOV AH,STD_CON_STRING_OUTPUT
|
|||
|
INT 21H
|
|||
|
MOV AH,STD_CON_STRING_INPUT
|
|||
|
MOV DX,OFFSET INBUF
|
|||
|
INT 21H ;Get user response
|
|||
|
MOV DX,OFFSET CRLF
|
|||
|
MOV AH,STD_CON_STRING_OUTPUT
|
|||
|
INT 21H
|
|||
|
MOV SI,OFFSET INBUF+2
|
|||
|
MOV BYTE PTR [SI-1],0 ;Any digits?
|
|||
|
JZ GETSEG
|
|||
|
DIGLP:
|
|||
|
LODSB
|
|||
|
SUB AL,"0"
|
|||
|
JC DIGERR
|
|||
|
CMP AL,10
|
|||
|
JB HAVDIG
|
|||
|
AND AL,5FH ;Convert to upper case
|
|||
|
SUB AL,7
|
|||
|
CMP AL,10
|
|||
|
JB DIGERR
|
|||
|
CMP AL,10H
|
|||
|
JAE DIGERR
|
|||
|
HAVDIG:
|
|||
|
SHL BX,1
|
|||
|
SHL BX,1
|
|||
|
SHL BX,1
|
|||
|
SHL BX,1
|
|||
|
OR BL,AL
|
|||
|
JMP DIGLP
|
|||
|
|
|||
|
DIGERR:
|
|||
|
CMP BYTE PTR [SI-1],0DH ;Is last char. a CR?
|
|||
|
JNZ GETSEG
|
|||
|
LOADEXE:
|
|||
|
XCHG BX,BP ;BX has LOAD, BP has fixup
|
|||
|
|
|||
|
MOV CX,[SIZ]
|
|||
|
MOV AH,read
|
|||
|
push di
|
|||
|
mov di,[handle1]
|
|||
|
PUSH DS
|
|||
|
MOV DS,BX
|
|||
|
XOR DX,DX
|
|||
|
push bx
|
|||
|
mov bx,di
|
|||
|
INT 21H ;Read in up to 64K
|
|||
|
pop bx
|
|||
|
POP DS
|
|||
|
pop di
|
|||
|
Jnc HAVEXE ;Did we get it all?
|
|||
|
MOV DX,OFFSET RDBAD
|
|||
|
jmp xERROR ;Non fatal, print warning
|
|||
|
HAVEXE:
|
|||
|
CMP [RELCNT],0 ;Any fixups to do?
|
|||
|
JZ STORE
|
|||
|
MOV AX,[RELTAB] ;Get position of table
|
|||
|
|
|||
|
push dx
|
|||
|
push cx
|
|||
|
push ax
|
|||
|
push bx
|
|||
|
mov dx,ax
|
|||
|
xor cx,cx
|
|||
|
mov al,0
|
|||
|
mov bx,[handle1]
|
|||
|
mov ah,lseek
|
|||
|
int 21h
|
|||
|
pop bx
|
|||
|
pop ax
|
|||
|
pop cx
|
|||
|
pop dx
|
|||
|
|
|||
|
MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
|
|||
|
RELOC:
|
|||
|
MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
|
|||
|
MOV CX,4
|
|||
|
MOV AH,read
|
|||
|
push bx
|
|||
|
mov bx,[handle1]
|
|||
|
INT 21H ;Read in one relocation pointer
|
|||
|
pop bx
|
|||
|
Jnc RDCMP
|
|||
|
JMP BADEXE
|
|||
|
RDCMP:
|
|||
|
MOV DI,[RELPT] ;Get offset of relocation pointer
|
|||
|
MOV AX,[RELSEG] ;Get segment
|
|||
|
ADD AX,BX ;Bias segment with actual load segment
|
|||
|
MOV ES,AX
|
|||
|
ADD ES:[DI],BP ;Relocate
|
|||
|
DEC [RELCNT] ;Count off
|
|||
|
JNZ RELOC
|
|||
|
STORE:
|
|||
|
MOV AH,CREAT
|
|||
|
MOV DX,OFFSET file2
|
|||
|
xor cx,cx
|
|||
|
INT 21H
|
|||
|
Jc MKERR
|
|||
|
mov [handle2],ax
|
|||
|
MOV CX,[SIZ]
|
|||
|
MOV AH,write
|
|||
|
push di
|
|||
|
mov di,[handle2]
|
|||
|
PUSH DS
|
|||
|
MOV DS,BX
|
|||
|
XOR DX,DX ;Address 0 in segment
|
|||
|
push bx
|
|||
|
mov bx,di
|
|||
|
INT 21H
|
|||
|
pop bx
|
|||
|
POP DS
|
|||
|
pop di
|
|||
|
Jc WRTERR ;Must be zero if more to come
|
|||
|
MOV AH,CLOSE
|
|||
|
push bx
|
|||
|
mov bx,[handle2]
|
|||
|
INT 21H
|
|||
|
pop bx
|
|||
|
RET
|
|||
|
|
|||
|
WRTERR:
|
|||
|
MOV DX,OFFSET FULL
|
|||
|
JMP xERROR
|
|||
|
MKERR:
|
|||
|
MOV DX,OFFSET DIRFULL
|
|||
|
JMP xERROR
|
|||
|
|
|||
|
LOCATE ENDP
|
|||
|
CODE ENDS
|
|||
|
END LOCATE
|
|||
|
|