dos_compilers/Logitech Modula-2 v1/LOADER.ASM

475 lines
11 KiB
NASM
Raw Normal View History

2024-07-01 00:16:10 +02:00
;**********************************************************************
;
; 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