#if e #report LINK11 - EMAS Version #else #report LINK11 - DEIMOS Version #fi {##################################} {# 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 #if e %externalroutine LINK11(%string(63) Dummy) %externalroutinespec Destroy(%string(63) File) %externalroutinespec Run(%string(63) File) %externalroutinespec Define(%string(63) File) %externalroutinespec Prompt(%string(63) What) %externalintegerfnspec EXIST(%string(63) File) %externalintegerfnspec smaddr(%integer chan,%integername length) %externalstring(63)%fnspec ItoS(%integer N, P) %constinteger commands = 1, source = 3, map = 2, object = 21 #else %begin %externalroutinespec Print ch %alias "Printsymbol" (%integer i) %externalroutinespec Prompt(%string(31) P) %externalpredicatespec Exists(%string(12) File) %externalstring(63)%fnspec ItoS(%integer N, P) %constinteger commands=1, source = 3, map = 1, object = 2 #fi #if e %constinteger FID Size = 17, REF Size = 14, Max Items = 900, Max Module = 100, Max File = 20 #else %constinteger FID Size = 30, REF Size = 14, Max Items = 200, Max Module = 40, Max File = 20 %constinteger Max Refs = 50 #fi { *-------*-----* { | FILES | END | { *---+---*--+--* { | | { | *----------------------------* { | | { V V { *------*---* *------*---* *------*---* { *-->| FILE | *-+----> | FILE | *-+----> | FILE | | { | *--+---*---* *--+---*---* *--+---*---* { | | | | { | | { | V { | *--------*---*---* { *---| MODULE | * | *-+---> References { *--+-----*-+-*---* { | | ^ { | | | { | | *-------*----------------* { | | | | { | | *--+--*---* *--+--*---* { | *--------| DEF | *-+----> | DEF | *-+----> .... { | *-----*---* *-----*---* { V { Etc #if e %ownstring(FID Size) Default Perm = "ERCS09.Perm11#Rel" #else %ownstring(FID size) Default Perm = "PERM11" #fi {%constrecord(*)%name Null == 0 Blast!} #if ~e %recordformatspec Modulefm #fi %recordformat Itemfm(%string(REF Size) Text, %byte Area, Used, %integer Displacement, %record(Modulefm)%name M, %record(Itemfm)%name Chain, Link) #if e %constrecord(Itemfm)%name Null = 0 #else %constrecord(*)%name Null == 0 #fi %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 %own %integer 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 } #if e %conststring (FID Size) Share Lib = "ERCM11.SHR#REL", Share Fix = "ERCM11.SHR#FIX", Non Share Lib = "ERCM11.IMP#REL", Non Share Fix = "ERCM11.IMP#FIX" #else %conststring(FID Size) Share Lib ="SHRREL", Share Fix = "SHRFIX", Non Share Lib = "IMPREL", Non Share Fix = "IMPFIX" #fi %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} #if ~e %recordformatspec Filefm #fi %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, #if e ref address, #fi %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 #if e %monitor #fi %stop %end %routine Read Octal(%integername N) %integer Sym N = 0 Skipsymbol %while Nextsymbol = ' ' %or Nextsymbol=nl %return %unless '0' <= Nextsymbol <= '7' %cycle Readsymbol(Sym) N = N<<3+(Sym-'0') %repeat %until %not '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 %return %if 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 %return %if File = "" P == Record(New File) P_File = File File End_Link == P File End == P %end #if e %integerfn Existence(%string(63)%name File) #else %integerfn Existence(%string(*)%name File) #fi #if e %if Exist(File."#REL")=1 %then File=File."#REL" %and %result=-1 %if Exist(File)=1 %then %result=-1 #else %result=-1 %if Exists(File) #fi 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 %return %if Word # "" %finish %else %start Word = Word.Tostring(Sym) %finish Read Sym %repeat %end %routine Skip Line Readsym %while Sym = ' ' %if Sym # NL %start Printch('`') %cycle Printch(Sym) Readsym %repeat %until 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 %finish %else %start %exit %if 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 %finish %else %if Word = ".MAKESHARE" %start DEIMOS = Makeshare Bit!No Share Bit Stack size = 0 Low = 0 High = k'20000' %finish %else %if Word = ".STREAMS" %start Prompt("Streams: ") Read Octal(n streams) IO Size = n streams * IO stream size %finish %else %if Word = ".GLA7" %start Gla Seg = 7 %finish %else %if 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 %finish %else %if Word = ".STACKSEG" %start read (stack seg) %unless 1< stackseg < 7 %start printstring("Stack segment must be 2 to 6") newline stack seg=-1 %finish %finish %else %if Word = ".STACK" %start Prompt("Stack size: ") Read Octal(Stack Size) %if Nextsymbol&95 = 'K' %start Skipsymbol Stack Size = Stack Size*1024 %finish %else %if Nextsymbol&95 = 'B' %start Skipsymbol %finish %finish %else %if Word = ".BIGSTACK" %start Stack Size = -1 %finish %else %if Word = ".SQUEEZE" %start Squeeze = 1 %finish %else %if Word = ".NAME" %or Word = ".TASK" %start Prompt("Task name: ") Read Word Deimos Header_Task Id <- Word." "; !Must be four characters at least. %finish %else %if Word = ".NOPERM" %start Default Perm = "" %finish %else %if Word = ".ENTRY" %start Prompt("Entry point: ") Read Word EpId <- Word %finish %else %if Word = ".NOSHARE" %start Deimos = Deimos!Noshare Bit %finish %else %if Word = ".SHARE" %start Read Word Word = Word."#REL" %unless Word -> ("#REL") Shared = Word %if Existence(Word) # 0 %finish %else %if Word = ".FIXUP" %start Read Word Append Fixup File(Word) %if Existence(Word)#0 %finish %else %start Printstring(Word." not known"); Newline %finish %finish Skip Line %repeat Prompt("Object file: ") read word; #if e %if word -> ("#") %then file <- word %else file <- word."#ABS" file -> word.("#") default taskname <- word." " #else file <- word default taskname = word #fi Skip Line %if DEIMOS # 0 %start %if DEIMOS&Noshare Bit = 0 %start Append File(Share Lib) Append Fixup File(Share Fix) %finish %else %start Append File(Non Share Lib) Append Fixup File(Non Share Fix) %finish %finish Append File(Default Perm) %if Default Perm # "" %c %and Existence(Default Perm) # 0 %end %routine Open for Input(%record(Filefm)%name F) #if e Define("ST3,".F_File) Select Input(3) #else open input(source,F_File) select input(source) #fi %end %routine Finished with File #if e Select Input(0) Close Stream(3) #else Close Input Select Input(0) #fi %end #if e %integerfn Two Bytes(%byteintegerarrayname BUF,%integername ptr) %integer L, H L = BUF(ptr+1) ; H = BUF(ptr+2) ; ptr=ptr+2 #else %integerfn Two Bytes %integer L, H Readch(L); Readch(H) #fi %result = H<<8+L %end #if e %routine Get String(%string(*)%name S,%byteintegerarrayname BUF, %integername ptr) #else %routine Get String(%string(*)%name S) #fi %string(255) os %integer L, Sym os = "" #if e ptr=ptr+1 ; L=BUF(ptr) #else Readch(L) #fi %while L > 0 %cycle L = L-1 #if e ptr=ptr+1 ; Sym=BUF(ptr) #else Readch(Sym) #fi 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 #if e %routine Next Definition(%record(Modulefm)%name M,%byteintegerarrayname BUF, %integername ptr) #else %routine Next Definition(%record(Modulefm)%name M) #fi %record(Itemfm)%name R R == Record(New Def) R_M == M R_Link == M_Definitions M_Definitions == R #if e ptr=ptr+1 ; R_Area=BUF(ptr) R_Displacement=Two Bytes(BUF,ptr) Get string(R_Text,BUF,ptr) #else Readch(R_Area) R_Displacement = Two Bytes Get String(R_Text) #fi %end #if e %routine Get External Definitions(%record(Modulefm)%name M,%byteintegerarrayname BUF, %integername ptr) #else %routine Get External Definitions(%record(Modulefm)%name M) #fi %integer N #if e N = Two Bytes(BUF,ptr) #else N = Two Bytes #fi %while N > 0 %cycle #if e Next Definition(M,BUF,ptr) #else Next Definition(M) #fi N = N-1 %repeat %end #if e %routine Next Reference(%record(Modulefm)%name M,%byteintegerarrayname BUF, %integername ptr) #else %routine Next Reference(%record(Modulefm)%name M) #fi %record(Itemfm)%name R R == Record(New Item) R_M == M R_Link == M_References M_References == R #if e Get String(R_Text,BUF,ptr) #else Get String(R_Text) #fi %end #if e %routine Get External References(%record(Modulefm)%name M,%byteintegerarrayname BUF, %integername ptr) #else %routine Get External References(%record(Modulefm)%name M) #fi %integer N #if e M_ref address=ptr N=Two Bytes(BUF,ptr) #else N = Two Bytes #fi M_Number of Refs = N %while N > 0 %cycle #if e Next Reference(M,BUF,ptr) #else Next Reference(M) #fi 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 #if e %routine Skip Module Body(%byteintegerarrayname BUF,%integername ptr) #else %routine Skip Module Body #fi %switch T(0:15) %integer S %cycle T(5):T(6):T(10): #if e ptr=ptr+1 ; S=BUF(ptr) #else Readch(S) #fi ->T(S) T(14): #if e ptr=ptr+6 #else Readch(S); Readch(S) Readch(S); Readch(S) Readch(S); Readch(S) #fi T(1):T(2):T(3):T(4):T(7):T(8):T(9):T(12):T(13): #if e ptr=ptr+1 #else Readch(S) #fi T(11): #if e ptr=ptr+1 #else Readch(S) #fi %repeat T(15): %end #if e %routine Get Linkage Information(%record(Filefm)%name F,%integer start,length) %byteintegerarrayformat BUFFER(1:length) %byteintegerarrayname BUF %integer ptr #else %routine Get Linkage Information(%record(Filefm)%name F) #fi %integer Next %record(Modulefm)%name M, P %record(Modulefm) Head P == Head #if e BUF==array(start,BUFFER) ptr=0 #fi %cycle #if ~E Next = Two Bytes #fi M == Record(New Module) M_F == F P_Link == M P == M #if e 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) #else M_Code Area Size = Two Bytes M_Gla Area Size = Two Bytes M_Diag Area Size = Two Bytes M_Line Area Size = Two Bytes M_Event Area Size = Two Bytes Get String(M_Section) #fi #if e Get External Definitions(M,BUF,ptr) Get External References (M,BUF,ptr) %exit %if Next = 0 Skip Module Body(BUF,ptr) #else Get External Definitions(M) Get External References (M) %exit %if Next = 0 {no more modules} Skip Module Body #fi %repeat P_Link == Null F_Modules == Head_Link Finished with File %end %routine Load Nominated Files #if e %integer start,length #fi %record(Filefm)%name F F == File Head_Link %while F ## Null %cycle #if e Define("ST3,".F_File) start=smaddr(3,length) Get Linkage Information(F,start,length) #else Open for Input(F) Get Linkage Information(F) #fi F == F_Link %repeat %end %routine Load Shared Library #if e %integer start,length #fi Shared Head_Modules == Null %return %if Shared = "" Shared Head_Used = 1 Shared Head_File = Shared #if e Define("ST3,".SharedHead_File) start=smaddr(3,length) Get Linkage Information(SharedHead,start,length) #else Open for Input(SharedHead) Get Linkage Information(SharedHead) #fi %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} %return %if R_M_F_File = Default Perm %exit %if 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 %repeat %until %not '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: %return %if F == Null Open for Input(F) Sym = ' '; !In case rubbish left from previous file %cycle Read Word %exit %if 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 %return %if P == EpTop {not really a module} M == P_M %return %if 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 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 %finish %else %start 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 %finish %else %if 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 Gla Base = 8_160000+Io Size+Shared Gla Size %c %else 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 %finish %else %start 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 %return %if 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 %finish %else %if Deimos=2 %start Allocate Deimos Shared %finish %else %start 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 #if e %integer start,length #fi %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 #if e %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 #else %routine Load Module(%record(Modulefm)%name M) %integerarray Reference(1:MaxRefs) %byteintegerarray Ref Area(1:MaxRefs) #fi %switch Item(1:15) %integer Code, N, S %integer Mask, Ep, Low, High, Last, X %string(15) Section #if ~e %routine Skip Definitions %integer N, J, L, S N = Two Bytes %while N > 0 %cycle N = N-1 Readch(S); Readch(S); Readch(S) Readch(L) Readch(S) %for J = 1,1,L %repeat %end #fi #if e %routine Get Reference Table(%byteintegerarrayname FILEBUF,%integername ptr) #else %routine Get Reference Table #fi %record(Itemfm) RefX %string(REF Size) Ref %integer N, X, P %record(Itemfm)%name D #if e N = Two Bytes(FILEBUF,ptr) #else N = Two Bytes #fi Fail("Phase error") %if M_Number of Refs # N P = 0 %while N > 0 %cycle N = N-1 P = P+1 #if e Get String(Ref,FILEBUF,ptr) #else Get String(Ref) #fi %continue %if 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 #if Fail("Too many Refs") %if M_Number of Refs > MaxRefs #fi #if e ptr=M_ref address Get Reference Table(FILEBUF,ptr) %return %if M_used = 0 #else Readch(S) %for N = 1,1,12 Get String(Section) Skip Definitions Get Reference Table %if M_Used = 0 %start Skip Module Body %return %finish #fi 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 #if e ptr=ptr+1 ; Code=FILEBUF(ptr) #else Readch(Code) #fi ->Item(Code) %if 0 < Code <= 15 Fail("Illegal code item ".ItoS(Code, 0). %c " in file ".M_F_File) #if e Item(1): {Select Code} Select(Code Buffer, Two Bytes(FILEBUF,ptr)); %continue Item(2): {Select Gla} Select(Gla buffer, Two Bytes(FILEBUF,ptr)); %continue Item(3): {Select Diag} Select(Diag Buffer, Two Bytes(FILEBUF,ptr)); %continue Item(4): {Select Line} Select(Line Buffer, Two Bytes(FILEBUF,ptr)); %continue #else Item(1): {Select Code} Select(Code Buffer, Two Bytes); %continue Item(2): {Select Gla} Select(Gla Buffer, Two Bytes); %continue Item(3): {Select Diag} Select(Diag Buffer, Two Bytes); %continue Item(4): {Select Line} Select(Line Buffer, Two Bytes); %continue #fi Item(5): {Code Reloc} Reloc = Reloc+M_Code Base; %continue Item(6): {Gla Reloc} Reloc = Reloc+M_Gla Base; %continue Item(7): {Diag Reloc} %continue Item(8): {Line Reloc} %continue Item(9): {Ext Reloc} #if e X = Two Bytes(FILEBUF,ptr) #else X = Two Bytes #fi N = Reference(X) %if Permit = 0 %start Fail("Shared perm accesses an external") %c %if 1<<12 < (N&x'FFFF')>>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 #if e 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) #else Item(11):{Add Byte} Readch(N); Add1(N); %continue Item(12):{Add Word} Last = Two Bytes Add2(Last); %continue Item(13):{Line No} N = Two Bytes; %continue Item(14):{Event block} Mask = Two Bytes Ep = Two Bytes Low = Two Bytes High = Two Bytes #fi 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 #if e %routine Load File(%record(Filefm)%name F,%integer start,length) %byteintegerarrayformat FILEBUFFER(1:length) %byteintegerarrayname FILEBUF #else %routine Load File(%record(Filefm)%name F) #fi %record(Modulefm)%name M M == F_Modules %while M ## Null %cycle #if e FILEBUF==array(start,FILEBUFFER) Load Module(M,FILEBUF) #else Load Module(M) #fi M == M_Link %repeat Finished with File %end %routine Load Files(%record(Filefm)%name Head) #if e %integer start,length #fi %record(Filefm)%name F F == Head_Link %while F ## Null %cycle #if e %if F_used # 0 %start Define("ST3,".F_File) start=smaddr(3,length) Load File(F,start,length) %finish #else Open for Input(F) %and Load File(F) %if F_Used # 0 #fi 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 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 #if e Define("ST3,".Shared Head_File) start=smaddr(3,length) Load File(Shared Head,start,length) #else Open for input(Shared Head) Load File(Shared Head) #fi 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 %repeat %until 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)) %return %if 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 %return %if 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 a < b %cycle l = a; u = b dump = P(u) Dump Text == Items(Dump)_Text ->find 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))_Text < Dump Text P(l) = P(u) ->up found: P(u) = Dump l = l-1; u = u+1 %if l-a > b-l %start Sort Items(u, b); b = l %finish %else %start 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" %return %if 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)) %continue %if 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 #if e Infile=""; Mapfile="" %if dummy#"" %start Infile=Dummy %unless Dummy->Infile.("/").Mapfile %or Dummy->Infile.(",").Mapfile %finish infile=".IN" %if infile="" define("1,".infile) #fi 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} #if e Define("ST21,T#OBJ") %if Map File ="" %start Map File = ".OUT" %finish %else %start Map File = Map File."#MAP" %unless Map File -> ("#") %finish define("2,".mapfile) #else open output(Object, File) %unless File=".X" #fi Generate Image select output(map) Print Map #if e 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("ercs09.comp11y") #fi %end %endoffile