!*********************************************************************** !* !* LINK - object file linker !* !*********************************************************************** ! ! !*********************************************************************** !* !* Constants !* !*********************************************************************** ! constant integer maxfiles= 256; ! Maximum number of input files constant integer ssobjfiletype= 1 constant integer sscharfiletype= 3 constant integer sspdfiletype= 6 constant integer instream= 81; ! Control input stream constant byte integer array hex(0:15)= c '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' constant string (1) snl= " " ! ! !*********************************************************************** !* !* Record formats !* !*********************************************************************** ! record format af(integer start, len, props) record format l1f(integer link, loc, string (31) iden) record format l4f(integer link, disp, l, a, string (31) iden) record format l78f(integer link, refloc, string (31) iden) record format l9f(integer link, refarray, l, string (31) iden) record format l13f(integer link, a, disp, len, rep, addr) record format l14f(integer link, n) record format ofmf(integer n, record (af) array area(1:7)) record format ohf(integer dataend, datastart, filesize, filetype, sum, datetime, lda, ofm) record format rf(integer conad, filetype, datastart, dataend) ! own integer array format ldataf(0:14) own integer array format reflocaf(1:32768) ! ! !*********************************************************************** !* !* Subsystem references !* !*********************************************************************** ! external routine spec changefilesize alias "S#CHANGEFILESIZE"(string (31) file, integer newsize, integer name flag) external integer map spec comreg alias "S#COMREG"(integer i) external routine spec connect alias "S#CONNECT"(string (31) file, integer mode, hole, prot, record (rf) name r, integer name flag) external routine spec define alias "S#DEFINE"(integer chan, string (31) iden, integer name afd, flag) external routine spec disconnect alias "S#DISCONNECT"(string (31) file, integer name flag) external string function spec failuremessage alias "S#FAILUREMESSAGE"(integer mess) external routine spec lput alias "S#LPUT"(integer type, p1, p2, p3) external routine spec move alias "S#MOVE"(integer length, from, to) external routine spec outfile alias "S#OUTFILE"(string (31) file, integer size, hole, prot, integer name conad, flag) external integer function spec parmap alias "S#PARMAP" external routine spec prompt(string (255) s) external routine spec psysmes alias "S#PSYSMES"(integer root, mess) external routine spec setfname alias "S#SETFNAME"(string (63) s) external routine spec setpar alias "S#SETPAR"(string (255) s) external routine spec set return code(integer i) external routine spec setwork alias "S#SETWORK"(integer name ad, flag) external string function spec spar alias "S#SPAR"(integer n) external routine spec uctranslate alias "S#UCTRANSLATE"(integer ad, len) external string function spec uinfs(integer entry) ! ! !*********************************************************************** !* !* Common routines !* !*********************************************************************** ! routine phex(integer i, width) integer j ! for j = width-4, -4, 0 cycle printsymbol(hex((i>>j)&x'f')) repeat end ; ! of phex ! !----------------------------------------------------------------------- ! integer function linker(integer nfiles, integer array name b, string (31) array name c, string (31) file) integer i, l, link, total, fbase, newsize, map, flag, histot integer pr, fillsize, lh, p, p1, res integer array base, size, start, totalsize, props(1:7) integer array histbeg, histlength, dt(1:nfiles) integer array t(1:8) integer array name ldata record (rf) rr record (ohf) name r record (l1f) name r1, r1c record (l4f) name r4, r4c record (ofmf) name ofm string name iden routine spec generate load data(integer lbase, fbase) ! res = 0 map = comreg(27)&x'20000' lput(0, 0, 0, 0); ! Open object file total = 0 histot = 5; ! Size of basic history data if map#0 then start newline printstring(" File CODE GLA PLT SST UST ICMN ISTK") newline finish for i = 1, 1, 7 cycle base(i) = 0 size(i) = 0 start(i) = 0 totalsize(i) = 0 props(i) = 0 repeat ! for i = 1, 1, nfiles cycle fbase = b(i) r == record(fbase) dt(i) = r_datetime ldata == array(fbase+r_lda, ldataf) ofm == record(fbase+r_ofm) p = fbase+ldata(12); ! Points to start of file history histbeg(i) = p p1 = p; ! Find end of history data while byteinteger(p1)#0 cycle p1 = p1+2+byteinteger(p1+1) repeat histlength(i) = p1-p histot = histot+histlength(i)+length(c(i))+8 ! Space for name and other odd bits t(l) = 0 for l = 1, 1, 8 ! for l = 1, 1, 7 cycle start(l) = ofm_area(l)_start size(l) = ofm_area(l)_len props(l) = props(l)!ofm_area(l)_props if l=1 then start ; ! Look for code going over segment boundary if (base(l)+16)&x'fffc0000'#(base(l)+size(l)+16)&x'fffc0000' then start fillsize = x'40000'-((base(l)+16)&x'3ffff') lput(31, fillsize, 0, 0); ! Fill up to end of segment with zeros t(1) = fillsize t(8) = fillsize totalsize(l) = totalsize(l)+fillsize lput(6, 32, 0, addr(t(1))); ! Write out dummy component t(8) = 0; ! Reset for real code area base(l) = base(l)+fillsize finish if map#0 then start ; ! Defer listing, in case base increased by filler write(i, 3) spaces(2) for pr = 1, 1, 7 cycle phex(base(pr), 24) spaces(2) repeat printstring(c(i).snl) finish finish lput(30+l, size(l), 0, start(l)+fbase) base(l) = base(l)+size(l) t(l) = size(l) totalsize(l) = totalsize(l)+t(l) t(8) = t(8)+t(l) repeat ! generate load data(fbase+r_lda, fbase) lput(6, 32, 0, addr(t(1))); ! Terminate this set of areas repeat ! if map#0 then start printstring(snl."Totals".snl) t(8) = 0 spaces(6) for l = 1, 1, 7 cycle phex(totalsize(l), 24) t(8) = t(8)+totalsize(l) spaces(2) repeat printstring(file.snl) finish lput(7, 32, 0, addr(t(1))); ! Finish off object file ! ! Now check for duplicate procedure and data entries, and add the file history ! connect(file, 0, 0, 0, rr, flag); ! Get connect address of file if flag=0 then start ; ! Only do all this if file connected OK fbase = rr_conad r == record(fbase) ldata == array(fbase+r_lda, ldataf) ! link = ldata(1); ! List 1 - procedure entries while link#0 cycle r1 == record(fbase+link) iden == r1_iden; ! Test against this one l = r1_link while l#0 cycle r1c == record(fbase+l) if iden=r1c_iden then start printstring("Warning - Duplicate procedure entry - ".iden) res = 290 newline finish l = r1c_link repeat link = r1_link repeat ! link = ldata(4); ! List 4 - data entries while link#0 cycle r4 == record(fbase+link) iden == r4_iden; ! Test against this one l = r4_link while l#0 cycle r4c == record(fbase+l) if iden=r4c_iden then start printstring("Warning - Duplicate data entry - ".iden) res = 290 newline finish l = r4c_link repeat link = r4_link repeat ! if map#0 then start ; ! Print file header at end of map printstring(snl."Header".snl) for i = fbase, 4, fbase+28 cycle phex(integer(i), 32) space repeat newline finish ! ! Add the file history ! p = r_dataend newsize = r_filesize if newsize<p+histot then start ! Need to extend file newsize = p+histot changefilesize(file, newsize, flag) if flag=261 then start ; ! VM hole too small disconnect(file, flag) changefilesize(file, newsize, flag) finish finish if flag=0 then connect(file, 3, 0, 0, rr, flag) ! Connect in write mode if flag#0 then start printstring("Warning - Cannot include file history or property codes".snl." -") printstring(failuremessage(flag)) res = flag ->err finish fbase = rr_conad; ! File may have moved r == record(fbase) r_filesize = (newsize+4095)//4096*4096 ! In case it changed ofm == record(fbase+r_ofm) ofm_area(i)_props = props(i) for i = 1, 1, 7 ! Fill in revised property codes ldata == array(fbase+r_lda, ldataf) ldata(12) = r_dataend; ! Point to end of file, where history will go lh = fbase+r_dataend; ! Insert history header byteinteger(lh) = 3; ! Initialise - "COMPONENTS" byteinteger(lh+1) = 0; ! Zero length for information part lh = lh+2 for i = 1, 1, nfiles cycle ; ! For each file byteinteger(lh) = 4; ! Object name string(lh+1) = c(i) lh = lh+2+length(c(i)) if byteinteger(histbeg(i))=3 then start byteinteger(lh) = 5; ! Linked object - date linked finish else byteinteger(lh) = 6 ! Object file - date compiled byteinteger(lh+1) = 4; ! Length of date move(4, addr(dt(i)), lh+2); ! Date from file header lh = lh+6 if histlength(i)>0 then move(histlength(i), histbeg(i), lh) lh = lh+histlength(i) repeat byteinteger(lh) = 7; ! "END" of components byteinteger(lh+1) = 0; ! Zero length for information part byteinteger(lh+2) = 0; ! End of history data - terminate lh = lh+3 r_dataend = lh-fbase; ! Set new length of file finish ! err: ! result = res ! ! routine generate load data(integer lbase, fbase) integer i, l, area, refarray, link integer array name refloc integer array name ldata record (l1f) name r1 record (l4f) name r4 record (l78f) name r78 record (l9f) name r9 record (l13f) name r13 record (l14f) name r14 ! ldata == array(lbase, ldataf) ! ! Process procedure and data entries ! link = ldata(1); ! List 1 - procedure entries while link#0 cycle r1 == record(fbase+link) lput(11, (r1_loc&x'80000000')!(r1_loc>>24), r1_loc&x'00ffffff', addr(r1_iden)) link = r1_link repeat ! link = ldata(4); ! List 4 - data entries while link#0 cycle r4 == record(fbase+link) lput(14, (r4_a<<24)!r4_l, r4_disp, addr(r4_iden)) link = r4_link repeat ! ! Now deal with data references ! link = ldata(9); ! List 9 - data references while link#0 cycle r9 == record(link+fbase) if r9_refarray&x'80000000'#0 then l = 10 else l = 15 ! See if 'common' area refarray = r9_refarray&x'7fffffff' ! Remove bit refloc == array(fbase+refarray+4, reflocaf) for i = 1, 1, integer(fbase+refarray) cycle ! Count of pointers to this reference area = refloc(i)&x'ff000000' lput(l, area!r9_l, refloc(i)&x'00ffffff', addr(r9_iden)) repeat link = r9_link repeat ! ! Process static and dynamic procedure references ! for i = 7, 1, 8 cycle link = ldata(i); ! Lists 7 and 8 - procedure references while link#0 cycle r78 == record(fbase+link) l = r78_refloc lput(i+5, l>>24, l&x'00ffffff', addr(r78_iden)) link = r78_link repeat repeat ! ! Process initialisation data ! link = ldata(13); ! List 13 - initialisation data while link#0 cycle r13 == record(fbase+link) l = r13_len if l=1 then start lput(r13_a+30, r13_rep, r13_disp, r13_addr) else lput(r13_a+40, (l<<24)!r13_rep, r13_disp, fbase+r13_addr) finish link = r13_link repeat ! ! Process generalised relocation blocks ! link = ldata(14); ! List 14 - generalised relocation blocks while link#0 cycle r14 == record(fbase+link) lput(26, ((r14_n<<1)+1)<<2, 0, addr(r14_n)) link = r14_link repeat end ; ! of generate load data end ; ! of linker ! !----------------------------------------------------------------------- ! routine readline(string name s) integer c ! on event 9 start ; ! Trap 'Input Ended' if s="" then s = ".END" uctranslate(addr(s)+1, length(s)) return finish ! s = "" cycle cycle readsymbol(c) exit if c=nl continue if c=' ' s <- s.tostring(c) repeat exit unless s="" repeat uctranslate(addr(s)+1, length(s)) end ; ! of readline ! ! !*********************************************************************** !* !* L I N K !* !*********************************************************************** ! external routine link(string (255) parms) integer nfiles, flag2, conad, total, i, ad, flag, afd string (6) owner string (31) object, file record (rf) rr record (ohf) name h integer array name ldata integer array inadds(1:maxfiles) string (31) array inputs(1:maxfiles) ! set return code(272); ! In case of catastrophic failure owner = uinfs(1) prompt("Link: ") total = 0 nfiles = 0 flag = 0 ! setpar(parms) if parmap>1 then start flag = 263; ! Wrong number of parameters ->merr finish ! ! Use non-default input if requested ! file = spar(1); ! Control input file if file#"" then start if "*"#file#".IN" then start connect(file, 1, 0, 0, rr, flag) ->merr if flag#0 if rr_filetype#sscharfiletype then start setfname(file) flag = 267; ! Invalid filetype ->merr finish finish define(instream, file, afd, flag) ->merr if flag#0 selectinput(instream) finish ! cycle readline(file) exit if file=".END" if nfiles=maxfiles then start flag = 277; ! Too many input files ->merr finish connect(file, 1, 0, 0, rr, flag2) if flag2#0 then start psysmes(8, flag2) flag = flag2 continue finish conad = rr_conad h == record(conad) if h_filetype#ssobjfiletype then start setfname(file) printstring("Warning -".failuremessage(267)) ! Invalid filetype flag = 267 continue finish ldata == array(conad+h_lda, ldataf) if ldata(5)#0 then start printstring("Warning - Cannot link bound object file ".file.snl) flag = 267 continue finish unless length(file)>7 and charno(file, 7)='.' then start file = owner.".".file finish nfiles = nfiles+1 inputs(nfiles) = file inadds(nfiles) = conad repeat ! if nfiles=0 then start flag = 305; ! No input files ->merr finish ! prompt("Object: ") readline(object) unless length(object)>7 and charno(object, 7)='.' then start object = owner.".".object finish for i = 1, 1, nfiles cycle if object=inputs(i) then start flag = 266; ! Inconsistent file use ->merr finish repeat connect(object, 1, 0, 0, rr, flag2); ! Check for PD overwrite if flag2=0 then start if rr_filetype=sspdfiletype then start flag = 310; ! Attempt to overwrite PD file ->merr finish finish ! outfile(object, -4096, 0, 0, conad, flag2); ! Try to create output file if flag2#0 then start psysmes(10, flag2); ! Create file failed flag = flag2 ->err finish comreg(52) = addr(object); ! Picked up by 'lput' ad = x'40000' setwork(ad, flag2); ! Create 'lput' workfile if flag2#0 then start psysmes(10, flag2); ! Create workfile failed flag = flag2 ->err finish ! i = linker(nfiles, inadds, inputs, object) if flag=0 then flag = i disconnect(object, flag); ! This is vital for diagnostics to work newline write(nfiles, 1) printstring(" Files linked successfully") newline ->err ! merr: psysmes(28, flag) ! err: set return code(flag) end ; ! of link end of file