(******************************************************************) (* *) (* Copyright (c) 1978 Regents of the University of California. *) (* Permission to copy or distribute this software or documen- *) (* tation in hard or soft copy granted only by written license *) (* obtained from the Institute for Information Systems. *) (* *) (******************************************************************) { * Phase2 reads in all linker info associated with * the segs in seginfo and sep seg list. Again all * fields are checked carefully. As a help to phase3, * ref lists are collected and place records for sep * proc/func are computed. Some small optimization is * done to eliminate the sep seg list if it is not * going to be needed, saving a few disk IO's. } procedure phase2; var s: segindex; sp: segp; dumpseps: boolean; { * Readlinkinfo reads in the link info for segment sp * and builds its symtab. Some simple disk io routines * do unblocking, and all fields are again verified. * The only legal litypes are in oktypes. Assume that * sp <> NIL } procedure readlinkinfo(sp: segp; oktypes: liset); var rp, rq: refp; syp: symp; errs, nrecs, nextblk, recsleft: integer; entry, temp: lientry; buf: array [0..31] of array [0..7] of integer; { * Getentry reads an 8 word record from disk buf * sequentially. No validity checking is done here, * only disk read errors. } procedure getentry(var entry: lientry); var err: boolean; begin err := FALSE; if recsleft = 0 then begin recsleft := 32; err := blockread(sp^.srcfile^.code^, buf, 1, nextblk) <> 1; if err then error('li read err') else nextblk := nextblk+1 end; moveleft(buf[32-recsleft], entry, 16); if err then entry.litype := EOFMARK; recsleft := recsleft-1 end { getentry } ; { * Addunit is called to find or allocate a library unit * that is found in link info as an external ref. This * occurs in lib units which use other units. If * the unit can't be found or no room, error is called. } procedure addunit(var name: alpha); var fp: finfop; seg: integer; begin fp := unitsrch(hostfile, name, seg); if fp <> NIL then if fp <> hostfile then if fp^.segtbl.diskinfo[seg].codeleng <> 0 then if nextseg = MAXSEG1 then error('no room in seginfo') else begin { allocate new seginfo el } new(seginfo[nextseg]); with seginfo[nextseg]^ do begin srcfile := fp; srcseg := seg; segkind := UNITSEG; symtab := NIL end; nextseg := nextseg+1 end end { addunit } ; { * Validate verifies lientry format. * If the entry is SEPPROC or FUNC * then a place rec is allocated for buildplace. If * a UNITREF is found, it searched for and possibly * allocated. If the unit must be added to seginfo, * it is placed after current position so it will have * its link info read as well. } procedure validate(var entry: lientry); begin with entry do if not alphabetic(name) then error('non-alpha name') else case litype of SEPPREF, SEPFREF, UNITREF, GLOBREF, PUBLREF, PRIVREF, CONSTREF: begin reflist := NIL; if (nrefs < 0) or (nrefs > 500) then error('too many refs'); if not (format in [WORD, BYTE, BIG]) then error('bad format'); if litype = PRIVREF then if (nwords <= 0) or (nwords > MAXLC) then error('bad private'); if (litype = UNITREF) and (nrefs > 0) then addunit(name) end; GLOBDEF: if (homeproc <= 0) or (homeproc > MAXPROC) or (icoffset < 0) or (icoffset > MAXIC) then error('bad globdef'); PUBLDEF: if (baseoffset <= 0) or (baseoffset > MAXLC) then error('bad publicdef'); EXTPROC, EXTFUNC, SEPPROC, SEPFUNC: begin if litype in [SEPPROC,SEPFUNC] then new(place) { for use in buildplaces } else place := NIL; if (srcproc <= 0) or (srcproc > MAXPROC) or (nparams < 0) or (nparams > 100) then error('bad proc/func') end end { case litype } end { validate } ; begin { readlinkinfo } recsleft := 0; { 8 wd recs left in buf } with sp^.srcfile^.segtbl, diskinfo[sp^.srcseg] do begin { seek to linkinfo } nextblk := codeaddr + (codeleng+511) div 512; if talkative then writeln('Reading ', segname[sp^.srcseg]) end; repeat getentry(entry); errs := errcount; if entry.litype <> EOFMARK then if entry.litype in oktypes then validate(entry) else begin error('bad litype'); entry.litype := EOFMARK end; if dumpseps then if entry.litype in [SEPPREF, SEPFREF, EXTPROC, EXTFUNC, GLOBREF] then dumpseps := FALSE; { we need them! } if entry.litype in reflitypes then begin { read ref list } nrecs := (entry.nrefs+7) div 8; while nrecs > 0 do begin { read ref rec } getentry(temp); new(rp); moveleft(temp, rp^.refs, 16); rp^.next := entry.reflist; entry.reflist := rp; nrecs := nrecs-1 end; { reverse ref list } rp := entry.reflist; entry.reflist := NIL; while rp <> NIL do begin rq := rp^.next; rp^.next := entry.reflist; entry.reflist := rp; rp := rq end end; if entry.litype = EOFMARK then if sp^.segkind = HOSTSEG then if (entry.nextlc > 0) and (entry.nextlc <= MAXLC) then nextbaselc := entry.nextlc else error('bad host LC') else else if errs = errcount then begin { ok...add to symtab } new(syp); syp^.entry := entry; entersym(syp, sp^.symtab) end until entry.litype = EOFMARK end { readlinkinfo } ; { * Buildplaces reads code of sep segs from disk to generate * the placerec entries for use during phase3. The seg is * read into the heap and the grossness begins. Assume that * sp <> NIL } procedure buildplaces(sp: segp); var cp: codep; heap: ^integer; nbytes, nblocks, nprocs, n: integer; { * procsrch recursivly searches symtab of sp to find * sepproc and sepfunc entries and build the actual * place record for the link info entry by indexing * thru proc dict to jtab and using entric field. } procedure procsrch(symtab: symp); var i, j: integer; begin if symtab <> NIL then begin procsrch(symtab^.llink); procsrch(symtab^.rlink); procsrch(symtab^.slink); with symtab^.entry do if litype in [SEPPROC, SEPFUNC] then if (srcproc <= 0) or (srcproc > nprocs) then error('bad proc #') else { find byte place in code } begin i := nbytes-2-2*srcproc; { point i at proc dict } i := i-fetchword(cp, i); { point i at jtab } if (fetchbyte(cp, i) <> srcproc) and (fetchbyte(cp, i) <> 0) then error('disagreeing p #') else begin j := fetchword(cp, i-2)+4; place^.srcbase := i+2-j; if (place^.srcbase < 0) or (j <= 0) or (j > MAXIC) then error('proc place err') else place^.length := j end end end end { procsrch } ; begin { buildplaces } nbytes := sp^.srcfile^.segtbl.diskinfo[sp^.srcseg].codeleng; nblocks := (nbytes+511) div 512; if memavail-400 < nblocks*256 then error('sep seg 2 big') else begin { alloc space in heap } mark(heap); n := nblocks; repeat new(cp); n := n-1 until n <= 0; if blockread(sp^.srcfile^.code^, heap^, nblocks, sp^.srcfile^.segtbl.diskinfo[sp^.srcseg].codeaddr) <> nblocks then error('sep seg read err') else begin cp := getcodep(ord(heap)); nprocs := fetchbyte(cp, nbytes-1); if (nprocs < 0) or (nprocs > MAXPROC) then error('bad proc dict') else procsrch(sp^.symtab) end; release(heap) end end { buildplaces } ; begin { phase2 } mark(heapbase); unitwrite(3, heapbase^, 35); { read link info for host segs } dumpseps := TRUE; { assume we don't need sep segs } for s := 0 to MAXSEG do if seginfo[s] <> NIL then case seginfo[s]^.segkind of LINKED: ; { nothin } UNITSEG: readlinkinfo(seginfo[s], [PUBLREF, PRIVREF, UNITREF, CONSTDEF,EXTPROC, EXTFUNC]); SEPRTSEG: readlinkinfo(seginfo[s], [GLOBREF, GLOBDEF, CONSTDEF,SEPPROC, SEPFUNC]); HOSTSEG: readlinkinfo(seginfo[s], [PUBLDEF, CONSTDEF, EXTPROC, EXTFUNC]); SEGPROC: readlinkinfo(seginfo[s], [EXTPROC, EXTFUNC]) end { cases } ; { now do sep list elements } if dumpseps then seplist := NIL; sp := seplist; while sp <> NIL do begin readlinkinfo(sp, reflitypes+[CONSTDEF, GLOBDEF, SEPPROC, SEPFUNC]); sp := sp^.next end; { build proc place entries for sep segs } if seginfo[MASTERSEG]^.segkind = SEPRTSEG then buildplaces(seginfo[MASTERSEG]); sp := seplist; while sp <> NIL do begin buildplaces(sp); sp := sp^.next end; if errcount > 0 then exit(linker) end { phase2 } ;