805 lines
20 KiB
NASM
805 lines
20 KiB
NASM
|
;*****************************************************************
|
|||
|
;
|
|||
|
; Copyrigth (C) 1984 Logitech. All Rights Reserved.
|
|||
|
;
|
|||
|
; Permission is hereby granted to registered users to use or
|
|||
|
; abstract the following program in the implementation of
|
|||
|
; customized versions. This permission does not include the
|
|||
|
; right to redistribute the source code of this program.
|
|||
|
;
|
|||
|
; LOGITECH SA. CH-1143 Apples, Switzerland
|
|||
|
;
|
|||
|
; Modula-2/86 Run Time Support package
|
|||
|
;
|
|||
|
; Module: LOADER.ASM
|
|||
|
; Loads Modula-2/86 '.LOD' files in memory
|
|||
|
; Version: 8086, RAM-based, MS-DOS 2.0 compatible
|
|||
|
; Release: 1.1 - Dec 84
|
|||
|
;
|
|||
|
;*****************************************************************
|
|||
|
|
|||
|
|
|||
|
CGROUP group code
|
|||
|
DGROUP group data
|
|||
|
|
|||
|
assume CS: CGROUP
|
|||
|
assume DS: DGROUP
|
|||
|
assume ES: NOTHING
|
|||
|
assume SS: NOTHING
|
|||
|
|
|||
|
include RTS.INC
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
; EXPORT QUALIFIED
|
|||
|
public LoadProg
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
; FROM RTS IMPORT
|
|||
|
extrn base_page:byte
|
|||
|
extrn START_MEM: word
|
|||
|
extrn MEM_SIZE: word
|
|||
|
|
|||
|
data ends
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
code segment public 'code'
|
|||
|
|
|||
|
; FROM RTS IMPORT
|
|||
|
extrn WRITE_MSG: near
|
|||
|
code ends
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
LD_FILE_HANDLE DW ? ; Load file handle
|
|||
|
LD_FILE_SPEC DB 64 DUP(?) ; Holds complete filename
|
|||
|
DEFAULT_NAME db 'MODULA ' ; default file to load
|
|||
|
; must be 8 characters long
|
|||
|
DEFAULT_TYPE db 'LOD' ; default filetype for loading
|
|||
|
; must be 3 characters long
|
|||
|
DEFAULT_PATH db '\M2LOD\' ; default directory for load-files
|
|||
|
DEF_PATH_LENGTH equ 7H
|
|||
|
FILE_MSG1 db ' '
|
|||
|
FILE_MSG2 db ' not found in current directory or in \M2LOD$'
|
|||
|
NO_FILE db 'File not found: $'
|
|||
|
NO_MEMORY db 'Insufficient Memory: $'
|
|||
|
|
|||
|
|
|||
|
;; - load error table and messages -
|
|||
|
badstr db '** Bad Structure - $'
|
|||
|
badver db '** Bad Version or Target system - $'
|
|||
|
badeof db '** Unexpected EOF - $'
|
|||
|
badmem db '** Insufficient Memory - $'
|
|||
|
badchk db '** Bad Checksum - $'
|
|||
|
baderr db '** LOAD error table fu - $'
|
|||
|
even
|
|||
|
LdErr dw badstr,badver,badeof,badmem,badchk,baderr
|
|||
|
data ends
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
code segment public 'code'
|
|||
|
|
|||
|
;-----------------------------------------------------------------
|
|||
|
LoadProg proc near
|
|||
|
; Finds the filename of the program to run and loads it in memory
|
|||
|
; It also builds the module-table.
|
|||
|
; in: AX prog id to use
|
|||
|
; CX:DX most recent entry in module-table
|
|||
|
;
|
|||
|
; out: BX status (0=ok)
|
|||
|
; ES:DI start address of Modula-2 program
|
|||
|
; CX:DX last module entry added to modula-table
|
|||
|
;
|
|||
|
PUSH CX
|
|||
|
PUSH DX
|
|||
|
PUSH AX
|
|||
|
CALL FIND_FILE
|
|||
|
POP AX
|
|||
|
POP DX
|
|||
|
POP CX
|
|||
|
CMP BX, 0FFFFH ; FIle found ?
|
|||
|
JNE LOAD_IT ; yes
|
|||
|
RET ; no
|
|||
|
LOAD_IT:
|
|||
|
CALL LOAD_FILE
|
|||
|
push bx
|
|||
|
call CLOSE_LOAD_FILE
|
|||
|
pop bx
|
|||
|
test bx,bx ; load ok?
|
|||
|
jz LOADED ; yes
|
|||
|
dec bx
|
|||
|
shl bx,1
|
|||
|
mov dx,LdErr[bx]
|
|||
|
CALL WRITE_MSG
|
|||
|
CALL WRITE_FILE_NAME
|
|||
|
MOV BX, 0FFFFH ; error return
|
|||
|
LOADED:
|
|||
|
RET
|
|||
|
LoadProg endp
|
|||
|
|
|||
|
|
|||
|
;---------------------------------------------------------------
|
|||
|
|
|||
|
WRITE_FILE_NAME:
|
|||
|
mov di,offset LD_FILE_SPEC
|
|||
|
WFN1:
|
|||
|
cmp byte ptr[di],0
|
|||
|
je WFN3
|
|||
|
inc di
|
|||
|
jmp WFN1
|
|||
|
WFN3:
|
|||
|
mov byte ptr[di],'$'
|
|||
|
mov dx,offset LD_FILE_SPEC
|
|||
|
call WRITE_MSG
|
|||
|
ret
|
|||
|
|
|||
|
;---------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
FIND_FILE proc near
|
|||
|
; Finds the filename according to a search strategy and opens
|
|||
|
; the file. The file handle is stored in LD_FILE_HANDLE.
|
|||
|
; Upon return BX indicates if file successfully opened (0FFFFH = not ok)
|
|||
|
; First we look for the filename, which the operator
|
|||
|
; has entered:
|
|||
|
CALL GET_SPECIFIED_NAME
|
|||
|
CALL OPEN_LOAD_FILE
|
|||
|
JNB FOUND
|
|||
|
; Not found. Let's look in the Load-File default directory.
|
|||
|
; This second search is not done, if pathname was specified:
|
|||
|
MOV SI, OFFSET LD_FILE_SPEC
|
|||
|
SEARCH_SLASH:
|
|||
|
CMP BYTE PTR [SI],"\"
|
|||
|
JE NOT_FOUND ; path speficied, so don't retry
|
|||
|
CMP BYTE PTR [SI],0
|
|||
|
JE SECOND_LOOKUP
|
|||
|
INC SI
|
|||
|
JMP SEARCH_SLASH
|
|||
|
NOT_FOUND:
|
|||
|
MOV DX, OFFSET NO_FILE
|
|||
|
CALL WRITE_MSG
|
|||
|
CALL WRITE_FILE_NAME
|
|||
|
MOV BX, 0FFFFH ; some invalid handle
|
|||
|
RET
|
|||
|
SECOND_LOOKUP:
|
|||
|
; There was no directory specified
|
|||
|
CALL GET_SECOND_NAME
|
|||
|
CALL OPEN_LOAD_FILE
|
|||
|
JNB FOUND
|
|||
|
; not in default directory neither:
|
|||
|
MOV DX, OFFSET FILE_MSG1
|
|||
|
CALL WRITE_MSG
|
|||
|
MOV BX, 0FFFFH ; some invalid handle
|
|||
|
RET
|
|||
|
FOUND:
|
|||
|
MOV BX, 0
|
|||
|
RET
|
|||
|
FIND_FILE endp
|
|||
|
|
|||
|
;-----------------------------------------------------------
|
|||
|
|
|||
|
GET_SPECIFIED_NAME:
|
|||
|
; Builds the program name out of what the operator typed plus
|
|||
|
; the default parts for name and extension. Default drive and
|
|||
|
; directory are the current-one. The so constructed filename
|
|||
|
; is stored in variable LD_FILE_SPEC
|
|||
|
; No parameters for this procedure.
|
|||
|
|
|||
|
mov di,offset LD_FILE_SPEC
|
|||
|
mov si,DEFAULT_DMA + offset base_page
|
|||
|
cld
|
|||
|
mov cx,0
|
|||
|
; check if operator gave a program name:
|
|||
|
mov cl,byte ptr[si]
|
|||
|
inc si
|
|||
|
jcxz USE_DEF_NAME ; no command tail, use default name
|
|||
|
; there is a command tail, skip leading blancs:
|
|||
|
SKIP_BLANK:
|
|||
|
lodsb ; look for first non-blank
|
|||
|
cmp al,' '
|
|||
|
jne PUT_FN_CHAR ; that must be file name
|
|||
|
loop SKIP_BLANK
|
|||
|
jmp USE_DEF_NAME ; only blanks, use default name
|
|||
|
|
|||
|
GET_FN_CHAR: ; read char from name in command tail
|
|||
|
lodsb
|
|||
|
cmp al,' '
|
|||
|
jbe END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,'*'
|
|||
|
jbe put_fn_char
|
|||
|
cmp al,','
|
|||
|
jbe END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,'.'
|
|||
|
je END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,'/'
|
|||
|
je END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,':'
|
|||
|
jbe put_fn_char
|
|||
|
cmp al,'>'
|
|||
|
jbe END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,'Z'
|
|||
|
jbe put_fn_char
|
|||
|
cmp al,'['
|
|||
|
je END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,']'
|
|||
|
je END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,'^'
|
|||
|
je END_PROG_NAME ; until 'wrong' char
|
|||
|
cmp al,'~'
|
|||
|
ja END_PROG_NAME ; until 'wrong' char
|
|||
|
PUT_FN_CHAR:
|
|||
|
stosb
|
|||
|
loop GET_FN_CHAR ; or end of command line
|
|||
|
inc si ; pretend we saw a blank..
|
|||
|
END_PROG_NAME:
|
|||
|
dec si ; SI is adjusted to pos of terminating blanc
|
|||
|
cmp byte ptr[si-1],":" ; was only the device there?
|
|||
|
je USE_DEF_NAME ; yes, so set the default name.
|
|||
|
SEARCH_DOT:
|
|||
|
dec si
|
|||
|
cmp byte ptr[si],"."
|
|||
|
je EXT_END ; extension already here.
|
|||
|
cmp si,DEFAULT_DMA ; at start of command tail?
|
|||
|
ja SEARCH_DOT ; no: keep looking for '.'
|
|||
|
jmp USE_DEF_EXT ; yes: no extension, supply one.
|
|||
|
|
|||
|
USE_DEF_NAME:
|
|||
|
mov si,offset DEFAULT_NAME
|
|||
|
mov cx,8
|
|||
|
COPY_FN_CHAR:
|
|||
|
movsb
|
|||
|
dec cx
|
|||
|
jz USE_DEF_EXT
|
|||
|
cmp byte ptr[si]," "
|
|||
|
jne COPY_FN_CHAR
|
|||
|
USE_DEF_EXT: ; end of all the 'write filename' loops
|
|||
|
mov byte ptr[di],"."
|
|||
|
inc di
|
|||
|
mov si,offset DEFAULT_TYPE
|
|||
|
mov cx,3
|
|||
|
COPY_EXT_CHAR:
|
|||
|
cmp byte ptr[si]," "
|
|||
|
je EXT_END
|
|||
|
movsb
|
|||
|
dec cx
|
|||
|
jnz COPY_EXT_CHAR
|
|||
|
EXT_END: ; name is complete
|
|||
|
mov byte ptr[di],0
|
|||
|
RET
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
GET_SECOND_NAME:
|
|||
|
mov cx,15
|
|||
|
mov di,offset FILE_MSG1
|
|||
|
mov si,offset LD_FILE_SPEC
|
|||
|
cld
|
|||
|
rep movsb
|
|||
|
mov cx,64-DEF_PATH_LENGTH
|
|||
|
mov di,offset LD_FILE_SPEC+63
|
|||
|
mov si,offset LD_FILE_SPEC+63-DEF_PATH_LENGTH
|
|||
|
std ; move filename towards the end,
|
|||
|
rep movsb ; so path can be inserted.
|
|||
|
mov di,offset LD_FILE_SPEC+2
|
|||
|
cmp byte ptr[di]-1,":"
|
|||
|
je INS_PATH
|
|||
|
mov di,offset LD_FILE_SPEC
|
|||
|
INS_PATH:
|
|||
|
mov si,offset DEFAULT_PATH
|
|||
|
cld
|
|||
|
mov cx,DEF_PATH_LENGTH
|
|||
|
rep movsb ; insert path
|
|||
|
ret
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
OPEN_LOAD_FILE:
|
|||
|
MOV AX, 3D00H ; open file for READ only
|
|||
|
MOV DX, offset LD_FILE_SPEC
|
|||
|
INT OS
|
|||
|
MOV LD_FILE_HANDLE, AX
|
|||
|
RET
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
READ_LD_FILE:
|
|||
|
mov bx,LD_FILE_HANDLE
|
|||
|
mov cx,LdBufSize
|
|||
|
mov dx,offset LdBuf
|
|||
|
mov ah,3FH
|
|||
|
int OS ; sequential read
|
|||
|
RET
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
CLOSE_LOAD_FILE:
|
|||
|
MOV AH, 3EH
|
|||
|
MOV BX, LD_FILE_HANDLE
|
|||
|
INT OS
|
|||
|
RET
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
; Alloc_Mem - called by LoadProg to allocate memory for the 'IPL'
|
|||
|
;
|
|||
|
; in: AX memory request size, in paragraphs
|
|||
|
; out: AX first paragraph of allocated chunk
|
|||
|
; BX =0 if ok, <>0 if memory not available
|
|||
|
;
|
|||
|
|
|||
|
Alloc_Mem:
|
|||
|
mov bx,1
|
|||
|
cmp ax, MEM_SIZE ; can request be satisfied?
|
|||
|
ja AllFU ; no
|
|||
|
sub MEM_SIZE,ax ; yes
|
|||
|
add ax, START_MEM ; compute next free paragraph..
|
|||
|
xchg ax, START_MEM ; update start_mem, return old value
|
|||
|
xor bx,bx
|
|||
|
AllFU: ret
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
currentVersion equ 1
|
|||
|
targetSystem equ 0
|
|||
|
NameLength equ 24 ; bytes of module name
|
|||
|
KeyLength equ 6 ; bytes of module key
|
|||
|
|
|||
|
|
|||
|
MDescr struc
|
|||
|
MDname db NameLength dup (?) ; module name
|
|||
|
MDkey db KeyLength dup (?) ; key
|
|||
|
MDproc dw ? ; offset of procedure table
|
|||
|
MDcode dw ? ; base of code
|
|||
|
MDdata dw ? ; base of data
|
|||
|
MDprogid dw ? ; 'owner' program id
|
|||
|
MDnext dd ? ; forward link
|
|||
|
MDprev dd ? ; backward link
|
|||
|
MDescr ends
|
|||
|
MDSize equ size MDescr
|
|||
|
|
|||
|
badStructure equ 1
|
|||
|
badVersion equ 2
|
|||
|
readEOF equ 3
|
|||
|
TooBig equ 4 ; not enough memory
|
|||
|
badCheck equ 5
|
|||
|
|
|||
|
; Object Record Tags:
|
|||
|
FormatVersion equ 0
|
|||
|
ProgramHeader equ 1
|
|||
|
SCModHeader equ 2
|
|||
|
ImportElement equ 3
|
|||
|
FilledData equ 4
|
|||
|
ProcedureCode equ 5
|
|||
|
SCModInitCode equ 6
|
|||
|
ModuleCode equ 7
|
|||
|
SCModuleCall equ 8
|
|||
|
RefExtData equ 9
|
|||
|
RefExtCode equ 10
|
|||
|
RefExtProc equ 11
|
|||
|
RefOwnData equ 12
|
|||
|
RefOwnCode equ 13
|
|||
|
RefOwnProc equ 14
|
|||
|
SCModuleEnd equ 15
|
|||
|
ProgramEnd equ 16
|
|||
|
|
|||
|
|
|||
|
LoadSP dw ? ; sp inside LoadProg
|
|||
|
LdBufSize equ 512
|
|||
|
LdBuf db LdBufSize dup (?) ; read buffer
|
|||
|
LdCnt dw ? ; bytes left in buffer
|
|||
|
LowSum db ? ; low byte of checksum
|
|||
|
HiSum db ? ; high byte of checksum
|
|||
|
Checksum equ word ptr LowSum
|
|||
|
CodeSize dw ? ; code size in paragraphs
|
|||
|
DataSize dw ? ; data size in paragraphs
|
|||
|
LdProgId dw ? ; id of loading program?
|
|||
|
SCMcnt dw ? ; number of SCM's to load
|
|||
|
ProgCodeBase dw ? ; base of program code segment
|
|||
|
ProgDataBase dw ? ; base of program data segment
|
|||
|
ModCodeBase dw ? ; base of module code segment
|
|||
|
ModDataBase dw ? ; base of module data segment
|
|||
|
StartOff dw ? ; start address of program, ..
|
|||
|
StartBase dw ? ; .. offset and segment.
|
|||
|
StartPtr equ dword ptr StartOff
|
|||
|
MDoff dw ?
|
|||
|
MDbase dw ?
|
|||
|
MDptr equ dword ptr MDoff
|
|||
|
PrevOff dw ?
|
|||
|
PrevBase dw ? ; previous module descrip. (init NIL)
|
|||
|
PrevPtr equ dword ptr PrevOff
|
|||
|
|
|||
|
ModCodeSize dw ?
|
|||
|
ModDataSize dw ?
|
|||
|
|
|||
|
LdMCB dw 3 dup (?) ; Memory Control Block
|
|||
|
even
|
|||
|
data ends
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
; LOAD_FILE - load from file
|
|||
|
; in: AX prog id to use
|
|||
|
; CX:DX most recent entry in module 'tree'
|
|||
|
;
|
|||
|
; out: BX status
|
|||
|
; ES:DI start address
|
|||
|
; CX:DX last module entry added
|
|||
|
;
|
|||
|
|
|||
|
LOAD_FILE proc near
|
|||
|
|
|||
|
mov LdProgId,ax ; save prog id for module descriptors
|
|||
|
mov LoadSP,sp ; save stack pointer
|
|||
|
mov PrevBase,cx ; current 'top' of module table
|
|||
|
mov PrevOff,dx
|
|||
|
call ReadSeq ; initialize for subsequent reading
|
|||
|
mov Checksum,0 ; reset checksum
|
|||
|
call ReadFormatVersion
|
|||
|
call ReadProgHdr
|
|||
|
call AllocateProgMem ; allocate code, data, module table
|
|||
|
call LoadSCM ; load first module
|
|||
|
les bx,MDptr ; point to its descriptor
|
|||
|
mov bx,ES:MDproc[bx] ; get offset to procedure table
|
|||
|
mov ES,StartBase
|
|||
|
mov ax,ES:word ptr 2[bx] ; get offset to procedure 0
|
|||
|
mov StartOff,ax ; which is offset of start address
|
|||
|
dec SCMcnt ; more modules to load?
|
|||
|
jz SCMend ; guess not.
|
|||
|
SCMloop:
|
|||
|
add MDoff,MDSize ; allocate a new module descriptor
|
|||
|
call LoadSCM ; load one SCM
|
|||
|
dec SCMcnt ; more?
|
|||
|
jnz SCMloop ; yes, load them too (why not)
|
|||
|
SCMend: call ReadProgEnd ; process ProgramEnd
|
|||
|
les di,StartPtr
|
|||
|
mov cx,MDbase
|
|||
|
mov dx,MDoff ; pointer to last module entry
|
|||
|
xor bx,bx ; if no error, return BX=0
|
|||
|
LoadFU: mov sp,LoadSP ; reset stack pointer
|
|||
|
ret
|
|||
|
LOAD_FILE endp
|
|||
|
|
|||
|
|
|||
|
ReadFormatVersion proc near
|
|||
|
call GetByte ; record tag
|
|||
|
cmp al,FormatVersion
|
|||
|
je RFV2
|
|||
|
mov bx,badStructure
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RFV2: call GetByte ; object file format
|
|||
|
cmp al,currentVersion
|
|||
|
je RFV4 ; right version
|
|||
|
mov bx,badVersion
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RFV4: call GetByte ; read target system
|
|||
|
cmp al,targetSystem
|
|||
|
je RFV6
|
|||
|
mov bx,badVersion
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RFV6: jmp CheckChecksum
|
|||
|
ReadFormatVersion endp
|
|||
|
|
|||
|
|
|||
|
ReadProgHdr proc near
|
|||
|
call GetByte
|
|||
|
cmp al,ProgramHeader
|
|||
|
je RPH2
|
|||
|
mov bx,badStructure
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RPH2: call GetWord
|
|||
|
mov CodeSize,ax
|
|||
|
call GetWord
|
|||
|
mov DataSize,ax
|
|||
|
call GetWord
|
|||
|
mov SCMcnt,ax
|
|||
|
jmp CheckChecksum
|
|||
|
ReadProgHdr endp
|
|||
|
|
|||
|
AllocateProgMem proc near
|
|||
|
mov ax,MDSize ; size of a module descriptor
|
|||
|
mul SCMcnt ; times number of modules..
|
|||
|
add ax,15
|
|||
|
mov cl,4
|
|||
|
shr ax,cl ; convert to paragraphs
|
|||
|
add ax,CodeSize ; add paragraphs of code..
|
|||
|
add ax,DataSize ; and paragraphs of data
|
|||
|
call Alloc_Mem ; allocate memory, base => AX
|
|||
|
test bx,bx ; got it?
|
|||
|
jz GotMem ; yes
|
|||
|
mov bx,TooBig ; nope.
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
GotMem: mov ProgCodeBase,ax ; start of code segment
|
|||
|
mov ModCodeBase,ax ; start of first module
|
|||
|
mov StartBase,ax ; save base of start address
|
|||
|
add ax,CodeSize
|
|||
|
mov ProgDataBase,ax ; start of data segment
|
|||
|
mov ModDataBase,ax ; data of first module
|
|||
|
add ax,DataSize
|
|||
|
mov MDbase,ax ; base of module descriptor table
|
|||
|
mov MDoff,0 ; initial offset
|
|||
|
ret
|
|||
|
AllocateProgMem endp
|
|||
|
|
|||
|
|
|||
|
; LoadSCM - load one module
|
|||
|
;
|
|||
|
LoadSCM proc near
|
|||
|
call ReadSCMHdr
|
|||
|
call GetByte ; next field tag..
|
|||
|
cmp al,ModuleCode ; ModuleCode record?
|
|||
|
je LdSCM2 ; yes
|
|||
|
mov bx,badStructure
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
LdSCM2: call RestModCode ; yes, process rest of record
|
|||
|
call ReadFixups ; process rest of module (fixups & end)
|
|||
|
ret
|
|||
|
LoadSCM endp
|
|||
|
|
|||
|
|
|||
|
; ReadSCMhdr - process an SCModHeader record
|
|||
|
; out: ModName module name
|
|||
|
; ModKey module key
|
|||
|
ReadSCMhdr proc near
|
|||
|
call GetByte
|
|||
|
cmp al,SCModHeader
|
|||
|
je RSCMH2
|
|||
|
mov bx,badStructure
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RSCMH2: les di,MDptr
|
|||
|
mov ax,ModCodeBase
|
|||
|
mov ES:MDcode[di],ax ; code-base for this module
|
|||
|
mov ax,ModDataBase
|
|||
|
mov ES:MDdata[di],ax ; data base for this module
|
|||
|
mov ax,LdProgId
|
|||
|
mov ES:MDprogid[di],ax ; owner-program id for this module
|
|||
|
;;;;;;;;add di,offset MDname ; DOESN'T WORK!!!
|
|||
|
MOV AX, OFFSET MDname
|
|||
|
ADD DI, AX
|
|||
|
mov ax,NameLength
|
|||
|
call GetNBytes ; read module name
|
|||
|
les di,MDptr
|
|||
|
;;;;;;;;add di,offset MDkey ; DOESN'T WORK
|
|||
|
MOV AX, OFFSET MDkey
|
|||
|
ADD DI, AX
|
|||
|
mov ax,KeyLength
|
|||
|
call GetNBytes ; read module key
|
|||
|
call GetWord
|
|||
|
les di,MDptr
|
|||
|
mov ES:MDproc[di],ax ; offset of procedure table
|
|||
|
call GetWord
|
|||
|
mov ModCodeSize,ax ; bytes of code
|
|||
|
call GetWord
|
|||
|
mov ModDataSize,ax ; bytes of data
|
|||
|
call GetWord ; (internal use by compiler)
|
|||
|
jmp CheckChecksum
|
|||
|
ReadSCMhdr endp
|
|||
|
|
|||
|
|
|||
|
; RestModCode - read the rest of a ModuleCode record
|
|||
|
; (called after the tag has been read)
|
|||
|
RestModCode proc near
|
|||
|
call GetWord ; length of code (bytes)
|
|||
|
mov ES,ModCodeBase ; base
|
|||
|
mov di,0 ; offset
|
|||
|
call GetNBytes ; read AX bytes at ES:0000
|
|||
|
jmp CheckChecksum
|
|||
|
RestModCode endp
|
|||
|
|
|||
|
|
|||
|
; ReadFixups - process fixup records until SCModuleEnd record is processed
|
|||
|
;
|
|||
|
ReadFixups proc near
|
|||
|
call GetByte
|
|||
|
cmp al,RefOwnCode
|
|||
|
jne RFIX2
|
|||
|
call GetWord ; offset of fixup (current module)
|
|||
|
push ax
|
|||
|
call GetWord ; 'bias' (paragraphs from codebase)
|
|||
|
add ax,ProgCodeBase ; compute fixup value
|
|||
|
pop bx ; fixup offset..
|
|||
|
mov ES,ModCodeBase ; fixup base: current module
|
|||
|
mov ES:[bx],ax
|
|||
|
call CheckChecksum
|
|||
|
jmp short ReadFixups
|
|||
|
;
|
|||
|
RFIX2: cmp al,SCModuleEnd
|
|||
|
je RFIX4
|
|||
|
mov bx,badStructure
|
|||
|
jmp LoadFU
|
|||
|
; end of module:
|
|||
|
RFIX4: mov ax,ModCodeSize ; adjust base-of-module-code
|
|||
|
add ax,15 ; paragraph pointer by size
|
|||
|
mov cl,4 ; of module code, rounded up
|
|||
|
shr ax,cl ; and converted to paragraphs.
|
|||
|
add ModCodeBase,ax
|
|||
|
mov ax,ModDataSize
|
|||
|
add ax,15
|
|||
|
mov cl,4
|
|||
|
shr ax,cl
|
|||
|
add ModDataBase,ax
|
|||
|
call LinkModuleDescriptor
|
|||
|
jmp CheckChecksum
|
|||
|
ReadFixups endp
|
|||
|
|
|||
|
LinkModuleDescriptor proc near
|
|||
|
les di,PrevPtr
|
|||
|
cmp di,NIL_OFF
|
|||
|
jne LMD2
|
|||
|
mov ax,ES
|
|||
|
cmp ax,NIL_SEG
|
|||
|
je LMD4 ; IF PrevPtr <> NIL THEN..
|
|||
|
LMD2: mov ax,MDoff
|
|||
|
mov ES:word ptr MDnext[di],ax
|
|||
|
mov ax,MDbase
|
|||
|
mov ES:word ptr MDnext+2[di],ax ; PrevPtr^.next := MDptr
|
|||
|
LMD4: les di,MDptr ; END
|
|||
|
mov ES:word ptr MDnext[di],NIL_OFF
|
|||
|
mov ES:word ptr MDnext+2[di],NIL_SEG ; MDptr^.next := NIL
|
|||
|
mov ax,PrevOff
|
|||
|
mov ES:word ptr MDprev[di],ax
|
|||
|
mov ax,PrevBase
|
|||
|
mov ES:word ptr MDprev+2[di],ax ; MDptr^.prev := PrevPtr
|
|||
|
mov PrevOff,di
|
|||
|
mov PrevBase,ES ; PrevPtr := MDptr
|
|||
|
ret
|
|||
|
LinkModuleDescriptor endp
|
|||
|
|
|||
|
ReadProgEnd proc near
|
|||
|
call GetByte
|
|||
|
cmp al,ProgramEnd
|
|||
|
je RPE2
|
|||
|
mov bx,badStructure
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RPE2: jmp CheckChecksum
|
|||
|
ReadProgEnd endp
|
|||
|
|
|||
|
; GetWord - get next word from object record (update checksum)
|
|||
|
; out: AX data word
|
|||
|
; BX status/error code
|
|||
|
; <CC> set for BX
|
|||
|
GetWord proc near
|
|||
|
call GetByte ; read lo byte
|
|||
|
mov ah,al
|
|||
|
call GetByte ; read hi byte
|
|||
|
xchg ah,al ; shuffle into position
|
|||
|
ret
|
|||
|
GetWord endp
|
|||
|
|
|||
|
|
|||
|
; GetNBytes - get multiple bytes into memory (with Checksum)
|
|||
|
; in: AX byte count (must be > 0!)
|
|||
|
; ES:DI where to put the bytes
|
|||
|
; out: CX =0
|
|||
|
; ES:DI points past last byte read
|
|||
|
GetNBytes proc near
|
|||
|
mov cx,ax
|
|||
|
mov dx,Checksum ; move checksum into reg for speed
|
|||
|
NBcont: mov bx,LdCnt ; ditto for bytes-left-in-buffer
|
|||
|
cld ; make sure direction flag is forward
|
|||
|
xor ah,ah ; extend each byte to cardinal
|
|||
|
NBytes: lodsb ; fetch next byte from buffer
|
|||
|
sub bx,1
|
|||
|
jc NBfill ; refill buffer
|
|||
|
add dx,ax ; update checksum
|
|||
|
stosb ; place byte into memory
|
|||
|
loop NBytes ; and repeat N times
|
|||
|
mov LdCnt,bx ; bring memory variables up to date
|
|||
|
mov Checksum,dx
|
|||
|
ret
|
|||
|
;
|
|||
|
NBfill: call ReadSeq ; read next buffer sequentially
|
|||
|
jmp short NBcont
|
|||
|
GetNBytes endp
|
|||
|
|
|||
|
; GetByte - get next byte from object record (updates checksum)
|
|||
|
; out: AL data byte
|
|||
|
; BX status/error code
|
|||
|
; note: CX, DX, DI, ES preserved
|
|||
|
GetByte proc near
|
|||
|
call ReadByte ; read one raw
|
|||
|
add LowSum,al ; update checksum
|
|||
|
adc HiSum,0
|
|||
|
ret
|
|||
|
GetByte endp
|
|||
|
|
|||
|
CheckChecksum proc near
|
|||
|
call ReadWord ; read record checksum field
|
|||
|
cmp ax,Checksum ; checksum checks?
|
|||
|
jne Struct ; no
|
|||
|
ret
|
|||
|
;
|
|||
|
Struct: mov bx,badCheck ; no
|
|||
|
jmp LoadFU ; short-circuit exit
|
|||
|
CheckChecksum endp
|
|||
|
|
|||
|
|
|||
|
ReadWord proc near
|
|||
|
call ReadByte ; read low byte
|
|||
|
mov ah,al ; save it
|
|||
|
call ReadByte ; read high byte
|
|||
|
xchg ah,al ; swap into position
|
|||
|
ret
|
|||
|
ReadWord endp
|
|||
|
|
|||
|
|
|||
|
; ReadByte - get next raw byte from input file
|
|||
|
; out: AL next byte
|
|||
|
; BX status/error code
|
|||
|
; note: AH, CX, DX, DI, ES preserved
|
|||
|
;
|
|||
|
ReadByte proc near
|
|||
|
cld
|
|||
|
lodsb ; yes: pull next byte from buffer
|
|||
|
sub LdCnt,1 ; anything left in buffer?
|
|||
|
jc ReadB2 ; no, refill buffer
|
|||
|
ret
|
|||
|
;
|
|||
|
ReadB2: call ReadSeq
|
|||
|
jmp short ReadByte ; try again
|
|||
|
ReadByte endp
|
|||
|
|
|||
|
|
|||
|
; ReadSeq - read next sequential block into buffer
|
|||
|
;
|
|||
|
; out: BX status/error code
|
|||
|
; SI points to start of buffer
|
|||
|
; LdCnt number of bytes read
|
|||
|
; note: AX, CX, DX, DI, ES are preserved
|
|||
|
ReadSeq proc near
|
|||
|
push ax ; just to be polite
|
|||
|
push cx
|
|||
|
push dx
|
|||
|
push di
|
|||
|
push ES
|
|||
|
push DS
|
|||
|
call READ_LD_FILE
|
|||
|
pop DS
|
|||
|
cmp ax,LdBufSize ; full record?
|
|||
|
je RstBuf ; yes
|
|||
|
cmp ax,0 ; partial record?
|
|||
|
jne RstBuf ; yes
|
|||
|
mov bx,readEOF ; no, EOF, which should never happen!
|
|||
|
jmp LoadFU
|
|||
|
;
|
|||
|
RstBuf: mov si,offset LdBuf ; reset buffer scanner
|
|||
|
mov LdCnt,LdBufSize ; and buffer count
|
|||
|
pop ES
|
|||
|
pop di
|
|||
|
pop dx
|
|||
|
pop cx
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
ReadSeq endp
|
|||
|
|
|||
|
code ends
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
end
|
|||
|
|