{##################################} {# PDP11 IMP77 Object file linker #} {# #} {# Copyright November 1981 #} {# Peter S. Robertson #} {# #} {##################################} { 0 1 7 } {*--------*----------*--------*-----------------*-------*---*---------------*} {| Shared | Events | Code |-> Ds ----- Sp <-| Gla |\\\| I/O Segment |} {*--------*----------*--------*-----------------*-------*---*---------------*} { ^ ^ ^ ^ } { | | | | } { #Event #Code #Stack #Gla } { Base Base Base Base } { I/O STREAMS } %CONSTINTEGER Fixup Stream= 6 %EXTERNALROUTINE dLINK11 %alias "c#dlink11"(%STRING (63) Dummy) %ROUTINE destroy(%STRING (255) s) %EXTERNALROUTINESPEC emas3(%STRINGNAME command,params, %INTEGERNAME flag) %INTEGER flag emas3("DESTROY",s,flag) %END; ! Of %ROUTINE destroy. %ROUTINE run(%STRING (255) s) %EXTERNALROUTINESPEC emas3(%STRINGNAME command,params, %INTEGERNAME flag) %INTEGER flag emas3("RUN",s,flag) %END; ! Of %ROUTINE run. %ROUTINE define(%STRING (255) s) %EXTERNALROUTINESPEC emas3(%STRINGNAME command,params, %INTEGERNAME flag) %INTEGER flag emas3("DEFINE",s,flag) %if flag # 0 %start printstring("Define ".s." Fails:"); write(flag, 1); newline %finish %END; ! Of %ROUTINE define. %EXTERNALROUTINESPEC prompt %ALIAS "S#PROMPT"(%STRING (255) s) %EXTERNALINTEGERFUNCTIONSPEC exist %ALIAS "S#EXIST"(%STRING (255) file) %EXTERNALINTEGERFNSPEC smaddr(%INTEGER chan, %INTEGERNAME length) %EXTERNALSTRING (63) %FNSPEC ItoS %alias "s#itos"(%INTEGER N) %CONSTINTEGER commands= 1, source = 3, map = 2, object = 21 %CONSTINTEGER FID Size= 26, REF Size = 14, Max Items = 900, Max Module = 100, Max File = 20 { *-------*-----*} { | FILES | END |} { *---+---*--+--*} { | |} { | *----------------------------*} { | |} { V V} { *------*---* *------*---* *------*---*} { *-->| FILE | *-+----> | FILE | *-+----> | FILE | |} { | *--+---*---* *--+---*---* *--+---*---*} { | | | |} { | |} { | V} { | *--------*---*---*} { *---| MODULE | * | *-+---> References} { *--+-----*-+-*---*} { | | ^} { | | |} { | | *-------*----------------*} { | | | |} { | | *--+--*---* *--+--*---*} { | *--------| DEF | *-+----> | DEF | *-+----> ....} { | *-----*---* *-----*---*} { V} { Etc} %OWNSTRING (FID Size) Default Perm= "ercm09:dimp11y.Perm11#Rel" {%constrecord(*)%name Null == 0 Blast!} %RECORDFORMAT Itemfm(%STRING (REF Size) Text, %BYTE Area,Used, %INTEGER Displacement, %RECORD (Modulefm) %NAME M, %RECORD (Itemfm) %NAME Chain,Link) %CONSTRECORD (Itemfm) %NAME Null= 0 %RECORD (Itemfm) %ARRAY Items(1:Max Items) %OWNINTEGER Max Item= 0, Min Item = Max Items+1 %RECORD (Itemfm) %NAME Unsatisfied %OWNSTRING (15) EpId= "P#START" %OWNINTEGER Entry Point= 1 %OWNSTRING (15) Shared= "", Fixup File = "" %CONSTINTEGER IO stream size= K'1030', default streams = 4 %OWNINTEGER n streams= default streams %OWNINTEGER stackseg= -1, code seg = -1 %OWNINTEGER gla seg= -1 %OWNINTEGER Shared Code Size,Shared Gla Size=K'1540', IO Size = IO stream size * default streams {default} %STRING (4) default taskname %STRING (63) File %OWNRECORD (Itemfm) EpTop %INTEGER More %OWNINTEGER Code Base,Code Size= 0, Gla Base, Gla Size = 0, Event Base, Event Size = 0, Stack Base, Stack Size = 8192, {default 2K} Initial Sp %CONSTINTEGER Deimos Unused= 4, Deimos Read Only = 5, Deimos Read Write = 6, Deimos Shared = 7 %RECORDFORMAT Segfm(%INTEGER Mode,Size) %RECORDFORMAT Deimos Header Fm(%STRING (4) Task Id, %INTEGER Initial Sp, %RECORD (Segfm) %ARRAY Seg(0:7)) %RECORD (Deimos Header Fm) Deimos Header { Library and fixup files to be scanned } %CONSTSTRING (FID Size) Share Lib= "ercm09:dimp11y.SHR#REL", Share Fix = "ercm09:dimp11y.SHR#FIX", Non Share Lib = "ercm09:dimp11y.IMP#REL", Non Share Fix = "ercm09:dimp11y.IMP#FIX" %OWNINTEGER Squeeze= 0 {compress store requirements} %OWNINTEGER Deimos= 1 {0 if stand alone} %OWNINTEGER Rom= 0, {#0 if romable file wanted} Glap = 0 {bias for loading gla} %OWNINTEGER Low= 0, High = 0 { Bits in DEIMOS flag word } %CONSTINTEGER ALONE BIT= 1, {.ALONE} No Share BIT = 2, {Dont use shared library} NOINIT BIT = 4, {Dont initialise IO streams at startup} Makeshare BIT = 8 {Makeshare - so dont dump DISPLAY etc} %RECORDFORMAT Modulefm(%RECORD (Itemfm) %NAME Definitions,References, %INTEGER Code Area Size,Code Base,Gla Area Size,Gla Base, Diag Area Size,Diag Base,Line Area Size,Line Base,Event Area Size, Event Base,Used,Number of Refs,ref address, %STRING (15) Section, %RECORD (Filefm) %NAME F, %RECORD (Modulefm) %NAME Link) %RECORD (Modulefm) %ARRAY Modules(1:Max Module) %OWNINTEGER ModuleP= 0 %RECORDFORMAT Filefm(%STRING (FID Size) File, %INTEGER Used, %RECORD (Modulefm) %NAME Modules, %RECORD (Filefm) %NAME Link) %RECORD (Filefm) %ARRAY Files(1:Max File) %OWNINTEGER FileP= 0 %RECORD (Filefm) File Head,Shared Head,Fixup Head %RECORD (Filefm) %NAME File End,Shared End,Fixup End %OWNINTEGER Sym= ' ', Area = 0 %STRING (31) Infile,Mapfile %OWNSTRING (63) Word %INTEGER J %RECORDFORMAT HashPfm(%RECORD (Itemfm) %NAME P) %RECORDFORMAT Hashfm(%RECORD (HashPfm) %ARRAY A(0:518)) %RECORD (Hashfm) Hash %ROUTINE Fail(%STRING (63) Why) Select output(0) Printstring("*Link11 fails -- ".Why) Newline %MONITOR %STOP %END %ROUTINE Read Octal(%INTEGERNAME N) %INTEGER Sym N = 0 Skipsymbol %WHILE Nextsymbol=' ' %OR Nextsymbol=nl %RETURNUNLESS '0'<=Nextsymbol<='7' %CYCLE Readsymbol(Sym) N = N<<3+(Sym-'0') %REPEATUNTILNOT '0'<=Nextsymbol<='7' %END %ROUTINE Print Octal(%INTEGER N) %INTEGER J N = N&x'FFFF' Printch(N>>J&7+'0') %FOR J = 15,-3,0 %END %INTEGERFN Hash Key(%STRING (*) %NAME S) %INTEGER Key,J,L L = Length(S) Key = -L %FOR J = 1,1,L %CYCLE Key = Key<<1+Charno(S,J) %REPEAT Key = Key&((-1)>>1) Key = Key-Key//519*519 %RESULT = Key %END {%record(Filefm)%map} %INTEGERFN New File %RECORD (Filefm) %NAME F Fail("Too many files") %IF FileP=Max File FileP = FileP+1 F == Files(FileP) F = 0 %RESULT = Addr(F) %END %ROUTINE Append Fixup File(%STRING (FID Size) File) %RECORD (Filefm) %NAME P %RETURNIF File="" P == Record(New File) P_File = File Fixup End_Link == P Fixup End == P %END %ROUTINE Append File(%STRING (FID Size) File) %RECORD (Filefm) %NAME P %RETURNIF File="" P == Record(New File) P_File = File File End_Link == P File End == P %END %INTEGERFN Existence(%STRING (63) %NAME File) %IF Exist(File."#REL")=1 %THEN File = File."#REL" %ANDRESULT = -1 %IF Exist(File)=1 %THENRESULT = -1 Printstring("Cannot access ".File) Newline %RESULT = 0 %END %ROUTINE Read Sym Readch(Sym) Sym = Sym-32 %IF 'a'<=Sym<='z' %END %ROUTINE Read Word Word = "" %CYCLE %IF Sym=' ' %OR Sym=NL %START %RETURNIF Word#"" %FINISHELSESTART Word = Word.Tostring(Sym) %FINISH Read Sym %REPEAT %END %ROUTINE Skip Line Readsym %WHILE Sym=' ' %IF Sym#NL %START Printch('`') %CYCLE Printch(Sym) Readsym %REPEATUNTIL Sym=NL Printstring("` ignored"); Newline %FINISH %END %ROUTINE Process Commands %CYCLE Prompt("Link: ") Read Word %IF Charno(Word,1)#'.' %START {file} Append File(Word) %IF Existence(Word)#0 %FINISHELSESTART %EXITIF Word=".END" %IF Word=".ROM" %START Rom = -1 EpId = "P#ROMSTART" %FINISH %IF Word=".ALONE" %OR Rom<0 %START Rom = 1 %IF Rom<0 Deimos = 0; Shared = "" Prompt("Small address:"); Read Octal(Low) Prompt("Large address:"); Read Octal(High) %IF (Low>>1)&8_77777>(High>>1)&8_77777 %START Printstring("Store inside-out") Newline %FINISH %FINISHELSEIF Word=".MAKESHARE" %START DEIMOS = Makeshare Bit!No Share Bit Stack size = 0 Low = 0 High = k'20000' %FINISHELSEIF Word=".STREAMS" %START Prompt("Streams: ") Read Octal(n streams) IO Size = n streams*IO stream size %FINISHELSEIF Word=".GLA7" %START Gla Seg = 7 %FINISHELSEIF Word=".CODESEG" %START read(code seg) %UNLESS 0<=code seg<7 %START printstring("Code segment must be 0 to 6") newline code seg = -1 %FINISH %FINISHELSEIF Word=".STACKSEG" %START read(stack seg) %UNLESS 1("#REL") Shared = Word %IF Existence(Word)#0 %FINISHELSEIF Word=".FIXUP" %START Read Word Append Fixup File(Word) %IF Existence(Word)#0 %FINISHELSESTART Printstring(Word." not known"); Newline %FINISH %FINISH Skip Line %REPEAT Prompt("Object file: ") read word; %IF word->("#") %THEN file <- word %ELSE file <- word."#ABS" file -> word.("#") default taskname <- word." " Skip Line %IF DEIMOS#0 %START %IF DEIMOS&Noshare Bit=0 %START Append File(Share Lib) Append Fixup File(Share Fix) %FINISHELSESTART Append File(Non Share Lib) Append Fixup File(Non Share Fix) %FINISH %FINISH Append File(Default Perm) %IF %C Default Perm#"" %AND Existence(Default Perm)#0 %END %ROUTINE Open for Input(%RECORD (Filefm) %NAME F) Define("ST3,".F_File) Select Input(3) %END %ROUTINE Finished with File Select Input(0) Close Stream(3) %END %INTEGERFN Two Bytes(%BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %INTEGER L,H L = BUF(ptr+1); H = BUF(ptr+2); ptr = ptr+2 %RESULT = H<<8+L %END %ROUTINE Get String(%STRING (*) %NAME S, %BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %STRING (255) os %INTEGER L,Sym os = "" ptr = ptr+1; L = BUF(ptr) %WHILE L>0 %CYCLE L = L-1 ptr = ptr+1; Sym = BUF(ptr) os = os.Tostring(Sym) %REPEAT S <- os %END {%record(Itemfm)%map} %INTEGERFN New Item %RECORD (Itemfm) %NAME I Min Item = Min Item-1 Fail("Too many references and definitions") %IF Min Item=Max Item I == Items(Min Item) I = 0 %RESULT = Addr(I) %END {%record(Itemfm)%map} %INTEGERFN New Def %RECORD (Itemfm) %NAME I Max Item = Max Item+1 Fail("Too many references and definitions") %IF Min Item=Max Item I == Items(Max Item) I = 0 %RESULT = Addr(I) %END %ROUTINE Next Definition(%RECORD (Modulefm) %NAME M, %BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %RECORD (Itemfm) %NAME R R == Record(New Def) R_M == M R_Link == M_Definitions M_Definitions == R ptr = ptr+1; R_Area = BUF(ptr) R_Displacement = Two Bytes(BUF,ptr) Get string(R_Text,BUF,ptr) %END %ROUTINE Get External Definitions(%RECORD (Modulefm) %NAME M, %BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %INTEGER N N = Two Bytes(BUF,ptr) %WHILE N>0 %CYCLE Next Definition(M,BUF,ptr) N = N-1 %REPEAT %END %ROUTINE Next Reference(%RECORD (Modulefm) %NAME M, %BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %RECORD (Itemfm) %NAME R R == Record(New Item) R_M == M R_Link == M_References M_References == R Get String(R_Text,BUF,ptr) %END %ROUTINE Get External References(%RECORD (Modulefm) %NAME M, %BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %INTEGER N M_ref address = ptr N = Two Bytes(BUF,ptr) M_Number of Refs = N %WHILE N>0 %CYCLE Next Reference(M,BUF,ptr) N = N-1 %REPEAT %END {%record(Modulefm)%map} %INTEGERFN New Module %RECORD (Modulefm) %NAME M Fail("Too many modules") %IF ModuleP=Max Module ModuleP = ModuleP+1 M == Modules(ModuleP) M = 0 %RESULT = Addr(M) %END %ROUTINE Insert Dummy File %RECORD (Modulefm) %NAME M %RECORD (Itemfm) %NAME R Append File("?") M == Record(New Module) M_F == File End File End_Modules == M {add the entry reference} R == Record(New Item) R_M == M M_References == R R_Text = EpId {add the standard definitions} %ROUTINE Define(%STRING (FID Size) Id) %RECORD (Itemfm) %NAME R R == Record(New Def) R_Text = Id R_M == M R_Link == M_Definitions R_Used = 1; !We always want to see these symbols M_Definitions == R %END Define("#IOAREA") Define("#IOTOP") Define("#NSTREAMS") Define("#EVENTTOP") Define("#EVENTBASE") Define("#CODEBASE") Define("#STACKBASE") Define("#GLABASE") Define("#INITSP") %END %ROUTINE Skip Module Body(%BYTEINTEGERARRAYNAME BUF, %INTEGERNAME ptr) %SWITCH T(0:15) %INTEGER S %CYCLE T(5): T(6): T(10): ptr = ptr+1; S = BUF(ptr) ->T(S) T(14): ptr = ptr+6 T(1): T(2): T(3): T(4): T(7): T(8): T(9): T(12): T(13): ptr = ptr+1 T(11): ptr = ptr+1 %REPEAT T(15): %END %ROUTINE Get Linkage Information(%RECORD (Filefm) %NAME F, %INTEGER start, length) %BYTEINTEGERARRAYFORMAT BUFFER(1:length) %BYTEINTEGERARRAYNAME BUF %INTEGER ptr %INTEGER Next %RECORD (Modulefm) %NAME M,P %RECORD (Modulefm) Head P == Head BUF == array(start,BUFFER) ptr = 0 %CYCLE M == Record(New Module) M_F == F P_Link == M P == M Next = Two Bytes(BUF,ptr) M_Code Area Size = Two Bytes(BUF,ptr) M_Gla Area Size = Two Bytes(BUF,ptr) M_Diag Area Size = Two Bytes(BUF,ptr) M_Line Area Size = Two Bytes(BUF,ptr) M_Event Area Size = Two Bytes(BUF,ptr) Get String(M_section,BUF,ptr) Get External Definitions(M,BUF,ptr) Get External References(M,BUF,ptr) %EXITIF Next=0 Skip Module Body(BUF,ptr) %REPEAT P_Link == Null F_Modules == Head_Link Finished with File %END %ROUTINE Load Nominated Files %INTEGER start,length %RECORD (Filefm) %NAME F F == File Head_Link %WHILE F##Null %CYCLE Define("ST3,".F_File) start = smaddr(3,length) Get Linkage Information(F,start,length) F == F_Link %REPEAT %END %ROUTINE Load Shared Library %INTEGER start,length Shared Head_Modules == Null %RETURNIF Shared="" Shared Head_Used = 1 Shared Head_File = Shared Define("ST3,".SharedHead_File) start = smaddr(3,length) Get Linkage Information(SharedHead,start,length) %END %ROUTINE Define Item(%RECORD (itemfm) %NAME R, %RECORD (Hashfm) %NAME Hash) %RECORD (HashPfm) %NAME H %RECORD (Itemfm) %NAME P H == Hash_A(Hash Key(R_Text)) P == H_P %WHILE P##Null %CYCLE %IF P_Text=R_Text %START {duplicate} %RETURNIF R_M_F_File=Default Perm %EXITIF P_M_F_File=Shared Printstring("Duplicate definition of ") Printstring(R_Text) Printstring(" in file ") Printstring(R_M_F_File) Newline %RETURN %FINISH P == P_Chain %REPEAT R_Chain == H_P H_P == R %END %ROUTINE Insert Module(%RECORD (Modulefm) %NAME M) %RECORD (Itemfm) %NAME R R == M_Definitions %WHILE R##Null %CYCLE Define Item(R,Hash) R == R_Link %REPEAT %END %ROUTINE Insert File(%RECORD (Filefm) %NAME F) %RECORD (Modulefm) %NAME M M == F_Modules %WHILE M##Null %CYCLE Insert Module(M) M == M_Link %REPEAT %END %ROUTINE Insert Files %RECORD (Filefm) %NAME F F == File Head_Link %WHILE F##Null %CYCLE Insert File(F) F == F_Link %REPEAT %END %ROUTINE Fixup Entries %ROUTINE Get Octal(%INTEGERNAME N) N = 0 Readsym %WHILE Sym=' ' Fail("Bad octal number in fixup for ".Word) %UNLESS '0'<=Sym<='7' %CYCLE N = N<<3+(Sym-'0') Read Sym %REPEATUNTILNOT '0'<=Sym<='7' %END %INTEGER Indirect,N %RECORD (Itemfm) %NAME R %RECORD (Filefm) %NAME F %OWNRECORD (Modulefm) Dummy Module= 0 %OWNRECORD (Filefm) Dummy File= 0 %ON 9 %START ->File Done %FINISH Dummy File_File = "*fixup*" Dummy File_Modules == Null Dummy Module_Used = 1 {to insert names into listing} Dummy Module_F == Dummy File Dummy Module_References == Null F == Fixup Head_Link Next File: %RETURNIF F==Null Open for Input(F) Sym = ' '; !In case rubbish left from previous file %CYCLE Read Word %EXITIF word=".END" Readsym %WHILE Sym=' ' Indirect = 0; Indirect = 1 %AND Readsym %IF Sym='@' Get Octal(N) Fail("Odd fixup for ".Word) %IF N&1#0 Skip Line R == Record(New Def) R_Text = Word R_Displacement = N!Indirect R_Area = 7 R_M == Dummy Module Define Item(R,Hash) %REPEAT File Done: Finished with File F == F_Link ->next file %END {%record(Itemfm)%map} %INTEGERFN Definition of(%RECORD (Itemfm) %NAME R, %RECORD (Hashfm) %NAME Hash) %RECORD (HashPfm) %NAME H %RECORD (Itemfm) %NAME D H == Hash_A(Hash Key(R_Text)) D == H_P %WHILE D##Null %CYCLE %RESULT = Addr(D) %IF D_Text=R_Text D == D_Chain %REPEAT %RESULT = Addr(Null) %END %ROUTINE Follow(%RECORD (Itemfm) %NAME R) %RECORD (Itemfm) %NAME P %RECORD (Modulefm) %NAME M P == Record(Definition of(R,Hash)) %IF P==Null %START R_Chain == Unsatisfied Unsatisfied == R %RETURN %FINISH P_Used = 1 %RETURNIF P==EpTop {not really a module} M == P_M %RETURNIF M_Used#0 M_Used = 1 M_F_Used = 1 R == M_References %WHILE R##Null %CYCLE Follow(R) R == R_Link %REPEAT %END %ROUTINE Allocate Space %INTEGER Event,Cbase,Gbase %ROUTINE Allocate Module(%RECORD (Modulefm) %NAME M) M_Event Base = Event; Event = Event+M_Event Area Size M_Code Base = Cbase; Cbase = Cbase+M_Code Area Size M_Gla Base = Gbase; Gbase = Gbase+M_Gla Area Size %END %ROUTINE Allocate File(%RECORD (Filefm) %NAME F) %RECORD (Modulefm) %NAME M M == F_Modules %WHILE M##Null %CYCLE Allocate Module(M) %IF M_Used#0 M == M_Link %REPEAT %END %ROUTINE Allocate(%RECORD (Filefm) %NAME Head) %RECORD (Filefm) %NAME F F == Head_Link %WHILE F##Null %CYCLE Allocate File(F) %IF F_Used#0 F == F_Link %REPEAT %END %ROUTINE Tot Up %INTEGER J %RECORD (Modulefm) %NAME M %FOR J = 1,1,ModuleP %CYCLE M == Modules(J) %IF M_Used#0 %START Code Size = Code Size+M_Code Area Size Gla Size = Gla Size+M_Gla Area Size Event Size = Event Size+M_Event Area Size %FINISH %REPEAT %END %ROUTINE Allocate Areas Code Base = Low Event Base = Code Base+Code Size Gla Base = Event Base+Event Size Stack Base = Gla Base+Gla Size Initial Sp = Stack Base+Stack Size %IF (Initial Sp>>1)&8_77777>(High>>1)&8_77777 %START Fail("Not enough store") %FINISH %END %ROUTINE Allocate Deimos Shared %INTEGER i Fail("Shared library must not trap events") %IF Event Size>0 Fail("Shared library must have no GLA") %IF Gla Size>0 Fail("Shared library too big") %IF Code Size>k'20000' Deimos header_seg(0)_mode = Deimos Read only Deimos header_seg(0)_size = Code Size %FOR i = 1,1,6 %CYCLE Deimos header_seg(i)_mode = Deimos Unused Deimos header_seg(i)_size = 0 %REPEAT Deimos header_seg(7)_mode = Deimos Read Write Deimos header_seg(7)_size = k'20000'; !Frig until Brian fixes the loader Code Base = 0 Event Base = 0 Gla Base = 0 Stack base = -1 Stack size = 0 %END %ROUTINE Allocate Deimos Areas %INTEGER N,S,Size,Extra Size %ROUTINE New Seg S = S+1 Fail("VM Full") %IF S>=7 Fail("Segment overlap error") %UNLESS %C Deimos Header_Seg(S)_Mode=Deimos Unused %END %FOR N = 0,1,7 %CYCLE Deimos Header_Seg(N)_Mode = Deimos Unused Deimos Header_Seg(N)_Size = 0 %REPEAT N = Code Size+Event Size Size = 0 %IF DEIMOS&No Share Bit#0 %START code seg = 0 %IF code seg=-1 %FINISHELSESTART code seg = 1 %IF code seg=-1 Deimos Header_Seg(0)_Mode = Deimos Shared Deimos Header_Seg(0)_Size = Shared Code Size %FINISH S = Code seg-1; Code Base = 8_20000*Code Seg Event Base = Code Base+Code Size %WHILE N#0 %CYCLE Size = N; Size = 8*1024 %IF Size>8*1024 New Seg Deimos Header_Seg(S)_Mode = Deimos Read Only Deimos Header_Seg(S)_Size = Size N = N-Size %REPEAT %IF stack seg#-1 %THEN S = stack seg-1 Stack Base = (S+1)<<13 {next segment by default} %IF Squeeze=0 %START {no squeeze} Extra Size = 0 %FINISHELSEIF Size<8*1024 %START Extra Size = 8*1024-Size {Fragment left at end of segment} Stack Base = S<<13+Size Deimos Header_Seg(S)_Mode = Deimos Read Write %FINISH %IF Stack Size=-1 %START Stack Size = k'160000'-Stack Base Stack Size = Stack Size-Gla Size %UNLESS Gla Seg=7 %FINISH Initial Sp = Stack Base+Stack Size %IF Gla Seg=7 %THEN %C Gla Base = 8_160000+Io Size+Shared Gla Size %ELSE %C Gla Base = Initial Sp Deimos Header_Initial Sp = Initial Sp N = Stack Size %IF Gla Seg#7 %THEN N = N+Gla Size %WHILE N>0 %CYCLE %IF Extra Size#0 %START {fill in end of previous segment} Size = Extra Size; Extra Size = 0 Size = N %IF Size>N Deimos Header_Seg(S)_Size = Deimos Header_Seg(S)_Size+Size %FINISHELSESTART Size = N; Size = 8*1024 %IF Size>8*1024 New Seg Deimos Header_Seg(S)_Mode = Deimos Read Write Deimos Header_Seg(S)_Size = Size %FINISH N = N-Size %REPEAT Deimos Header_Seg(7)_Mode = Deimos Read Write N = Shared Gla Size+IO Size N = N+Gla Size %IF Gla Seg=7 Fail("IO Segment full") %IF N>8*1024 Deimos Header_Seg(7)_Size = N %END %ROUTINE Insert Shared Perm %RECORD (Filefm) F %RETURNIF Shared="" F_Link == Shared Head Cbase = 0 Gbase = 7<<13 Event = 0 Allocate(F) Shared Code Size = Cbase Shared Gla Size = Gbase-7<<13 Fail("No event traps permitted in shared perm") %IF Event#0 %END Insert Shared Perm Tot Up %IF Deimos=0 %START Allocate Areas %FINISHELSEIF Deimos=2 %START Allocate Deimos Shared %FINISHELSESTART Allocate Deimos Areas %FINISH Event = Event Base Cbase = Code Base Gbase = Gla Base Allocate(File Head) Fail("Corrupt event list") %IF Event#Cbase+Event Size %END %INTEGERFN Address of(%RECORD (Itemfm) %NAME D) %RESULT = 0 %IF D==Null Area = D_Area %RESULT = D_Displacement %IF Area=0 %OR Area=7 %RESULT = D_Displacement+D_M_Code Base %IF Area=5 %RESULT = D_Displacement+D_M_Gla Base %IF Area=6 Fail("Bad relocation for ".D_Text." from file ".D_M_F_File) %END %ROUTINE Generate Image %INTEGER start,length %RECORD (Itemfm) Main %RECORDFORMAT Buffm(%INTEGER Base,Zero,P,A, %BYTEARRAY V(0:127)) %RECORD (Buffm) %NAME Buf,Old %RECORD (Buffm) Code Buffer,Gla Buffer,Line Buffer,Diag Buffer, Event Buffer %INTEGER Reloc,J,Permit,Dis %ROUTINE Flush Buffer %INTEGER J,Check,N %ROUTINE Psym(%INTEGER N) Check = Check+N Printch(N) %END %ROUTINE Put(%INTEGER N) Psym(N&255); Psym(N>>8) %END N = Buf_P %IF Buf_Zero#0 %OR Permit#0 %START Printch(0) %FOR J = 1,1,10 Check = 0 Put(1) Put(N+6) Put(Buf_Zero+Buf_Base) Psym(Byteinteger(J)) %FOR J = Buf_A,1,Buf_A+N-1 Printch((-Check)&255) %FINISH Buf_Base = Buf_Base+N Buf_P = 0 %END %ROUTINE Add1(%INTEGER N) Byteinteger(Buf_A+Buf_P) <- N Buf_P = Buf_P+1 Flush Buffer %IF Buf_P>126 %END %ROUTINE Add2(%INTEGER N) %INTEGER A A = Buf_A+Buf_P N = N+Reloc; Reloc = 0 Byteinteger(A) <- N Byteinteger(A+1) <- N>>8 Buf_P = Buf_P+2 Flush Buffer %IF Buf_P>126 %END %ROUTINE Load Module(%RECORD (Modulefm) %NAME M, %BYTEINTEGERARRAYNAME FILEBUF) %INTEGERARRAY Reference(1:M_Number of Refs) %BYTEARRAY Ref Area(1:M_Number of Refs) %INTEGER ptr %SWITCH Item(1:15) %INTEGER Code,N,S %INTEGER Mask,Ep,Low,High,Last,X %STRING (15) Section %ROUTINE Get Reference Table(%BYTEINTEGERARRAYNAME FILEBUF, %INTEGERNAME ptr) %RECORD (Itemfm) RefX %STRING (REF Size) Ref %INTEGER N,X,P %RECORD (Itemfm) %NAME D N = Two Bytes(FILEBUF,ptr) Fail("Phase error") %IF M_Number of Refs#N P = 0 %WHILE N>0 %CYCLE N = N-1 P = P+1 Get String(Ref,FILEBUF,ptr) %CONTINUEIF M_Used=0 RefX_Text = Ref Reference(P) = Address of(Record(Definition of(RefX,Hash))) Ref Area(p) = Area {7 for fixup} %REPEAT %END %ROUTINE Select(%RECORD (Buffm) %NAME Buffer, %INTEGER At) Buf == Buffer %IF Buf_Base+Buf_P#At %START Flush Buffer %IF Buf_P#0 Buf_Base = At %FINISH %END ptr = M_ref address Get Reference Table(FILEBUF,ptr) %RETURNIF M_used=0 Code Buffer = 0; Code Buffer_Zero = M_Code Base Code Buffer_A = Addr(Code Buffer_V(0)) Gla Buffer = 0; Gla Buffer_Zero = M_Gla Base-Glap Gla Buffer_A = Addr(Gla Buffer_V(0)) Line Buffer = 0 Diag Buffer = 0 Event Buffer = 0; Event Buffer_A = Addr(Event Buffer_V(0)) Reloc = 0 %CYCLE ptr = ptr+1; Code = FILEBUF(ptr) ->Item(Code) %IF 0>1<7<<12 %FINISH %IF Ref Area(X)=7 %START {fixup} ! Fail("Bad fixup") %IF Last # k'004737' {only calls} %IF N&1#0 %START {indirect} Fail("Bad fixup") %IF Last#k'004737' {only calls} Last = k'004777' Flush Buffer %UNLESS Buf_P=0 Buf_Base = Buf_Base-2; Add2(Last) {overwrite} N = N-1-(Buf_Zero+Buf_Base+Buf_P)-2 %FINISH %FINISH Reloc = Reloc+N; %CONTINUE Item(10): {Pc Reloc} N = Buf_Zero+Buf_Base+Buf_P Reloc = Reloc-N-2; %CONTINUE Item(11): {Add Byte} ptr = ptr+1; N = FILEBUF(ptr); Add1(N) %CONTINUE Item(12): {Add Word} Last = Two Bytes(FILEBUF,ptr) Add2(Last); %CONTINUE Item(13): {Line No} N = Two Bytes(FILEBUF,ptr); %CONTINUE Item(14): {Event Block} Mask = Two Bytes(FILEBUF,ptr) Ep = Two Bytes(FILEBUF,ptr) Low = Two Bytes(FILEBUF,ptr) High = Two Bytes(FILEBUF,ptr) Old == Buf Select(Event Buffer,M_Event Base) Add2(Low+M_Code Base) Add2(High+M_Code Base) Add2(Mask) Add2(Ep+M_Code Base) Buf == Old M_Event Base = M_Event Base+8 %REPEAT Item(15):{Eof} Buf == Code Buffer; Flush Buffer %IF Buf_P#0 Buf == Gla Buffer; Flush Buffer %IF Buf_P#0 Buf == Line Buffer; Flush Buffer %IF Buf_P#0 Buf == Diag Buffer; Flush Buffer %IF Buf_P#0 Buf == Event Buffer; Flush Buffer %IF Buf_P#0 %END %ROUTINE Load File(%RECORD (Filefm) %NAME F, %INTEGER start,length) %BYTEINTEGERARRAYFORMAT FILEBUFFER(1:length) %BYTEINTEGERARRAYNAME FILEBUF %RECORD (Modulefm) %NAME M M == F_Modules %WHILE M##Null %CYCLE FILEBUF == array(start,FILEBUFFER) Load Module(M,FILEBUF) M == M_Link %REPEAT Finished with File %END %ROUTINE Load Files(%RECORD (Filefm) %NAME Head) %INTEGER start,length %RECORD (Filefm) %NAME F F == Head_Link %WHILE F##Null %CYCLE %IF F_used#0 %START Define("ST3,".F_File) start = smaddr(3,length) Load File(F,start,length) %FINISH F == F_Link %REPEAT %END %ROUTINE dump value(%STRING (REF Size) symbol, %INTEGER value) %INTEGER Dis Buf = 0 Buf_A = Addr(Buf_V(0)) Main_Text = Symbol Dis = Address of(Record(definition of(Main,Hash))) %IF Dis#0 %START Buf_Zero = Dis Add2(Value) Flush Buffer %FINISH %END Select Output(Object) Permit = 1 Main_Text = EpId Entry Point = Address of(Record(Definition of(Main,Hash))) %IF Deimos#0 %START Reloc = 0 Buf == Code Buffer Buf = 0 Buf_A = Addr(Buf_V(0)) %IF Deimos Header_Task Id=" " %THEN %C Deimos Header_Task Id = default taskname Add2(Charno(Deimos Header_Task Id,1)+Charno(Deimos Header_Task Id, 2)<<8) Add2(Charno(Deimos Header_Task Id,3)+Charno(Deimos Header_Task Id, 4)<<8) Add2(Deimos Header_Initial Sp) %FOR J = 0,1,7 %CYCLE Add2(Deimos Header_Seg(J)_Mode) Add2(Deimos Header_Seg(J)_Size) %REPEAT Add2(Entry Point) Flush Buffer %FINISH Load Files(File Head) %IF Shared#"" %START Permit = 0 Define("ST3,".Shared Head_File) start = smaddr(3,length) Load File(Shared Head,start,length) Permit = 1 %FINISH Buf == Code Buffer; Buf = 0; Buf_A = Addr(Buf_V(0)) %UNLESS DEIMOS&Makeshare BIT#0 %START {initialise display to start of workspace} Main_Text = "@DISPLAY" Dis = Address of(Record(Definition of(Main,Hash))) %IF Dis#0 %START Buf_Zero = Dis Add2(Gla Base) %FOR J = 0,1,8 {initialise display} Flush Buffer %FINISH Dump Value("@EVENTBASE",Event Base) Dump Value("@CODEBASE",Code Base) Dump Value("@STACKBASE",Stack Base) Dump Value("@GLABASE",Gla Base) Dump Value("@EVENTTOP",Event Base+Event Size) Dump Value("@INITSP",Initial SP) Dump Value("@IOAREA",7<<13+Shared Gla Size) Dump Value("@IOTOP",7<<13+Shared Gla Size+IO Size) Dump Value("@NSTREAMS",N streams) %FINISH Buf_Base = 0 Buf_Zero = Entry Point{!1} Flush Buffer {terminating record} Select Output(0) Printstring("No entry point") %AND Newline %IF Entry Point=1 %END %ROUTINE Display Unsatisfied Printstring("*****Unsatisfied references:"); Newline %CYCLE Spaces(5) Spaces(REF Size-Length(Unsatisfied_Text)) Printstring(Unsatisfied_Text) %IF Unsatisfied_M##Null %START Printstring(" in file ") Printstring(Unsatisfied_M_F_File) %FINISH Newline Unsatisfied == Unsatisfied_Chain %REPEATUNTIL Unsatisfied==Null Newline %END %ROUTINE Fixup Known Items %ROUTINE Fix(%STRING (FID Size) Id, %INTEGER Address) %RECORD (Itemfm) %NAME R %RECORD (Itemfm) D D_Text = Id R == Record(Definition of(D,Hash)) %RETURNIF R==Null {lost!} R_Displacement = Address %END Fix("#IOAREA",7<<13+Shared Gla Size) Fix("#IOTOP",7<<13+Shared Gla Size+IO Size) Fix("#NSTREAMS",N streams) Fix("#EVENTBASE",Event Base) Fix("#EVENTTOP",Event Base+Event Size) Fix("#CODEBASE",Code Base) Fix("#STACKBASE",Stack Base) Fix("#GLABASE",Gla Base) Fix("#INITSP",Initial Sp) %END %ROUTINE Show Module(%RECORD (Modulefm) %NAME M) %ROUTINE Ps(%INTEGER Ad,Size) Print Octal(Ad) Printstring(" ("); Print Octal(Size); Printstring(")") %END %RETURNIF M_Used=0 Printstring(M_Section) spaces(25-length(M_Section)) Printstring(" Code: "); ps(M_Code Base,M_Code Area Size) Printstring(" Gla: "); ps(M_Gla Base,M_Gla Area Size) Newline %END %ROUTINE Print Map %INTEGERARRAY P(1:Max Item) %INTEGER N,J,A %RECORD (Itemfm) %NAME D %ROUTINE Sort Items(%INTEGER a,b) %INTEGER Dump %STRING (REF Size) %NAME Dump Text %INTEGER l,u %WHILE afind up: l = l+1; ->found %IF l=u find: ->up %UNLESS Items(P(l))_Text>Dump Text P(u) = P(l) down: u = u-1; ->found %IF l=u ->down %UNLESS Items(P(u))_Textup found: P(u) = Dump l = l-1; u = u+1 %IF l-a>b-l %START Sort Items(u,b); b = l %FINISHELSESTART Sort Items(a,l); a = u %FINISH %REPEAT %END %ROUTINE Print file map(%RECORD (Filefm) %NAME F) %RECORD (Modulefm) %NAME M Newline Printstring("File ".F_File); Newline M == F_Modules %WHILE M##Null %CYCLE Show Module(M) M == M_Link %REPEAT Newline %END %ROUTINE Print VM %INTEGER i %CONSTSTRING (11) %ARRAY type(5:7)="Read Only","Read Write","Shared" %RETURNIF Deimos&alone bit=0 newlines(2) Printstring(" VM MAP") newlines(2) Printstring(" Seg Size Type") newlines(2) %FOR i = 0,1,7 %CYCLE %IF deimos header_seg(i)_mode>Deimos Unused %START write(i,3) spaces(4) print octal(deimos header_seg(i)_size) spaces(4) printstring(type(deimos header_seg(i)_mode)) newline %FINISH %REPEAT newlines(3) %END %ROUTINE Print all files %RECORD (Filefm) %NAME F F == File Head_Link %WHILE F##Null %CYCLE print file map(F) %IF F_Used#0 F == F_Link %REPEAT %END P(J) = J %FOR J = 1,1,Max Item Sort Items(1,Max Item) N = 1 %FOR J = 1,1,Max Item %CYCLE D == Items(P(J)) %CONTINUEIF D_M_Used=0 %OR D_Used=0 N = N-1 N = 3 %AND Newline %IF N=0 Spaces(REF Size+3-Length(D_Text)) Printstring(D_Text) Space A = Address of(D) %IF A&1=0 %THEN space %ELSE print symbol('@') print octal(A&(\1)) %REPEAT Newline Print all files Print VM %END Infile = ""; Mapfile = "" %IF dummy#"" %START Infile = Dummy %UNLESS %C Dummy->Infile.("/").Mapfile %OR Dummy->Infile.(",").Mapfile %FINISH infile = ".IN" %IF infile="" define("1,".infile) select input(commands) Hash = 0 {Pun on Null == 0} EpTop = 0 Deimos Header = 0 Deimos Header_Task Id = " " File End == File Head; File Head_Link == Null Shared End == Shared Head; Shared Head_Link == Null Fixup End == Fixup Head; Fixup Head_Link == Null Unsatisfied == Null Process Commands Load Nominated Files Load Shared Library Fixup Entries Insert Dummy File Insert File(Shared Head) Insert Files EpTop_Text = EpId Follow(EpTop) Display Unsatisfied %IF Unsatisfied##Null Allocate Space Fixup Known Items File End_Used = 0 {prevent loading of the dummy file} Define("ST21,T#OBJ") %IF Map File="" %START Map File = ".OUT" %FINISHELSESTART Map File = Map File."#MAP" %UNLESS Map File->("#") %FINISH define("2,".mapfile) Generate Image select output(map) Print Map select output(0) printstring("Linking complete : Free store used = ") print((100.0*(max item+max items-min item))/max items,3,0) printstring("%") newline printstring("Compressing object file") newline close stream(21) define("5,T#OBJ") define("6,".File) run("ercm09:dimp11y.comp11y") %END %ENDOFFILE