ð­OSyntax10.Scn.Fnt4^ Syntax10b.Scn.Fnt&                 2!.!'      »)@°ÿÿÿ€8ÀÔFoldElemsNew#Syntax10.Scn.Fnt.. Call Kernel.Mark for all global pointers. ÿÿÿÿ€8ÀÔ­ýÿÿ€8ÀÔ?Syntax10.Scn.FntI5‘ VAR m:Module; i,p,ptradr:LONGINT; ptr:Kernel.Ptr; BEGIN m:=modules; (* ModuleDesc and ModuleBlock are marked via modules ??? *) WHILE m#NIL DO i:=LEN(m.ptrTab^); ptradr:=SYSTEM.ADR(m.ptrTab[0]); WHILE i>0 DO SYSTEM.GET(ptradr,p); SYSTEM.GET(p,ptr); IF ptr#NIL THEN Kernel.Mark(ptr); END; DEC(i); INC(ptradr,4); END; i:=LEN(m.tdescs^); ptradr:=SYSTEM.ADR(m.tdescs[0]); WHILE i>0 DO SYSTEM.GET(ptradr,ptr); Kernel.Mark(ptr); DEC(i); INC(ptradr,4); END; m:=m^.next; END END FindRoots;ÿÿÿÿ€8ÀÔ­ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt11 Call Kernel.Candidate for all stack values. ÿÿÿÿ€8ÀÔ+ûÿÿ€8ÀÔiSyntax10.Scn.Fntr#Q7E@$im VAR i,p,sp:LONGINT; ctxt:Unix.SigContextPtr; BEGIN SYSTEM.GETREG(29,sp); IF Kernel.TrapHandlingLevel>0 THEN (* running on system stack *) WHILE sp1 DO DEC(i); m1:=SYSTEM.VAL(Module,m.imports[i]); DEC(m1.refcnt); END; END Delete;ÿÿÿÿ€8ÀÔl¶ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt(( Read a module from its object file. ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ²ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔp Aÿÿÿÿ€8ÀÔ¨ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt66 Check if next character is correct block tag. ÿÿÿÿ€8ÀÔ`ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt~~ VAR ch:CHAR; BEGIN Files.Read(R,ch); IF ch#tag THEN importing:=m.name; res:=corruptedObjFile; END END Block;ÿÿÿÿ€8ÀÔ*Iùÿÿ€8ÀÔCSyntax10.Scn.FntáSyntax10b.Scn.FntŽu VAR tdb:TDescBlock; tdd:TDescDesc; i,tdsize,recsize,pvfp,bmno:LONGINT; nofmeth,nofnewmeth,mthno,nofptr,root,entry:LONGINT; name:Name; BEGIN Files.ReadString(R,name); IF name="" THEN Files.ReadNum(R,pvfp) ELSE pvfp:=0 END; Files.ReadNum(R,types[descnr].link); Files.ReadNum(R,recsize); Files.ReadNum(R,bmno); types[descnr].bmno:=bmno; IF bmno >= 0 THEN Files.ReadString(R,types[descnr].bname); IF types[descnr].bname="" THEN Files.ReadNum(R,types[descnr].bpvfp) END END; Files.ReadNum(R,nofmeth); types[descnr].nofmeth:=nofmeth; Files.ReadNum(R,types[descnr].nofinhmeth); Files.ReadNum(R,nofnewmeth); Files.ReadNum(R,nofptr); root:=14 (* tdsize..pvfp *) + nofmeth + ExtTabWordSize + 1 (* tag *); INC(root,(-root+2) MOD 4); (* ADR(tdesc.a[root]) MOD 16=8 ! *) types[descnr].root:=root; tdsize:=(root + 1 (* recsize *) + nofptr + 1 (* sentinel *))*4; SYSTEM.NEW(tdb,tdsize-24 (* SysBlk header *)); IF tdb=NIL THEN importing:=name; res:=notEnoughSpace; RETURN END; DEC(SYSTEM.VAL(ADDRESS,tdb),24); types[descnr].tdb:=tdb; tdd:=SYSTEM.VAL(TDescDesc,tdb); tdd.tdsize:=tdsize; tdd.sentinel:=-4; tdd.self:=SYSTEM.ADR(tdb.word[root]); tdd.name:=name; tdd.mdesc:=m; tdd.pvfprint:=pvfp; i:=0; WHILE i < nofnewmeth DO Files.ReadNum(R,mthno); Files.ReadNum(R,entry); INC(i); tdb.word[root + Mth0WordOffset-mthno]:=SYSTEM.ADR(m.code[0]) + 4*entry END; tdb.word[root-1]:=SYSTEM.ADR(tdb.word[0]); tdb.word[root]:=recsize; i:=0; WHILE i < nofptr DO Files.ReadNum(R,tdb.word[root+1+i]); INC(i) END; tdb.word[root+1+nofptr]:=-(nofptr+1)*4; tdesc:=SYSTEM.ADR(tdb.word[root]) END ReadType;ÿÿÿÿ€8ÀÔSþÿÿ€8ÀÔQSyntax10.Scn.Fnt`Syntax10b.Scn.FntàO— BEGIN LOOP IF curexp=limexp THEN res:=objNotFound; object:=name; objmode:=modeStr[mode]; EXIT END; IF (curexp.name=name) & (curexp.mode=mode) THEN IF curexp.fprint#fprint THEN res:=fpMismatch; object:=name; objmode:=modeStr[mode] END; adr:=curexp.adr; INC(SYSTEM.VAL(LONGINT,curexp),SIZE(Export)); EXIT; END; INC(SYSTEM.VAL(LONGINT,curexp),SIZE(Export)); END; END FindExp;ÿÿÿÿ€8ÀÔG¦ýÿÿ€8ÀÔ_Syntax10.Scn.Fnt²Syntax10b.Scn.Fnt–OYü VAR save,td:LONGINT; tdd:TDescDesc; BEGIN save:=curtd; (* anonymous tdescs are unsorted *) LOOP IF curtd=limtd THEN res:=objNotFound; object:=name; objmode:=modeStr[8]; EXIT ;END; SYSTEM.GET(curtd,td); SYSTEM.GET(td-4,tdd); IF tdd.name=name THEN IF (tdd.pvfprint=fprint) OR (fprint=0) THEN adr:=td; INC(curtd,4); EXIT; END; IF name#"" THEN res:=fpMismatch; object:=name; objmode:=modeStr[8]; EXIT; END END; INC(curtd,4); END; IF name="" THEN curtd:=save; END; END FindTDesc;ÿÿÿÿ€8ÀÔ4ÿÿÿÿ€8ÀÔŽ°«¥ IØ"F]ÿÿÿÿ€8ÀÔyúÿÿ€8ÀÔSyntax10.Scn.FntGüÿÿ˜xI@p1KeplerElemsAllocKeplerGraphsGraphDescKeplerGraphsStarDesc°°ð~Ðà~°~ðð|ÐÀ}°ð|ðÐ{Р|°Ð{ð°zЀ{°°zðyÐày°yððwÐÀxÀèxÀ˜x°ðwðÐvРw°Ðvð°uЀvÀÀx€ÀxÐ °À à~Ð à~À ~Ð ~À À}Ð À}À ð|Ð ð|À  |Ð  |À °zÈ ˆÈ ¸~È è}È ˜}È È|È ¨{¨ °˜°¨ °z˜~°¸~À ¸~ظ~Kepler1RectangleDescKeplerFramesCaptionDescexportsSyntax10.Scn.FnttdescsSyntax10.Scn.FntcmdsSyntax10.Scn.Fnt ptrTabSyntax10.Scn.Fnt  importsSyntax10.Scn.FntdataSyntax10.Scn.Fntglobal variablesSyntax10.Scn.FntconstantsSyntax10.Scn.FntcodeSyntax10.Scn.FntrefsSyntax10.Scn.FntKepler1LineDesc !"#$%&'tagSyntax10.Scn.Fnt(aSyntax10.Scn.Fnt)bSyntax10.Scn.Fnt*cSyntax10.Scn.Fnt+lenSyntax10.Scn.Fnt,dataSyntax10.Scn.Fnt-Kepler1AttrDesc./0123m.exports etc.Syntax10.Scn.Fnt4¿¯ú†ÿÿ ƒ The allocated module storage is composed of the blocks indicated on the left side of the picture. Each block is structured as show on the right. The pointer in m point to the value after the tag. The tag is always a replicate of the tag generated by SYSTEM.NEW for the whole allocated block. NOTE The len value contains the number of entries, i.e. bytes DIV 4.  ÿÿÿÿ€8ÀÔÙùÿÿ€8ÀÔ#Syntax10.Scn.Fnt VAR t,gvarSize:LONGINT; BEGIN SYSTEM.GET(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.exports),arrPtr); arrPtr.len:=nofexp; INC(SYSTEM.VAL(ADDRESS,arrPtr),((LONG(nofexp)*SIZE(Export)+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.tdescs),arrPtr); arrPtr.len:=nofdesc; INC(SYSTEM.VAL(ADDRESS,arrPtr),((LONG(nofdesc)*4+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.cmds),arrPtr); arrPtr.len:=nofcom; INC(SYSTEM.VAL(ADDRESS,arrPtr),((LONG(nofcom)*SIZE(Cmd)+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.ptrTab),arrPtr); arrPtr.len:=nofptr; INC(SYSTEM.VAL(ADDRESS,arrPtr),((LONG(nofptr)*4+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.imports),arrPtr); arrPtr.len:=nofimp+1; INC(SYSTEM.VAL(ADDRESS,arrPtr),(((nofimp+1)*4+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.data),arrPtr); gvarSize:=datasize+(-datasize) MOD 8; m.sb:=SYSTEM.ADR(arrPtr.data)+gvarSize; arrPtr.len:=(gvarSize+consize+3) DIV 4; INC(SYSTEM.VAL(ADDRESS,arrPtr),((gvarSize+consize+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.code),arrPtr); arrPtr.len:=codesize DIV 4; INC(SYSTEM.VAL(ADDRESS,arrPtr),((codesize+35) DIV 16)*16); SYSTEM.PUT(SYSTEM.VAL(ADDRESS,arrPtr)-4,t); SYSTEM.PUT(SYSTEM.ADR(m.refs),arrPtr); arrPtr.len:=refsize END BuildModBlock;ÿÿÿÿ€8ÀÔ ÿÿÿÿ€8ÀÔxÿÿÿÿ€8ÀÔMþÿÿ€8ÀÔ#Syntax10.Scn.Fnt‘‘Files.ReadLInt(R,refsize); Files.ReadInt(R,nofexp); Files.ReadInt(R,nofdesc); Files.ReadInt(R,nofcom); Files.ReadInt(R,nofptr); Files.ReadNum(R,nofimp); Files.ReadNum(R,newreclink); Files.ReadNum(R,newsyslink); Files.ReadNum(R,newarrlink); Files.ReadNum(R,datalink); Files.ReadNum(R,datasize); Files.ReadNum(R,consize); Files.ReadNum(R,codesize); Files.ReadString(R,modname); codesize:=4*codesize; ÿÿÿÿ€8ÀÔVÿÿÿ€8ÀÔ#Syntax10.Scn.Fntˆˆ ImpBlk=81X {name}. The import block contains a list of module names to import. They are all loaded calling recursively Load. ÿÿÿÿ€8ÀÔÎùÿÿ€8ÀÔ³Syntax10.Scn.FntpSyntax10b.Scn.Fnt xP[<}0Oߌ€Block(81X); FOR i:=0 TO nofimp-1 DO Files.ReadString(R,impname); Load(impname,imps[i]); IF res#done THEN RETURN END; END; (* Check, if the imports before caused the module this module to load itself, i.e. a cyclic import is present. *) m:=modules; WHILE (m#NIL) & (modname#m.name) DO m:=m.next END; IF m#NIL THEN (* cyclic load, done *) RETURN; END; (* Allocate the module descriptor, and the necessary space for the module itself. *) NEW(m); IF m=NIL THEN importing:=""; res:=notEnoughSpace; RETURN; END; k:=((LONG(nofexp)*SIZE(Export)+35) DIV 16 +(LONG(nofdesc)*4+35) DIV 16 +(LONG(nofcom)*SIZE(Cmd)+35) DIV 16 +(LONG(nofptr)*4+35) DIV 16 +((nofimp+1)*4+35) DIV 16 +(datasize+(-datasize) MOD 8+consize+35) DIV 16 +(codesize+35) DIV 16 +(refsize+35) DIV 16 )*16; SYSTEM.NEW(arrPtr,k); IF arrPtr=NIL THEN importing:=modname; m:=NIL; res:=notEnoughSpace; RETURN; END; (* Link the module into the module list. *) m.next:=modules; modules:=m; m.name:=modname; m.init:=FALSE; m.refcnt:=0; (* Set up all internal pointers, and the module descriptor. BuildModBlocks is a local procedure, which uses and modifies m and arrPtr. Then copy the import pointers from the local variable into the module block. *) BuildModBlock; m.imports[0]:=SYSTEM.ADR(m^); FOR i:=0 TO nofimp-1 DO m.imports[i+1]:=SYSTEM.ADR(imps[i]^); INC(imps[i].refcnt); END; ÿÿÿÿ€8ÀÔJþÿÿ€8ÀÔ#Syntax10.Scn.Fnt”” ExpBlk=82X {EConst|EType|EVar|EProc|ECProc|EStruct|TDesc|LinkProc} 0X. EConst=1X name fprint. ETyoe=2X name fprint. EVar=3X name fprint offset. EProc 4X name fprint entry. ECProc=5X name fprint. EStruct=6X name pbfprint pvfprint. TDesc=8X (name|0X pvprint) link recsize (-1|basemod (name|0X pvfprint)) nofmth nofinhmth nofnewmth nofptr {mthno entry} {ptroff}. LinkProc=9X entry link. ÿÿÿÿ€8ÀÔ úÿÿ€8ÀÔ³Syntax10.Scn.FntR< WSyntax10b.Scn.Fnt’&ˆW j ‘8®Block(82X); linknr:=0; expnr:=0; descnr:=0; Files.Read(R,ch); WHILE ch#0X DO (* character decides, which kind of export it is. *) IF ch=8X THEN (* TDesc *) ReadType(m.tdescs[descnr]); INC(descnr); IF res#done THEN Delete(m); m:=NIL; RETURN; END; ELSIF ch=9X THEN (* LinkProc *) Files.ReadNum(R,entry); links[linknr].entry:=SYSTEM.ADR(m.code[0])+4*entry; Files.ReadNum(R,links[linknr].link); INC(linknr); ELSE (* All other start with name fprint *) Files.ReadString(R,m.exports[expnr].name); Files.ReadNum(R,m.exports[expnr].fprint); m.exports[expnr].mode:=ORD(ch); IF ch=3X THEN (* EVar *) (* The variable offset is read and added to the static base to get the absolute address of the variable. *) Files.ReadNum(R,entry); m.exports[expnr].adr:=m.sb+entry; ELSIF ch=4X THEN (* EProc *) Files.ReadNum(R,entry); m.exports[expnr].adr:=SYSTEM.ADR(m.code[0])+4*entry; ELSIF ch=6X THEN (* EStruct *) INC(expnr); m.exports[expnr].mode:=7; m.exports[expnr].name:=m.exports[expnr-1].name; Files.ReadNum(R,m.exports[expnr].fprint); (* pvfprint *) END; INC(expnr); END; Files.Read(R,ch); END; ÿÿÿÿ€8ÀÔxÿÿÿ€8ÀÔ#Syntax10.Scn.Fntff CmdBlk=83X {name entry}. Entry is an LONGINT offset relative to the start of the code block. ÿÿÿÿ€8ÀÔ=ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt¡¡Block(83X); t:=SYSTEM.ADR(m.code[0]); FOR i:=0 TO nofcom-1 DO Files.ReadString(R,m.cmds[i].name); Files.ReadNum(R,entry); m.cmds[i].adr:=t+4*entry; END; ÿÿÿÿ€8ÀÔŠÿÿÿ€8ÀÔ#Syntax10.Scn.FntTT PtrBlk=84X {off}. All offsets are relative to the start of the data block. ÿÿÿÿ€8ÀÔ€ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt^^Block(84X); t:=m.sb; FOR i:=0 TO nofptr-1 DO Files.ReadNum(R,k); m.ptrTab[i]:=t+k; END; ÿÿÿÿ€8ÀÔ'ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt·· ConstBlk=87X {con:1}. Constant data area. This area is at the beginning of the data area, and may have any length, i.e. not necessarly a multiple of the size of a LONGINT. ÿÿÿÿ€8ÀÔÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt]]Block(87X); FOR i:=0 TO consize-1 DO Files.Read(R,ch); SYSTEM.PUT(t,ch); INC(t); END;ÿÿÿÿ€8ÀÔ‚ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt\\ CodeBlk=88X {instr:4}. The bytes forming a code area. Its size is a multiple of 4. ÿÿÿÿ€8ÀÔþÿÿ€8ÀÔ1Syntax10.Scn.Fnt×6§´Block(88X); t:=SYSTEM.ADR(m.code[0]); FOR i:=0 TO codesize-1 BY 4 DO Files.ReadLInt(R,k); SYSTEM.PUT(t,k); INC(t,4); END; WHILE linknr>0 DO DEC(linknr); Fixup(m,links[linknr].entry,links[linknr].link,FALSE) END; (* Fixup all referencs to the kernel routines. *) Fixup(m,KernelRoutines[0],newreclink,FALSE); Fixup(m,KernelRoutines[1],newsyslink,FALSE); Fixup(m,KernelRoutines[2],newarrlink,FALSE); Fixup(m,m.sb,datalink,TRUE); ÿÿÿÿ€8ÀÔ‡þÿÿ€8ÀÔ#Syntax10.Scn.FntWW UseBlk=89X {{UConst|UType|UVar|UProc|UCProc|UpbStr|UpvStr|LinkTD} 0X}. UConst=1X name fprint. UType=2X name fprint. UVar=3X name fprint link. UProc=4X name fprint link. UCProc=5X name fprint. UpbStr=6X name pbfprint. UpvStr=7X name pvfprint. LinkTD=8X (name | 0X pvfprint) link. The finger prints of all used objects. ÿÿÿÿ€8ÀÔœúÿÿ€8ÀÔCSyntax10.Scn.FntÂSyntax10b.Scn.FntZ"Block(89X); FOR i:=0 TO nofimp-1 DO m1:=SYSTEM.VAL(Module,m.imports[i+1]); curexp:=SYSTEM.VAL(ExportPtr,SYSTEM.ADR(m1.exports^)); limexp:=SYSTEM.VAL(ExportPtr,SYSTEM.VAL(ADDRESS,curexp)+LEN(m1.exports^)*SIZE(Export)); curtd:=SYSTEM.ADR(m1.tdescs^); limtd:=curtd+LEN(m1.tdescs^)*4; Files.Read(R,ch); WHILE ch#0X DO Files.ReadString(R,name); Files.ReadNum(R,fprint); CASE ch OF | 1X,2X,5X,6X,7X:FindExp(ORD(ch),name,fprint,entry); link:=-1 | 3X,4X:FindExp(ORD(ch),name,fprint,entry); Files.ReadNum(R,link); data:=ch=3X | 8X:IF name="" THEN Files.ReadNum(R,link) ELSE link:=fprint; fprint:=0 END; FindTDesc(name,fprint,entry); data:=TRUE END; IF res#done THEN importing:=m.name; imported:=m1.name; IF res=fpMismatch THEN Console.Str(m.name); Console.Str(" imports "); Console.Str(objmode); Console.Ch(" "); Console.Str(m1.name); Console.Ch("."); Console.Str(object); Console.Str(" with bad fingerprint") ELSE Console.Str(objmode); Console.Ch(" "); Console.Str(m1.name); Console.Ch("."); IF object="" THEN Console.Str("'anonymous'") ELSE Console.Str(object) END; Console.Str(" not found") END; Console.Ln; Delete(m); m:=NIL; RETURN END; IF link#-1 THEN Fixup(m,entry,link,data) END; Files.Read(R,ch) END; END; ÿÿÿÿ€8ÀÔmÿÿÿ€8ÀÔ#Syntax10.Scn.Fntqq RefBlk=8AX {0F*X procend savedr savedf frame callarea name {Mode Form adr name}}. Reference information ÿÿÿÿ€8ÀÔfÿÿÿ€8ÀÔ#Syntax10.Scn.FntxxBlock(8AX); t:=SYSTEM.ADR(m.refs[0]); FOR i:=0 TO refsize-1 DO Files.Read(R,ch); SYSTEM.PUT(t,ch); INC(t); END; ÿÿÿÿ€8ÀÔj93&D?ÿÿÿÿ€8ÀÔ H]P”•è }Zµ"'%7m$*a +#%s^"T1ÁE€N‘+ËX¿eB;Ø<¾™ÿÿÿ€8ÀÔ#Syntax10.Scn.FntEE Initialise module bodies of modules contained in the boot file. ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ‹J2>|kJ'ÿÿÿÿ€8ÀÔ #;f-MODULE Modules; (* RC 14.2.94 *) (* object model *) (* The module loader. Limitations A module may import no more than 32 other modules. *) IMPORT SYSTEM ,Console,Files,Kernel,Unix; CONST ModNameLen*=32; TYPE ADDRESS=LONGINT; Name*=ARRAY ModNameLen OF CHAR; ModuleName*=Name; Command*=PROCEDURE; Export*=RECORD name*:Name; fprint*:LONGINT; adr*:ADDRESS; mode*:INTEGER END; Cmd*=RECORD name*:Name; adr*:ADDRESS END; Module*=POINTER TO ModuleDesc; ModuleDesc*=RECORD next*:Module; name*:Name; init*:BOOLEAN; refcnt*,sb*:LONGINT; exports*:POINTER TO ARRAY OF Export; tdescs*:POINTER TO ARRAY OF (* Kernel.Tag *) ADDRESS; cmds*:POINTER TO ARRAY OF Cmd; ptrTab*:POINTER TO ARRAY OF ADDRESS; imports*:POINTER TO ARRAY OF (* Module *) ADDRESS; data*,code*:POINTER TO ARRAY OF LONGINT; refs*:POINTER TO ARRAY OF CHAR END; VAR modules*:Module; imported*:Name; importing*:Name; object*:Name; objmode*:Name; res*:INTEGER; CONST done=0; fileNotFound=1; notAnObjFile=2; fpMismatch=3; corruptedObjFile=4; cmdNotFound=5; modNotFound=6; notEnoughSpace=7; refCntNotZero=8; objNotFound=10; tooManyFiles=11; (* instruction format *) IMM=10000H; JAL=0C000000H; LUI=03C000000H; OP=04000000H; RS=200000H; RT=10000H; ExtTabWordSize=16; Tag0WordOffset=-2; Mth0WordOffset=Tag0WordOffset-ExtTabWordSize; VAR KernelRoutines:ARRAY 3 OF ADDRESS; (* Address of Kernel NewXXX procedures *) loop:Command; modeStr:ARRAY 9 OF Name; PROCEDURE FindRoots; (**) PROCEDURE FindAmbRoots; (**) PROCEDURE Fixup(m:Module; entry,L:LONGINT; data:BOOLEAN); PROCEDURE Delete(m:Module); PROCEDURE ^Load(name:ARRAY OF CHAR; VAR m:Module); PROCEDURE LoadModule(VAR R:Files.Rider; VAR m:Module); (**) TYPE TDescBlock=POINTER TO RECORD word:ARRAY 32000 OF LONGINT; END; TDescDesc=POINTER TO RECORD tdsize,sentinel,self:LONGINT; ext:RECORD extlev:SHORTINT; filler:ARRAY 3 OF CHAR; END; name:Name; mdesc:Module; pvfprint:LONGINT; END; Type=RECORD tdb:TDescBlock; link,root,nofmeth,nofinhmeth,bmno,bpvfp:LONGINT; bname:Name; END; ExportPtr=POINTER TO Export; ArrPtr=POINTER TO RECORD a,b,c,len,data:LONGINT; END; VAR i,entry,link,fprint,k,t,curtd,limtd:LONGINT; m1:Module; data:BOOLEAN; curexp,limexp:ExportPtr; refsize,nofimp,newreclink,newsyslink,newarrlink,datalink,datasize,consize,codesize:LONGINT; nofexp,nofdesc,nofcom,nofptr,linknr,expnr,descnr:INTEGER; name:Name; ch:CHAR; body:Command; links:ARRAY 256 OF RECORD entry,link:LONGINT; END; imps:ARRAY 32 OF Module; (* Remember imported modules. *) types:ARRAY 128 OF Type; arrPtr:ArrPtr; modname,impname:Name; PROCEDURE Block(tag:CHAR); (**) PROCEDURE ReadType(VAR tdesc:ADDRESS); PROCEDURE FindExp(mode:INTEGER; VAR name:Name; fprint:LONGINT; VAR adr:LONGINT); PROCEDURE FindTDesc(VAR name:Name; fprint:LONGINT; VAR adr:LONGINT); PROCEDURE InitType(tdesc:ADDRESS; VAR type:Type); VAR l,r,t,k,base,tag,root,n,entry,pvfp:LONGINT; mb:Module; tdb:TDescBlock; tdd:TDescDesc; BEGIN tdb:=type.tdb; IF tdb#NIL THEN (* not done yet *) type.tdb:=NIL; Fixup(m,tdesc,type.link,TRUE); k:=0; root:=type.root; base:=type.bmno; IF base#-1 THEN mb:=SYSTEM.VAL(Module,m.imports[base]); IF type.bname="" THEN pvfp:=type.bpvfp; t:=-1; REPEAT (* tdesc always present since local *) INC(t); SYSTEM.GET(mb.tdescs[t]-4,tdd) UNTIL tdd.pvfprint=pvfp ELSE l:=0; r:=LEN(mb.tdescs^)-1; LOOP IF l>r THEN EXIT; END; t:=(l + r) DIV 2; SYSTEM.GET(mb.tdescs[t]-4,tdd); IF type.bname < tdd.name THEN r:=t-1; ELSIF type.bname>tdd.name THEN l:=t + 1; ELSE EXIT; END; END; IF l>r THEN importing:=m.name; imported:=mb.name; object:=type.bname; bjmode:=modeStr[8]; res:=objNotFound; RETURN; END; END; IF base=0 THEN InitType(mb.tdescs[t],types[t]); (* res always 0 here *) END; base:=mb.tdescs[t]; SYSTEM.GET(base+Tag0WordOffset*4,tag); WHILE tag#0 DO tdb.word[root+Tag0WordOffset-k]:=tag; INC(k); SYSTEM.GET(base+(Tag0WordOffset-k)*4,tag); END; n:=type.nofinhmeth; WHILE n>0 DO DEC(n); entry:=tdb.word[root+Mth0WordOffset-n]; IF entry=0 THEN SYSTEM.GET(base+(Mth0WordOffset-n)*4,tdb.word[root+Mth0WordOffset-n]); END END END; SYSTEM.PUT(SYSTEM.ADR(tdb.word[3]),SHORT(SHORT(k))); (* ok for little and big endian *) tdb.word[root + Tag0WordOffset-k]:=SYSTEM.ADR(tdb.word[root]); (* INC(k); WHILE k < ExtTabWordSize DO tdb.word[root+Tag0WordOffset-k]:=0; INC(k); END; *) END END InitType; PROCEDURE BuildModBlock; (**) BEGIN (* ASSERT((m=NIL)&(res=done)); *) (* ObjFile=OFtag HeaderBlk ImpBlk ExpBlk CmdBlk PtrBlk ConstBlk CodeBlk UseBlk RefBlk. OFtag=0F9X 36X. HeaderBlk=refsize:4 nofexp:2 noftdesc:2 nofcom:2 nofptr:2 nofimp newreclink newsyslink newarrlink datalink datasize consize codesize modname. The object file starts with a header containing size/number of elements of the different parts and the module name. *) Header block (**) Import block (**) Export block (**) Command block (**) Pointer block (**) Constant block (**) Code block (**) Use block (**) Ref block (* init types *) FOR i:=0 TO LEN(m.tdescs^)-1 DO InitType(m.tdescs[i],types[i]); IF res#done THEN Delete(m); m:=NIL; RETURN END; (* Terminate if types could not be initialised (why ?) *) END; (* execute body *) body:=SYSTEM.VAL(Command,SYSTEM.ADR(m.code[0])); (* command 0 points to module body. *) m.init:=TRUE; Unix.Cacheflush(SYSTEM.ADR(m.code[0]),codesize,1); (* Make sure instruction cache does not contain invalid data *) body; (* Call module body *) res:=done; END LoadModule; PROCEDURE Load(name:ARRAY OF CHAR; VAR m:Module); VAR f:Files.File; fname:ARRAY 64 OF CHAR; i:INTEGER; R:Files.Rider; state:BOOLEAN; tag:INTEGER; BEGIN (* Try to find the module in the list of already loaded modules. *) m:=modules; res:=done; WHILE (m#NIL) & (name#m.name) DO m:=m.next; END; IF m=NIL THEN (* Create the object file name, by appending .Obj to the module name. *) COPY(name,fname); i:=0; WHILE fname[i]#0X DO INC(i); END; fname[i]:="."; fname[i+1]:="O"; fname[i+2]:="b"; fname[i+3]:="j"; fname[i+4]:=0X; (* Perform a garbage collection to prevent running out of file handles. Terminate with an error, if not enough file handles were freed. *) IF Kernel.nofiles>=Unix.OpenMax-4 THEN state:=Kernel.GCenabled; Kernel.GCenabled:=TRUE; Kernel.GC(TRUE); Kernel.GCenabled:=state; END; IF Kernel.nofiles>=Unix.OpenMax-4 THEN importing:=""; res:=tooManyFiles; RETURN; END; (* Try to open the file. If it's found and really an object file, call LoadModules to actually load the module. *) f:=Files.Old(fname); IF f=NIL THEN COPY(fname,importing); res:=fileNotFound; RETURN; END; Files.Set(R,f,0); Files.ReadInt(R,tag); IF tag=36F9H THEN LoadModule(R,m); ELSE COPY(fname,importing); res:=notAnObjFile; END END; END Load; PROCEDURE ThisMod*(name:ARRAY OF CHAR):Module; (* Load the specified module. *) VAR mod:Module; state:BOOLEAN; BEGIN (* Free as much memory as possible,as the garbage collector is disabled during Load. Why disabled ??? This will cause problems for a loader which requests memory from the host OS on demand. *) Kernel.GC(TRUE); (* Remeber state before diabling,in case ThisMod is called recursively. *) state:=Kernel.GCenabled; Kernel.GCenabled:=FALSE; Load(name,mod); Kernel.GCenabled:=state; RETURN mod END ThisMod; PROCEDURE ThisCommand*(mod:Module; name:ARRAY OF CHAR):Command; (* Searches a modules command list,to find the address of a command. *) VAR i:LONGINT; BEGIN i:=LEN(mod.cmds^); WHILE i>0 DO DEC(i); IF mod.cmds[i].name=name THEN res:=done; RETURN SYSTEM.VAL(Command,mod.cmds[i].adr); END; END; COPY(name,importing); res:=cmdNotFound; RETURN NIL; END ThisCommand; PROCEDURE Free*(name:ARRAY OF CHAR; all:BOOLEAN); VAR i:LONGINT; m,m1:Module; BEGIN res:=done; (* Search module to free,and if found verify,that it is not referenced by some other modules,i.e. has refcnt#0. *) m:=modules; WHILE (m#NIL) & (name#m.name) DO m:=m.next END; IF m=NIL THEN COPY(name,importing); res:=modNotFound; ELSIF m.refcnt#0 THEN importing:=m.name; res:=refCntNotZero; ELSE (* Decrease refcnt of all modules, which this one imports. *) i:=LEN(m.imports^); WHILE i>1 DO DEC(i); m1:=SYSTEM.VAL(Module,m.imports[i]); DEC(m1.refcnt); END; IF all THEN (* Try to recursively free also all modules this module imports. *) i:=LEN(m.imports^); WHILE i>1 DO DEC(i); m1:=SYSTEM.VAL(Module,m.imports[i]); Free(m1.name,TRUE); END; res:=done; END; (* Unlink the module descriptor. *) m1:=modules; (* recursive call may change list structure *) IF m1=m THEN modules:=m.next; ELSE WHILE m1.next#m DO m1:=m1.next; END; m1.next:=m.next; END END END Free; PROCEDURE Init; (* Init is called in replacement of the module body initialisation. See CallBodies. *) VAR modPtr,cmdPtr:POINTER TO RECORD name:Name END; newRec:PROCEDURE(tag:Kernel.Tag):ADDRESS; newSys:PROCEDURE(size:LONGINT):ADDRESS; newArr:PROCEDURE(eltag:Kernel.Tag; nofelem,nofdim:LONGINT):ADDRESS; BEGIN modeStr[1]:="constant"; modeStr[2]:="type"; modeStr[3]:="variable"; modeStr[4]:="procedure"; modeStr[5]:="code procedure"; modeStr[6]:="public structure of"; modeStr[7]:="private structure of"; modeStr[8]:="type descriptor of"; (* Install the Kernel callbacks for finding all root pointers and stack pointer candidates. *) Kernel.FindRoots:=FindRoots; Kernel.FindAmbRoots:=FindAmbRoots; (* Remember Kernel New procedures for module fixup. *) newRec:=Kernel.NewRec; newSys:=Kernel.NewSys; newArr:=Kernel.NewArr; KernelRoutines[0]:=SYSTEM.VAL(ADDRESS,newRec); KernelRoutines[1]:=SYSTEM.VAL(ADDRESS,newSys); KernelRoutines[2]:=SYSTEM.VAL(ADDRESS,newArr); (* init loop only if Modules is last module in boot file:*) Unix.dlsym(0,"modPtr",SYSTEM.VAL(LONGINT,modPtr)); Unix.dlsym(0,"cmdPtr",SYSTEM.VAL(LONGINT,cmdPtr)); loop:=ThisCommand(ThisMod(modPtr.name),cmdPtr.name); END Init; PROCEDURE CallBodies; (**) TYPE Body=PROCEDURE; VAR m,last:Module; body:Body; i,t:LONGINT; td:POINTER TO RECORD filler:ARRAY 4 OF LONGINT; name:Name; END; BEGIN (* We somehow know,that the first kernel block contains a pointer to the module list. *) modules:=SYSTEM.VAL(Module,Kernel.firstBlock+4); (* Traverse list to end,to find tail of the list. *) last:=modules; WHILE last.next#NIL DO last:=last.next; END; (* Initialise modules in list order. Special treatment for Modules and Kernel. Call Modules.Init instead of its body,as this is already called by the bootstrap. Set Kernel.ptrElemTag to the Tag of type PtrElemDesc. *) m:=modules; LOOP IF m.name="Modules" THEN Init; ELSE IF m.name="Kernel" THEN i:=LEN(m.tdescs^); REPEAT DEC(i); t:=m.tdescs[i]; SYSTEM.GET(t-4,td) UNTIL td.name="PtrElemDesc"; Kernel.ptrElemTag:=t; END; body:=SYSTEM.VAL(Body,SYSTEM.ADR(m.code[0])); body; END; IF m=last THEN EXIT END; m:=m.next; END END CallBodies; BEGIN (* entry of boot file,must not return *) Kernel.Boot; CallBodies; loop; (* call loop only if Modules is last module in boot file *) END Modules.