home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / asmutl / smmaclnk.ark / LNK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-09-10  |  18.9 KB  |  644 lines

  1. /*
  2. ** LNK.C -- Small-Mac Linkage Editor
  3. **
  4. **    Copyright 1985 J. E. Hendrix
  5. **
  6. ** Usage: LNK [-B] [-G#] [-M] program [module/library...]
  7. **
  8. ** -B            A BIG program is being linked, so use all
  9. **            of free memory for the symbol table and load the
  10. **            program to disk entirely.  This is slower but it
  11. **            gets the job done.
  12. **
  13. ** -G#            Make program absolute at # (hex) and
  14. **            output as "program.LGO" instead of "program.COM".
  15. **
  16. ** -M            Monitor linking activity.
  17. **
  18. ** program        A file specifier for the program being linkrd.
  19. **            The default, and only allowed, extension is REL.
  20. **
  21. ** module/library...    A list of zer or more module (.rel) and/or
  22. **            library (.LIB) files.  Each module is linked to
  23. **            the program and the libraries are searched for
  24. **            just those modules which satisfy one or more
  25. **            unresolved external references.
  26. **
  27. ** NOTE:  Merely declaring a symbol to be external willcause
  28. ** its module to be loaded.  It need not actually be referenced.
  29. **
  30. ** terminal module; i.e., the module which must be loaded last
  31. ** of all.  That module contains special code which identifies
  32. ** the physical end of the program and the beginning of free
  33. ** memory.  The linker is sensitive to its name and waits until
  34. *  all other modules are loaded before loading the terminal module.
  35. **
  36. ** The absence of an extension, or a .REL extension, identifies a module;
  37. ** whereas, a .LIB extension identifies a library.  If necessary, a
  38. ** library is rescanned to resolve backward external references between
  39. ** modules within the library.  Module files and libraries are processed
  40. ** in the order in which they occur in the command line.
  41. **
  42. ** Drive Designators (e.g. B:):
  43. **    - allowed with module and library names
  44. **    - program drive designator locates the input .REL file
  45. **    - output goes to the defaoul drive
  46. **
  47. ** Filename Extensions:
  48. **    - must specify .LIB with library name
  49. **    - standard extensions are:
  50. **
  51. **    .REL = relocatable object module
  52. **    .LIB = library of object modules
  53. **    .NDX = index to library (not user specified)
  54. **    .COM = CP/M command file (default output)
  55. **    .LGO = Load-and-go file (-G# output)
  56. **    .O$  = temporary overflow file
  57. **    .R$  = temporary reference file
  58. **
  59. ** Enter control-S to pause and control-C to abort.
  60. **
  61. ** NOTE: Compile only with Small-C 2.1 (edit level 63) or later.
  62. ** Edit 63 fixes CSYSLIB so that when it overflows a buffer while
  63. ** writing into a file it will no longer assume that it is at the
  64. ** end of the file.  This prevents it from padding sector with
  65. ** 1A (hex) in the middle of the file when random access is being used.
  66. */
  67. #include <stdio.h>
  68. #include "notice.h"
  69. #include "rel.h"
  70.  
  71. #define NODEBUG        /* don't compile debug displays */
  72. #define NOCCARGC    /* dom't pass arg counts to functions */
  73. #define NAMESIZE   15
  74. #define MAXFIL     10
  75. #define STACK     512    /* allow for stack space */
  76. #define AUXBUF   2048    /* aux buffer for reference file */
  77. #define MAXOPEN     4    /* maximum files opened */
  78. #define OHDOPEN   164    /* memory overhead per open file */
  79. #define COMBASE  259    /* 0100H + 3 */
  80. #define RET     201    /* RET instruction (0C9H) */
  81. #define JMP      195    /* JMP instruction (0C3H) */
  82. #define RES       -1    /* value of resolved ext ref */
  83. #define XRPLUS    -2    /* ext-ref-plus-offset flag */
  84. #define TMNAME  "END"    /* terminal module name */
  85. #define MODEXT ".REL"
  86. #define LIBEXT ".LIB"
  87. #define NDXEXT ".NDX"
  88. #define COMEXT ".COM"
  89. #define LGOEXT ".LGO"
  90. #define OFLEXT  ".O$"
  91. #define REFEXT  ".R$"
  92.  
  93. /*
  94. ** symbol table definitions
  95. */
  96. #define NXT    0        /* next-entry pointer */
  97. #define VAL    2        /* offset value */
  98. #define SYM    4        /* symbol */
  99. #define SSZ (SYM+MAXSYM+1)    /* size of tabl entry */
  100. #define HIGH 127        /* high-value byte */
  101. #define CUSHION  (200*SSZ)    /* reserved for table at overflowpoint */
  102. char high[] = {HIGH,0};        /* high-value symbol */
  103.  
  104. /*
  105. ** global variables
  106. */
  107. char
  108.  *xr,            /* external reference */
  109.  *nxt,            /* next in ext ref chain */
  110.  *ep,            /* entry point */
  111.  *buffer,        /* beginning of code buffer */
  112.  *bnext,        /* next byte in code buffer */
  113.  *sfree,        /* head of free entry list */
  114.  *snext,        /* next symbol table entry */
  115.  *cloc,            /* location counter */
  116.  *cmod,            /* module loction */
  117.  *cbase,        /* base address */
  118.  *csize,        /* program size (fake unsigned) */
  119.  *goloc,        /* go location */
  120.  *cdisk,        /* disk overflow location */
  121.  *epfirst,        /* first entry point */
  122.  *epprev,        /* previous entry point */
  123.  *epnext,        /* next entry point */
  124.  *xrfirst,        /* first external reference */
  125.  *xrprev,        /* previous external reference */
  126.  *xrnext,        /* next external reference */
  127.   modname[MAXSYM+1],    /* name of curent module */
  128.   infn   [NAMESIZE],    /* input filename */
  129.   ndxfn  [NAMESIZE],    /* index filename */
  130.   tmfn   [NAMESIZE],    /* terminal-module library name */
  131.   csfn   [NAMESIZE],    /* code seg filename */
  132.   crfn   [NAMESIZE],    /* code rel filename */
  133.   outfn  [NAMESIZE];    /* output filename */
  134.  
  135. int
  136.   lgo,        /* load-and-go format? */
  137.   monitor,    /* monitor activity? */
  138.   instr,    /* instruction to plant at 0000 */
  139.   addr,        /* start address */
  140.   ref,        /* reference to program relative item */
  141.   big,        /* linking a big program? */
  142.   xrplus,    /* value of offset for next ext ref */
  143.   xrpflag=XRPLUS,    /* value of xrplus flag */
  144.   ndxfd,    /* index fd */
  145.   inblock,    /* block of next library member */
  146.   inbyte,    /* byte of block of next library member */
  147.   tmblock,    /* block of terminal module in tmfn */
  148.   tmbyte,    /* byte of terminal module in tmblock */
  149.   csfd,        /* code segment fd */
  150.   crfd,        /* code relative index fd */
  151.   outfd;    /* output fd */
  152.  
  153. extern int Uchrpos[];    /* lives in CSYSLIB */
  154.  
  155. main(argc,argv) int argc, argv[]; {
  156.   fputs("Small-Mac Linkage Editor, ", stderr); fputs(VERSION, stderr);
  157.   fputs(CRIGHT1, stderr);
  158.   getsw(argc, argv);        /* fetch and remember switches */
  159.   getmem();            /* acquire maximum memory buffer */
  160.   phase1(argc, argv);        /* load and link */
  161.   if(!okay()) abort(7);        /* quit early */
  162.   phase2();            /* generate final output */
  163.   }
  164.  
  165. /*
  166. ** get as much memory as possible for symbol table
  167. */
  168. getmem() {
  169.   char sz[8];
  170.   int max;
  171.   max = avail(YES);        /* how much available? */
  172.   max -= STACK + AUXBUF + (MAXOPEN * OHDOPEN);
  173.   buffer = bnext = malloc(max);    /* allocate space */
  174.   snext  = buffer + (max - SSZ);    /* first enry */
  175.   sfree  = 0;                /* np reusable entries yet */
  176. #ifdef DEBUG
  177.   if(monitor) {itou(max, sz, 8); puts2(sz, "Byte Buffer");}
  178. #endif
  179.   newtbl(&epfirst);        /* set low and high ent pts */
  180.   newtbl(&xrfirst);        /* set low and high ext refs */
  181.   }
  182.  
  183. /*
  184. ** get next module name
  185. */
  186. getname() {
  187.   if(getrel() == PNAME) {
  188.     strcpy(modname, symbol);
  189.     return (YES);
  190.     }
  191.   if(item == EFILE) return (NO);
  192.   error2(infn, " - Corrupted");
  193.   }
  194.  
  195. /*
  196. ** read next entry from library index file
  197. */
  198. getndx() {
  199.   if(read(ndxfd, &inblock, 2) != 2 ||    /* next block */
  200.      read(ndxfd, &inbyte, 2) != 2) {    /* next byte in block */
  201.     error2("- Error Reading ", infn);
  202.     }
  203.   }
  204.  
  205. /*
  206. ** get switches from commandline
  207. */
  208. getsw(argc, argv) int argc, *argv; {
  209.   char arg[NAMESIZE];
  210.   int argnbr, b, len;
  211.   argnbr = 0;
  212.   while(getarg(++argnbr, arg, NAMESIZE, argc, argv) != EOF) {
  213.     if(arg[0] != '-') continue;        /* skip file names */
  214.     if(toupper(arg[1]) == 'G') {
  215.       lgo = YES;
  216.       len = xtoi(arg + 2, &b);
  217.       if(len >= 0 && !arg[len + 2]) cbase = b; else usage();
  218.       }
  219.     else if(toupper(arg[1]) == 'B') big = YES;
  220.     else if(toupper(arg[1]) == 'M') monitor = YES;
  221.     else usage();
  222.     }
  223.   }
  224.  
  225. /*
  226. ** is symbol an unresolved ext ref?
  227. ** on return of true, xrnext -> matching entry
  228. */
  229. isunres() {
  230.   int i;
  231.   xrnext = getint(xrfirst);
  232.   while(xrnext) {
  233.     if((i = strcmp(symbol, xrnext + SYM)) < 0) return (NO);
  234.     if(i == 0) return (YES);
  235.     xrnext = getint(xrnext);
  236.     }
  237.   return (NO);
  238.   }
  239.  
  240. /*
  241. ** link external references to entry points
  242. */
  243. link() {
  244.   int cspg, csch;
  245.   cspg = ctell(csfd);        /* remember temp file position */
  246.   csch = ctellc(csfd);
  247.   xrnext = getint(xrprev = xrfirst);    /* first external reference */
  248.   epnext = getint(epfirst);        /* first entry point */
  249.   while(YES) {
  250.     if(strcmp(xrnext + SYM, epnext + SYM) > 0) {    /* xr > ep */
  251.       epnext = getint(epnext);
  252.       continue;
  253.       }
  254.     if(strcmp(xrnext + SYM, epnext + SYM) < 0) {    /* xr < ep */
  255.       xrnext = getint(xrprev = xrnext);
  256.       continue;
  257.       }
  258.     if(*(xrnext + SYM) != HIGH) {            /* xr = ep */
  259.       resolve();            /* resolve this ext ref */
  260.       putint(xrprev, getint(xrnext));    /* delink from xr chain */
  261.       putint(xrnext, sfree);        /* link to prev freed entry */
  262.       sfree = xrnext;            /* make first freed entry */
  263.       xrnext = getint(xrprev);        /* advance to next ext ref */
  264.       continue;                /* same ext ref in diff modules? */
  265.       }
  266.     break;
  267.     }
  268.   cseek(csfd, cspg, 0);            /* restore temp file position */
  269.   Uchrpos[csfd] = csch;
  270.   }
  271.  
  272. /*
  273. ** load a module
  274. */
  275. load() {
  276.   char str[8];
  277.   epprev = epfirst;            /* start at the very beginning */
  278.   xrprev = xrfirst;
  279.   do {
  280.     poll(YES);
  281.     switch(getrel()) {
  282.       case  DSIZE: if(!field) break;
  283.       default: error("- Unsupported Link Item");
  284.       case    ERR: error("_ Corrupt Module");
  285.       case  EPROG: if(type == PREL) {
  286.              puts2("Start In ", modname);
  287.              goloc = field + cmod;
  288.              }
  289.       case  ENAME: break;        /* bypass enames */
  290.       case XCHAIN: newsym(&xrprev, "xr");
  291.            break;
  292.       case EPOINT: newsym(&epprev, "ep");
  293.            break;
  294.       case  PSIZE: cmod = cloc;
  295.            if(monitor) {
  296.              itox(field, str, 8);
  297.              fputs(str, stdout); fputs(" Bytes at", stdout);
  298.              itox(cloc, str, 6);
  299.              fputs(str, stdout); fputs("'", stdout);
  300.              itox(cloc+cbase, str, 6);
  301.              fputs(str, stdout); puts2(" ", modname);
  302.              }
  303.            if(!csfd &&
  304.              (big || (bnext + field) > (snext - CUSHION))) {
  305.             cdisk = cloc;        /* disk overflow point */
  306.             csfd = open(csfn, "w+");/* open overflow file */
  307. #ifdef DEBUG
  308.             if(monitor) {
  309.               itox(cdisk, str, 8); puts2(str, " Overflow Point");
  310.             }
  311. #endif
  312.              }
  313.            break;
  314.       case  SETLC: field = field + cmod;
  315.            while(cloc < field) {    /* adj loc ctr */
  316.              if(csfd) write(csfd, "\0", 1);
  317.              else *bnext++ = 0;
  318.              ++cloc;
  319.              }
  320.            break;
  321.       case  XPOFF: write(crfd, &xrpflag, 2);    /* flag xr plus */
  322.            write(crfd, &field, 2);    /* xr offset */
  323.            break;
  324.       case   PREL: field = field + cmod;
  325.            if(csfd) write(csfd, &field, 2);    /* put on disk */
  326.            else {                /* put in memory */
  327.              putint(bnext, field);
  328.              bnext += 2;
  329.              }
  330.            write(crfd, &cloc, 2);    /* reference for pass 2 */
  331.            cloc += 2;
  332.            break;
  333.       case    ABS: if(csfd) write(csfd, &field, 1);    /* put on disk */
  334.            else *bnext++ = field;        /* put in memory */
  335.            ++cloc;
  336.            break;
  337.       }
  338.     } while(item != EPROG);
  339.   }
  340.  
  341. /*
  342. ** create new file specifier from an old one
  343. */
  344. newfn(dest, sour, ext) char *dest, *sour, *ext; {
  345.   if(sour[1] == ':' && strcmp(ext, NDXEXT)) sour += 2;
  346.   while(*sour && *sour != '.') *dest++ = *sour++;
  347.   strcpy(dest, ext);
  348.   }
  349.  
  350. /*
  351. ** store new symbol tableentry
  352. ** they arrive in alphanumeric order
  353. */
  354. newsym(prev, ts) int *prev; char *ts; {
  355.   char at[8], *cp, *new;
  356.   if(new = sfree) sfree = getint(sfree);    /* use oldentry */
  357.   else {
  358.     new = snext;
  359.     if((snext -= SSZ) < bnext) error("- Must Specify -B Switch");
  360.     }
  361.   cp = *prev;
  362.   while(strcmp(symbol, cp + SYM) >= 0) {    /* find position */
  363.     *prev = cp;
  364.     cp = getint(cp);
  365.     }
  366.   putint(new, cp);        /* point new entry ahead */
  367.   putint(*prev, new);        /* point prev entry here */
  368.   *prev = new;            /* this becomes prev entry */
  369.   if(type == PREL) field = field + cmod;/* adjust for module location */
  370.   putint(new + VAL, field);    /* load value */
  371.   strcpy(new + SYM, symbol);    /* load symbol */
  372. #ifdef DEBUG
  373.   if(monitor) {
  374.     itox(getint(new + VAL), at, 8);
  375.     fputs(at, stdout); fputs(" ", stdout);
  376.     fputs(ts, stdout); fputs(" ", stdout);
  377.     puts(symbol);
  378.     }
  379. #endif
  380.   }
  381.  
  382. /*
  383. ** initial table enries
  384. */
  385. newtbl(low) int *low; {
  386.   *low = snext;            /* always points to low entry */
  387.   strcpy(snext + SYM, "");    /* store low symbol */
  388.   putint(snext, snext - SSZ);    /* link to next (high) ysymbol */
  389.   snext -= SSZ;            /* now point to next entry */
  390.   strcpy(snext + SYM, high);    /* store high symbol */
  391.   putint(snext, 0);        /* end of chain */
  392.   snext -= SSZ;            /* bump to next entry */
  393.   }
  394.  
  395. /*
  396. ** get next module name
  397. */
  398. nxtmod() {
  399.   getndx();            /* get location and */
  400.   seek();            /* go straight to next member */
  401.   return (getname());
  402.   }
  403.  
  404. /*
  405. ** report the outcome and decide whether to quit
  406. */
  407. okay() {
  408.   int err; char *eplast;
  409.   err = eplast = 0;
  410.   xrnext = getint(xrfirst);    /* first external reference */
  411.   epnext = getint(epfirst);    /* first entry point */
  412.   while(YES) {
  413.     poll(YES);
  414.     if(strcmp(xrnext + SYM, epnext + SYM) > 0) {    /* ext > ent */
  415.       if(epnext == eplast) {
  416.     puts2("- Redundant: ", xrnext + SYM);
  417.     err = YES;
  418.     }
  419.       eplast = epnext;
  420.       epnext = getint(epnext);
  421.       continue;
  422.       }
  423.     if(strcmp(xrnext + SYM, epnext + SYM) < 0) {    /* ext < ent */
  424.       puts2("- Unresolved: ", xrnext + SYM);
  425.       err = YES;
  426.       xrnext = getint(xrnext);
  427.       continue;
  428.       }
  429.     if(*(xrnext + SYM) != HIGH) {            /* ext = ent */
  430.       xrnext = getint(xrnext);
  431.       continue;            /* same ext ref in diff modules? */
  432.       }
  433.     break;
  434.     }
  435.   if(err) return (NO);
  436.   return (YES);
  437.   }
  438.  
  439. /*
  440. ** load input files and library members
  441. */
  442. phase1(argc, argv) int argc, *argv; {
  443.   char sz[8];
  444.   int i, lib, eof;
  445.   eof = EOF;
  446.   cdisk = -1;            /* high value for pointer */
  447.   if(lgo) instr = RET;        /* load and go format */
  448.   else {instr = JMP; cbase = COMBASE;} /* com file format */
  449.   i = 0;
  450.   while(getarg(++i, infn, NAMESIZE, argc, argv) != EOF) {
  451.     if(infn[0] == '-') continue;    /* skip switches */
  452.     if(extend(infn, MODEXT, LIBEXT))
  453.      lib = YES;
  454.     else lib = NO;
  455.     if(!*outfn) {        /* first file name */
  456.       if(lgo) newfn(outfn, infn, LGOEXT);
  457.       else    newfn(outfn, infn, COMEXT);
  458.       newfn(csfn, infn, OFLEXT);
  459.       newfn(crfn, infn, REFEXT);
  460.       crfd = open(crfn, "w+");    /* open reference file */
  461.       auxbuf(crfd, AUXBUF);    /* extra buffering lowers head movement */
  462.       }
  463.     if(lib) search();        /* search library if unresolved ext refs */
  464.     else {
  465.       inrel = open(infn, "r");    /* must open */
  466.       getname();        /* program name */
  467.       load();            /* load module */
  468.       link();            /* link previousmodules */
  469.       close(inrel);        /* must close */
  470.       }
  471.     }
  472.   if(!*outfn) usage();
  473.   if(*tmfn) {            /* must get terminal module */
  474.     inrel = open(tmfn, "r");
  475.     inblock = tmblock; inbyte = tmbyte;
  476.     seek();    getname();    load();    link();
  477.     close(inrel);
  478.     }
  479.   csize = cloc;
  480.   if(ferror(crfd)) error2("- Error Writing ", crfn);
  481.   write(crfd, &eof, 2);
  482.   rewind(crfd);
  483.   if(ferror(csfd)) error2("- Error Writing ", csfn);
  484.   rewind(csfd);
  485.   itox(csize, sz, 8); puts2(sz, " Bytes (hex)");
  486.   itou(csize, sz, 8); puts2(sz, " Bytes (dec)");
  487.   }
  488.  
  489. /*
  490. ** generate absoluteoutput in COM or LGO format
  491. **
  492. ** COM format: JMP <start> <program>
  493. **
  494. ** LGO format: RET <start> <prog-base> <prog-size> <program>
  495. */
  496. phase2() {
  497.   char at[5];
  498.   outfd = open(outfn, "w");
  499.   write(outfd, &instr, 1);    /* plant first instruction */
  500.   addr = cbase + goloc;
  501.   write(outfd, &addr, 2);    /* with its address */
  502.   if(lgo) {
  503.     write(outfd, &cbase, 2);    /* where to load for execution */
  504.     write(outfd, &csize, 2);    /* how many bytes to load */
  505.     }
  506.   cloc = -1;            /* allow efficient pre-increment */
  507.   readref();            /* get first reference */
  508.   while(++cloc < csize) {    /* while more code */
  509.     if(cloc != ref) {        /* not relative reference */
  510.       if(cloc < cdisk)
  511.     field = *(cloc + buffer);
  512.       else read(csfd, &field, 1);
  513.       write(outfd, &field, 1);    /* copy one byte as is */
  514.       continue;
  515.       }
  516.     if(cloc < cdisk)        /* get next 2-byte relative item */
  517.       field = getint(cloc + buffer);
  518.     else read(csfd, &field, 2);
  519.     field = field + cbase;    /* make absolute */
  520.     if(xrplus) {
  521.       field += xrplus;        /* apply offset */
  522.       xrplus = 0;
  523.       }
  524.     write(outfd, &field, 2);    /* copy 2 byes adjusted */
  525.     readref();            /* get next reference */
  526.     ++cloc;            /* need additional increment */
  527.     }
  528.   if(ferror(outfd))  error2("- Error Writing ", outfn);
  529.   close(outfd);
  530.   if(csfd) {
  531.     if(ferror(csfd)) error2("- Error Reading ", csfn);
  532.     close(csfd);
  533.     delete(csfn);
  534.     }
  535.   if(ferror(crfd))   error2("- Error Reading ", crfn);
  536.   close(crfd);
  537.   delete(crfn);
  538.   }
  539.  
  540. /*
  541. ** read next reference
  542. */
  543. readref() {
  544.   read(crfd, &ref, 2);        /* get next reference */
  545.   if(ref == XRPLUS) {        /* ext ref offset flag? */
  546.     read(crfd, &xrplus,2);    /* yes, get offset value */
  547.     read(crfd, &ref, 2);    /* then get reference */
  548.     }
  549.   }
  550.  
  551. /*
  552. ** resolve external references to a given symbol
  553. */
  554. resolve() {
  555.   char at[5];
  556.   if(!(xr = getint(xrnext + VAL))) return;    /* head of ext ref chain */
  557.   ep = getint(epnext + VAL);            /* entry point address */
  558.   do {
  559. #ifdef DEBUG
  560.     if(monitor) {
  561.       poll(YES);
  562.       fputs("Resolving ", stdout);
  563.       itox(xr, at, 5); fputs(at, stdout);
  564.       fputs(" to ", stdout);
  565.       itox(ep, at, 5); fputs(at, stdout);
  566.       puts2(" ", xrnext + SYM);
  567.       }
  568. #endif
  569.     if(xr < cdisk) {            /* in memory */
  570.       nxt = getint(xr + buffer);
  571.       if(nxt == 0) ep += cbase;        /* end of chain is absolute */
  572.       putint(xr + buffer, ep);
  573.       }
  574.     else {                /* on disk */
  575.       xrseek(xr - cdisk); read(csfd, &nxt, 2);
  576.       if(nxt == 0) ep += cbase;        /* end of chain is absolute */
  577.       xrseek(xr - cdisk); write(csfd, &ep, 2);
  578.       }
  579.     } while(xr = nxt);
  580.   }
  581.  
  582. /*
  583. ** search a library
  584. */
  585. search() {
  586.   int linked;
  587.   linked = NO;
  588.   newfn(ndxfn, infn, NDXEXT);
  589.   ndxfd = open(ndxfn, "r");
  590.   inrel = open(infn, "r");
  591.   while(YES) {                /* rescan till done */
  592.     while(nxtmod()) {
  593.       if(strcmp(modname, TMNAME) == 0) {    /* will load this one last */
  594.     strcpy(tmfn, infn);
  595.     tmblock = inblock;
  596.     tmbyte = inbyte;
  597.     continue;
  598.     }
  599.       while(getrel() == ENAME) {
  600.     poll(YES);
  601.     if(isunres()) {            /* unresolved reference? */
  602.       load();            /* load module */
  603.       link();            /* link to previous ones */
  604.       linked = YES;
  605.       break;
  606.       }
  607.     }
  608.       }
  609.     if(!linked) break;
  610.     linked = NO;
  611.     rewind(ndxfd);
  612.     }
  613.   close(ndxfd);
  614.   close(inrel);
  615.   }
  616.  
  617. /*
  618. ** seek to next member in old library
  619. */
  620. seek() {
  621.   if(inblock == EOF) error("- Premature End of Index");
  622.   if(cseek(inrel, inblock, 0) == EOF)
  623.     error("- Corrupt Library or Index");
  624.   Uchrpos[inrel] = inbyte;
  625.   inrem = 0;            /* force getrel() to read a byte */
  626.   }
  627.  
  628. /*
  629. ** abort with usage message
  630. */
  631. usage() {
  632.   error("Usage: LNK [-B] [-G#] [-M] program [module/library...]");
  633.   }
  634.  
  635. /*
  636. ** seek external reference
  637. */
  638. xrseek(byte) int byte; {
  639.   if(cseek(csfd, (byte >> 7) & 511, 0) == EOF)
  640.     error2("- Seek Error in ", csfn);
  641.   Uchrpos[csfd] = byte & 127;
  642.   }
  643.  {
  644.   if(cseek(csfd, (byt