// BLDR-BR.BCPL // Copyright Xerox Corporation 1979, 1981 // Swinehart, November 13, 1981 2:55 PM // Swinehart, June 20, 1977 10:00 PM get "bldr.decl" structure ADdrWord: [ ind bit 1; addr bit 15 ] structure INstWord: [ blank bit 8; addr bit 8] let READRELFILE(event, kind) be [ //PROCESS A NEW RELFILE if KSTATICCOUNT then [ CODEWARNING("Ignoring .BR file after .BK file"); return ] if kind eq $I then [ RELPAIRSW = true; LABLISTBASE = LABLIST!0*2 ] let RBASE=0 let RFILE = FINDNEXTINPUTFILE(event) if BFILE>>BFile.codeLoc eq -1 then [ BFILE>>BFile.codeLoc = CODELOC BFILE>>BFile.maxCodeLoc = CODELOC ] BFILE>>BFile.rFileCodeLoc = CODELOC PutTemplate(LSTREAM,"*T*T*T$6UO*N",CODELOC) let CODELOCSAVED = CODELOC let WARN = false if BFILEMODE eq 0 do [ if Usc(CODELOC , USERBOTTOM) ls 0 do [ WARN = true; CODEWARNING(" IS BELOW USERBOTTOM") ] if BETWEEN(CODELOC, STATICSTART, STATICMAX) do [ WARN = true; CODEWARNING(" OVERLAPS STATIC AREA") ] ] RSTREAM = Openfile(RFILENUM,ksTypeReadOnly,wordItem) [ RFILE>>RFile.codeLoc = BFILE>>BFile.rFileCodeLoc RFILE>>RFile.fileCode = BFILE>>BFile.rFileCodeLoc - BFILE>>BFile.codeLoc ReadBlock(RSTREAM,RHEAD,RHEADLENGTH) unless (RHEAD>>BRHeader.version rshift 8) eq (VERSION rshift 8) do ERROR("$S is incompatible with this version of BLDR*N", RFILENAME) SETBIPOS(RBASE+RHEAD>>BRHeader.namesAddr); READSTATICS() SETBIPOS(RBASE+RHEAD>>BRHeader.labelsAddr); READLABELS() SETBIPOS(RBASE+RHEAD>>BRHeader.codeAddr); READCODE() SETBIPOS(RBASE+RHEAD>>BRHeader.chainsAddr); READCHAINS() if RHEAD>>BRHeader.zChainsAddr then [ SETBIPOS(RBASE+RHEAD>>BRHeader.zChainsAddr); READZCHAINS() ] RFILE>>RFile.codeLength = RFILE>>RFile.codeLength+CODELENGTH let FIRSTKLUDGE=0 if BFILE eq SFILE then [ if BFILE>>BFile.rFileCodeLoc eq CODESTART then FIRSTKLUDGE = 1 SETBOPOS(BSTREAM, BFILE>>BFile.rFileCodeLoc-CODESTART+STARTCODEIMAGE-1+FIRSTKLUDGE) ] WriteBlock(BSTREAM, CODE+FIRSTKLUDGE, CODELENGTH-FIRSTKLUDGE) BFILE>>BFile.rFileCodeLoc = BFILE>>BFile.rFileCodeLoc + CODELENGTH if BFILE>>BFile.rFileCodeLoc gr BFILE>>BFile.maxCodeLoc then BFILE>>BFile.maxCodeLoc = BFILE>>BFile.rFileCodeLoc CODELOC = BFILE>>BFile.rFileCodeLoc RBASE=RBASE+RHEAD>>BRHeader.fileLength SetFilePos(RSTREAM,0,RBASE*2) if Endofs(RSTREAM) break ] repeat Closes(RSTREAM) PutTemplate(LSTREAM,"*T*T*T*T$6UO*T*T$6UO ($D)*N", CODELOC-1, CODELOC-CODELOCSAVED, CODELOC-CODELOCSAVED) if BFILEMODE eq 0 then [ if Usc(CODELOC , COREMAX) gr 0 then CODEWARNING(" overlaps OS") if WARN eq 0 & BETWEEN(CODELOC-1, STATICSTART, STATICMAX) then CODEWARNING(" overlaps static area") ] ] and SETBIPOS(idx) be SetFilePos(RSTREAM,0, idx lshift 1) and FINDNEXTINPUTFILE(event) = valof [ RFILE = event RFILENUM = RFILE>>RFile.fileNum RFILENAME = fileNameVec!RFILENUM rFileCount = rFileCount+1 RFILE>>RFile.rFileId = rFileCount RFILE>>RFile.bFileId = BFILE>>BFile.bFileId PutTemplate(LSTREAM," $S$S", RFILENAME,(RFILENAME!0 rshift 8)+3 < 8? "*T","") resultis RFILE ] and READSTATICS() be [ //PROCESS THE STATICS IN THE CURRENT RELFILE let sym = vec lSYm let SYMSTRING = vec NAMELENGTH/2 SYMLIST!0 = 0 let N = Gets(RSTREAM) for I = 1 to N do [ // static entry sym>>SYm.rFile = RFILE let flags = Gets(RSTREAM) sym>>SYm.flags = (flags𫙠) // last 4 bits record "local" if (flags) ne 0 then sym>>SYm.local = 1 sym>>SYm.initialValue = Gets(RSTREAM) sym>>SYm.staticAddress = -1 SYMSTRING!0 = Gets(RSTREAM) ReadBlock(RSTREAM,lv SYMSTRING!1,(SYMSTRING!0 rshift 8)/2) sym>>SYm.dictEntry = DICTENTRY(SYMSTRING) let entry, symType = SYMENTRY(sym, false), sym>>SYm.type test entry then [ entry>>SYm.jOnly = false if sym>>SYm.z ne entry>>SYm.z then [ COMMONERROR(sym, entry); entry>>SYm.z = 1 ] if symType > 0 & entry>>SYm.type > 0 then [ MULTDEFERROR(sym, entry); entry>>SYm.dupDef = true ] ] or entry = NEWSYMENTRY(sym) if symType > 0 then [ // defining symbol if RELPAIRSW &symType > 1 then entry>>SYm.relocatable = true unless entry>>SYm.dupDef do [ if BFILEMODE eq 1 & symType > 1 then entry>>SYm.initSwappedOut = true entry>>SYm.initialValue = sym>>SYm.initialValue entry>>SYm.rFile = sym>>SYm.rFile entry>>SYm.type = symType ] ] let P = SYMLIST!0 + 1 SYMLIST!0 = P SYMLIST!P = entry ] // static entry ] and READLABELS() be [ //PROCESS THE LABELS IN THE CURRENT RELFILE let LFIRST = LABLIST!0*2 + 1 let N = Gets(RSTREAM) for I = 1 to N do [ let ENTRY = SYMLIST!(Gets(RSTREAM)) let PC = Gets(RSTREAM) let P = LABLIST!0*2 + 1 LABLIST!0 = LABLIST!0 + 1 LABLIST!(P+0) = ENTRY LABLIST!(P+1) = PC if ENTRY>>SYm.dupDef eq 0 then ENTRY>>SYm.initialValue = PC + RFILE>>RFile.codeLoc ] let LLAST = LABLIST!0*2 - 1 if LISTLABSW do [ [ let PMIN = -1 let PCMIN = CODEMAX for P = LFIRST to LLAST by 2 do [ let PC = LABLIST!(P+1) if (PC & #100000) eq 0 do if PC ls PCMIN do PMIN, PCMIN = P, PC ] if PMIN eq -1 break PRINTSYM(LABLIST!PMIN) LABLIST!(PMIN+1) = LABLIST!(PMIN+1) + #100000 ] repeat ] for P = LFIRST to LLAST by 2 do [ LABLIST!P = (LABLIST!P)>>SYm.staticAddress LABLIST!(P+1) = (LABLIST!(P+1) & #77777) + RFILE>>RFile.fileCode ] ] and READCODE() be [ //READ THE CODE IMAGE IN THE CURRENT RELFILE CODELENGTH = Gets(RSTREAM) if CODELENGTH gr CODEMAX do ERROR("RELFILE TOO BIG") if ReadBlock(RSTREAM,CODE,CODELENGTH) ne CODELENGTH then ERROR("PREMATURE END OF FILE") ] and READCHAINS() be [ //PROCESS THE STATIC CHAINS IN THE CURRENT RELFILE let N, T = Gets(RSTREAM), nil for I = 1 to N do [ let PC = Gets(RSTREAM) let P = (I-1)*1 + 1 let ENTRY = SYMLIST!P test not PC<<ADdrWord.ind then while PC do [ T = CODE!PC CODE!PC = ENTRY>>SYm.staticAddress PC = T ] or [ unless ENTRY>>SYm.z do ERROR("BUG #1") PC = PC<<ADdrWord.addr [ T = (CODE!PC)<<INstWord.addr (CODE!PC)<<INstWord.addr = ENTRY>>SYm.staticAddress PC = PC - T ] repeatuntil T eq 0 ] ] ] and READZCHAINS() be [ let N, T = Gets(RSTREAM), nil for I = 1 to N do [ let ENTRY = SYMLIST!(Gets(RSTREAM)) let PC = Gets(RSTREAM)<<ADdrWord.addr unless ENTRY>>SYm.z do ERROR("BUG #2") [ T = (CODE!PC)<<INstWord.addr (CODE!PC)<<INstWord.addr = ENTRY>>SYm.staticAddress PC = PC - T ] repeatuntil T eq 0 ] ] and DICTENTRY(name, enterNew; numargs na) = valof [ // find name in DICT or enter it, or return false (depends on enterNew) if na eq 1 then enterNew = true let lN = name>>STRING.length if CASESW then for i = 1 to lN do name>>STRING.char↑i = CAPITALIZE(name>>STRING.char↑i) lN = lN rshift 1 // # words - 1 let c = name>>STRING.char↑1 // hash character let bucket = CAPITALIZE(c) bucket = (bucket-$A)*2+(c eq bucket? 1, 2) if c eq $. then bucket = 1 unless 0 le bucket & bucket le 26*2 do ERROR("Symbol $S invalid*N",name) let prevEnt, dictEnt = lv DICT!bucket, nil // comparison loop [ dictEnt = @prevEnt unless dictEnt break // loop control let dictName = lv dictEnt>>DIct.name if valof [ for i = 0 to lN do if dictName!i ne name!i resultis false resultis true ] resultis dictEnt prevEnt = dictEnt ] repeat unless enterNew resultis false dictEnt = Zmem(offsetDIctName+lN+1) prevEnt>>DIct.link = dictEnt // join name to tail of bucket MoveBlock(lv dictEnt>>DIct.name,name,lN+1) resultis dictEnt ] and SYMENTRY(sym) = valof [ let name = sym>>SYm.dictEntry let nextEntry = name>>DIct.sym let isSymLocal = sym>>SYm.local while nextEntry do [ let entry = nextEntry; nextEntry = @nextEntry if isSymLocal ne entry>>SYm.local loop unless isSymLocal resultis entry // local, must appear in same .BR file let symFile, entFile = sym>>SYm.rFile, entry>>SYm.rFile if symFile eq entFile % (DUPSW & fileNameVec!(symFile>>RFile.fileNum) eq fileNameVec!(entFile>>RFile.fileNum) ) resultis entry ] resultis 0 ] and NEWSYMENTRY(sym) = valof [ let entry = Zmem(lSYm) // next three lines obsolete SYMTAB!0 = SYMTAB!0 + 1 if SYMTAB!0 > SYMMAX then ERROR("Too many symbols") SYMTAB!(SYMTAB!0) = entry MoveBlock(entry,sym,lSYm) let dict = entry>>SYm.dictEntry // join new sym to head of syms with same name entry>>SYm.link = dict>>DIct.sym dict>>DIct.sym = entry if entry>>SYm.staticAddress ne -1 resultis entry test entry>>SYm.z then [ // page 0 if COMMONLOC eq JCOMMONMIN then COMMONLOC = JCOMMONMAX+1 entry>>SYm.staticAddress = COMMONLOC COMMONLOC = COMMONLOC + 1 ] or [ // normal static if STATICLOC eq JSTATICMIN then STATICLOC = JSTATICMAX+1 entry>>SYm.staticAddress = STATICLOC STATICLOC = STATICLOC + 1 ] resultis entry ] and READJKFILE(event, kind) be [ let RFILE = FINDNEXTINPUTFILE(event) Puts(LSTREAM,$*N) Closes(READJKSTATICS(Openfile(RFILENUM,ksTypeReadOnly,charItem), kind)) ] and SKIPTO(STREAM, CHAR) = valof // **** [ let KCHAR = nil KCHAR = Endofs(STREAM)? 1000, Gets(STREAM) repeatuntil KCHAR eq CHAR % KCHAR eq 1000 resultis KCHAR ] and READJKSTATICS(STREAM, kind) = valof // returns STREAM [ //PROCESS THE STATICS IN THE CURRENT .BJ or .BK FILE let sym, entry = vec lSYm, nil let SYMSTRING = vec NAMELENGTH/2 let GOTNAME, GOTOCTAL = 0, 0 let TYPE, RELOC = nil, nil let BASE = 0 let KCHAR = $*C [CLOOP switchon KCHAR into [CASES case $*S: case $*L: case $*T: endcase case $/: KCHAR = SKIPTO(STREAM, $*C) case 1000: case $*C: if GOTNAME & GOTOCTAL then [ let dict = DICTENTRY(SYMSTRING, kind ne $K) sym>>SYm.dictEntry = dict sym>>SYm.flags = 0 if kind eq $H then TYPE = 0 // for /H sym>>SYm.type = TYPE sym>>SYm.relocatable = TYPE gr 1? RELOC, 0 sym>>SYm.rFile = RFILE test kind eq $K ifso if dict then PROCESSKSTATIC(sym) ifnot PROCESSJSTATIC(sym) ] if KCHAR eq 1000 then break sym>>SYm.initialValue, sym>>SYm.staticAddress = 0, -1 GOTNAME, GOTOCTAL = false, false TYPE = kind eq $K? 2, 0 RELOC = 0 endcase case $0 to $7: [ let I = 0 while BETWEEN(KCHAR,$0,$7+1) do [ I = I lshift 3 + (KCHAR-$0) KCHAR = Endofs(STREAM)? 1000, Gets(STREAM) ] test GOTNAME ifso [ test kind ne $K ifso unless GOTOCTAL then sym>>SYm.staticAddress = I+BASE ifnot sym>>SYm.initialValue = I+BASE GOTOCTAL = true ] ifnot [ BASE = I if KCHAR ne $*C do KCHAR = SKIPTO(STREAM, $*C) endcase ] loop ] default: [ if GOTNAME then [ switchon KCHAR into [ case $V: TYPE = 1 ; endcase case $P: TYPE = 2 ; endcase case $L: TYPE = 3 ; endcase case $R: RELOC = 1 ; endcase default: endcase ] endcase ] let I = 0 while BETWEEN(KCHAR,$a,$z+1) % BETWEEN(KCHAR,$A,$Z+1) % BETWEEN(KCHAR,$0,$9+1) do [ I = I + 1 SYMSTRING>>STRING.char↑I = KCHAR KCHAR = Endofs(STREAM)? 1000, Gets(STREAM) ] if I eq 0 then endcase SYMSTRING>>STRING.char↑(I+1) = 0 SYMSTRING>>STRING.length = I GOTNAME = true loop ] ]CASES KCHAR = Endofs(STREAM)? 1000, Gets(STREAM) ]CLOOP repeat resultis STREAM ] and PROCESSJSTATIC(sym) be // **** [ let entry = SYMENTRY(sym) let ADDR = sym>>SYm.staticAddress sym>>SYm.z = BETWEEN(ADDR,1,#400) test entry ifso [ let OLDADDR = entry>>SYm.staticAddress if OLDADDR ne -1 & OLDADDR ne ADDR % sym>>SYm.type > 0 & entry>>SYm.type > 0 then MULTDEFERROR(sym, entry, true) entry>>SYm.staticAddress = ADDR if sym>>SYm.type > 0 then entry>>SYm.rFile = RFILE // e.g., sym>>SYm.rFile ] ifnot entry = NEWSYMENTRY(sym) entry>>SYm.jOnly = 1 test BETWEEN(ADDR, COMMONSTART, COMMONMAX) ifso [ JCOMMONMIN = Umin(JCOMMONMIN, ADDR) JCOMMONMAX = Umax(JCOMMONMAX, ADDR) ] ifnot if BETWEEN(ADDR, STATICSTART, STATICMAX) then [ JSTATICMIN = Umin(JSTATICMIN, ADDR) JSTATICMAX = Umax(JSTATICMAX, ADDR) ] ] and PROCESSKSTATIC(sym) be // **** [ let entry = SYMENTRY(sym) if entry & not entry>>SYm.type & not entry>>SYm.jOnly then [ entry>>SYm.initialValue = sym>>SYm.initialValue sym>>SYm.z = entry>>SYm.z entry>>SYm.flags = sym>>SYm.flags CODE ! KSTATICCOUNT = entry KSTATICCOUNT = KSTATICCOUNT + 1 entry>>SYm.rFile = RFILE // e.g., sym>>SYm.rFile if LISTLABSW & sym>>SYm.type gr 1 then PRINTSYM(entry) ] ]