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