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
|
||
|