475 lines
11 KiB
NASM
475 lines
11 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.
|
||
;
|
||
;
|
||
; title 'Modula-2/86 Resident Loader'
|
||
;
|
||
; Author: Hugh McLarty
|
||
;
|
||
; Version: 0.0 03 August 83
|
||
; 8308.06 converted to MSDOS
|
||
;
|
||
; Introduction:
|
||
;
|
||
; This module loads Modula-2/86 'LOD' files into memory.
|
||
;
|
||
code segment public
|
||
data segment public
|
||
DOS equ 21h
|
||
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
|
||
FileHandle dw ?
|
||
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
|
||
|
||
; LoadProg - load from file
|
||
; in: AX prog id to use
|
||
; BX file handle of already opened file
|
||
; CX:DX most recent entry in module 'tree'
|
||
;
|
||
; out: BX status
|
||
; ES:DI start address
|
||
; CX:DX last module entry added
|
||
;
|
||
public LoadProg
|
||
extrn Alloc_Mem:NEAR
|
||
assume CS:code,DS:data
|
||
LoadProg 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 InitInput ; initialize for reading from FCB
|
||
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
|
||
LoadProg 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,0Fh
|
||
jne LMD2
|
||
mov ax,ES
|
||
cmp ax,0FFFFh
|
||
je LMD4 ; IF PrevPtr <> NIL THEN..
|
||
LMD2: mov ax,MDoff
|
||
mov ES:MDnext[di],ax
|
||
mov ax,MDbase
|
||
mov ES:MDnext+2[di],ax ; PrevPtr^.next := MDptr
|
||
LMD4: les di,MDptr ; END
|
||
mov ES:MDnext[di],0Fh
|
||
mov ES:MDnext+2[di],0FFFFh ; MDptr^.next := NIL
|
||
mov ax,PrevOff
|
||
mov ES:MDprev[di],ax
|
||
mov ax,PrevBase
|
||
mov ES: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
|
||
|
||
|
||
InitInput proc near
|
||
mov FileHandle,bx
|
||
InitInput endp ; fall through to read first block
|
||
; 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
|
||
mov bx,FileHandle
|
||
mov cx,LdBufSize
|
||
mov dx,offset LdBuf
|
||
mov ah,3FH
|
||
int DOS ; sequential read
|
||
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
|
||
|