home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / BDSC / BDSC-2 / NL2.C < prev    next >
Text File  |  2000-06-30  |  24KB  |  887 lines

  1. /* L2.C    New linker for BDS C
  2.  
  3.         Written 1980 by Scott W. Layson
  4.         This code is in the public domain.
  5.  
  6. This is an improved linker for BDS C CRL format.  It eliminates the
  7. jump table at the beginning of each function in the object code,
  8. thus saving up to 10% or so in code space with a slight improvement
  9. in speed.  
  10.  
  11. Compile:   A>cc nl2.c -e4800 -o    (use -e4a00 if using CLINK instead of L2)
  12.        A>cc portio.c
  13. link:       A>l2 nl2 portio
  14.  
  15.         [81.4.27] Overlay capability now exists.  It works a bit
  16.                      differently from CLINK:  the option
  17.                    -ovl <base name> <origin>
  18.                  causes symbols to be read from <base name>.sym
  19.                      and produces a segment linked at <origin>.  It
  20.                      also defaults the name of the overlay function to
  21.                      that of the first .crl file (to override, put -m
  22.                      after the -ovl), and replaces c.ccc with a jump
  23.                      to that function.  Also note that the base
  24.                      symbols are loaded at the very beginning, so name
  25.                      conflicts are always resolved in favor of the
  26.                      base.
  27.  
  28. Changes made by EBM:
  29.     1) added -2 and -d flags
  30.     2) fixed so that duplicates work right when two passes are made
  31.     3) changed to use hashing for symbols
  32.     4) added -f flag
  33.     5) change "two-pass" processing to write file as it goes and go
  34.        back through for fixups (this removes the -2 flag)
  35.     6) added -o flag for choosing output file name
  36.     7) made symbols grow down from top so table size is variable;
  37.        also added more checks for various tables overflowing
  38. */
  39.  
  40.  
  41. /**************** Globals ****************/
  42.  
  43. /*    #define SDOS                /* comment this out for CP/M */*/
  44. /*    #define OVERLAYS            /* comment this out for shorter version */*/
  45. /*    #define MARC                /* for MARC cross-linker version */*/
  46.  
  47.  
  48. #include "bdscio.h"            /* for i/o buffer defs */
  49.  
  50. #define NUL        0
  51. #define FLAG        char
  52.  
  53. #define STDOUT        1
  54.  
  55. int needfixups;            /* set if we need to go back through */
  56.  
  57. /* Sizes */
  58. #define FNAMESIZE     15        /* length of file names */
  59. #define MAXPROGS     30        /* max number of program files */
  60. #define MAXLIBS     20        /* max number of library files */
  61.  
  62. /* function table */
  63. struct funct {
  64.     char fname[9];
  65.     FLAG flinkedp;            /* indicates whether found or external */
  66.     unsigned faddr;        /* address of function (initially 0) */
  67.     unsigned fchain;        /* chain of fixups */
  68.     struct funct *next;        /* next one in same hash bucket */
  69.     } *ftab, *ftabend;
  70.  
  71. /* Hash table */
  72. struct funct *hashtab[256];
  73.  
  74. #define LINKED        1        /* (flinkedp) function really here */
  75. #define EXTERNAL    2        /* function defined in separate symbol table */
  76.  
  77. char fdir[512];            /* CRL file function directory */
  78.  
  79. /* command line parameters etc. */
  80. int nprogs, nlibs;
  81. char progfiles [MAXPROGS][FNAMESIZE];    /* program file names */
  82. char libfiles  [MAXLIBS] [FNAMESIZE];    /* library file names */
  83. FLAG symsp,                    /* write symbols to .sym file? */
  84.     appstatsp,                /* append stats to .sym file? */
  85.     sepstatsp;                /* write stats to .lnk file? */
  86. FLAG maxmemp,                    /* punt MARC shell? */
  87.     marcp;                    /* uses CM.CCC */
  88. unsigned cccsize;                /* for fixup processing */
  89. char mainfunct[10];
  90. char objname[FNAMESIZE];            /* name for output file */
  91. FLAG objset;                    /* was -O specified ? */
  92. FLAG ovlp;                    /* make overlay? */
  93. char symsfile[FNAMESIZE];        /* file with symbols (for overlays) */
  94. FLAG    debug;                    /* extra printouts */
  95.  
  96. /* useful things to have defined */
  97. struct inst {
  98.     char opcode;
  99.     char *address;
  100.     };
  101.  
  102. union ptr {
  103.     unsigned u;            /* an int */
  104.     unsigned *w;            /* a word ptr */
  105.     char *b;                /* a byte ptr */
  106.     struct inst *i;        /* an instruction ptr */
  107.     };
  108.  
  109.  
  110. /* Link control variables */
  111.  
  112. union ptr codend;            /* last used byte of code buffer + 1 */
  113. union ptr exts;            /* start of externals */
  114. union ptr acodend;            /* actual code-end address */
  115. unsigned extspc;            /* size of externals */
  116. unsigned origin;            /* origin of code */
  117. unsigned buforg;            /* origin of code buffer */
  118. unsigned jtsaved;            /* bytes of jump table saved */
  119.  
  120. char *lspace;                /* space to link in */
  121. char *lspcend;                /* end of link area */
  122. char *lodstart;            /* beginning of current file */
  123. char *firstfree;            /* address of first byte above good stuff */
  124.  
  125.  
  126. #include "portio.h"
  127. struct iobuf ibuf, obuf;
  128.  
  129. /* BDS C i/o buffer */
  130. char symbuf[BUFSIZ];
  131.  
  132. #define TRUE (-1)
  133. #define FALSE 0
  134. #define NULL 0
  135.  
  136. /* 8080 instructions */
  137. #define LHLD 0x2A
  138. #define LXIH 0x21
  139. #define SPHL 0xF9
  140. #define JMP  0xC3
  141. #define CALL 0xCD
  142.  
  143. /* strcmp7 locals, made global for speed */
  144. char _c1, _c2, _end1, _end2;
  145.  
  146. /**************** End of Globals ****************/
  147.  
  148.  
  149.  
  150. main (argc, argv)
  151.     int argc;
  152.     char **argv;
  153. {
  154.     puts ("Mark of the Unicorn Linker for BDS C, vsn. 2.1x\n");
  155.     setup (argc, argv);
  156.     if (!ovlp) makeext (&objname, "COM");
  157.     else makeext (&objname, "OVL");
  158.     if (ccreat (&obuf, &objname) < 0)
  159.         Fatal ("Couldn't create binary file!");
  160.     linkprog();
  161.     linklibs();
  162.     if (needfixups) dofixups();
  163.     else wrtcom();
  164.     if (symsp) wrtsyms();
  165.     }
  166.  
  167.  
  168. setup (argc, argv)            /* initialize function table, etc. */
  169.     int argc;
  170.     char **argv;
  171. {
  172.     int i;
  173.  
  174.     symsp = appstatsp = sepstatsp = maxmemp = marcp = FALSE;
  175.     ovlp = needfixups = debug = objset = FALSE;
  176.     nprogs = nlibs = 0;
  177.     strcpy (&mainfunct, "MAIN");
  178.     origin = 0x100;
  179.     cmdline (argc, argv);
  180.     lspace = endext();
  181.     lspcend = topofmem() - 1024;
  182.     loadccc();
  183.     ftab = ftabend = lspcend;
  184. #ifdef OVERLAYS
  185.     if (ovlp) loadsyms();
  186. #endif
  187.     for (i = 0; i < 256; ++i) hashtab[i] = NULL;
  188.     intern (&mainfunct);
  189.     buforg = origin;
  190.     jtsaved = 0;
  191.     }
  192.  
  193.  
  194. cmdline (argc, argv)        /* process command line */
  195.     int argc;
  196.     char **argv;
  197. {
  198.     int i, progp;
  199.  
  200.     if (argc < 1) {
  201.         puts ("Usage is:\n");
  202.         puts ("  l2 {program files} -l {library files}\n");
  203.         puts ("Optional flags are:\n");
  204.         puts ("  -w  to write symbol table (without stats)\n");
  205.         puts ("  -wa write symbol table with stats appended\n");
  206.         puts ("  -ws write symbol table and separate stats file\n");
  207.         puts ("  -d  print extra, debugging info about each function\n");
  208.         puts ("  -m  take next argument as name of main function\n");
  209.         puts ("  -f  next argument is the name of a file of file names,\n");
  210.         puts ("      one per line; those files will be included as if\n");
  211.         puts ("      they were on the command line in the same place\n");
  212.         puts ("  -o  take next argument as first name of output file\n");
  213.         puts ("  -ovl symbol-file origin\n");
  214.         puts ("      links an overlay where the main program symbols\n");
  215.         puts ("      are in symbol-file and the overlay starts at the\n");
  216.         puts ("      specified origin (origin is expressed in hex)\n");
  217.         puts ("  -marc  link for the MARC operating system\n");
  218.         exit (1);
  219.         }
  220.     progp = TRUE;
  221.     for (i = 1; i < argc; ++i) {
  222.         if (argv[i][0] == '-') {
  223.             if (!strcmp (argv[i], "-L")) progp = FALSE;
  224.             else if (!strcmp (argv[i], "-W")) symsp = TRUE;
  225.             else if (!strcmp (argv[i], "-WA")) symsp = appstatsp = TRUE;
  226.             else if (!strcmp (argv[i], "-WS")) symsp = sepstatsp = TRUE;
  227.             else if (!strcmp (argv[i], "-M")) {
  228.                 if (++i >= argc) Fatal ("-m argument missing.\n");
  229.                 strcpy (&mainfunct, argv[i]);
  230.                 }
  231.             else if (!strcmp (argv[i], "-D")) debug = TRUE;
  232.             else if (!strcmp (argv[i], "-F")) {
  233.                 if (++i >= argc) Fatal ("-f argument missing.\n");
  234.                 getfiles (argv[i], progp);
  235.                 }
  236.             else if (!strcmp (argv[i], "-O")) {
  237.                 if (++i >= argc) Fatal ("-o argument missing.\n");
  238.                 strcpy (&objname, argv[i]);
  239.                 objset = TRUE;
  240.                 }
  241. #ifdef OVERLAYS
  242.             else if (!strcmp (argv[i], "-OVL")) {
  243.                 ovlp = TRUE;
  244.                 if (i + 2 >= argc) Fatal ("-ovl argument missing.\n");
  245.                 strcpy (&symsfile, argv[++i]);
  246.                 sscanf (argv[++i], "%x", &origin);
  247.                 }
  248. #endif
  249. #ifdef MARC
  250.             else if (!strcmp (argv[i], "-MARC")) {
  251.                 maxmemp = TRUE;
  252.                 marcp = TRUE;
  253.                 }
  254. #endif
  255.             else printf ("Unknown option: '%s'\n", argv[i]);
  256.             }
  257.         else {
  258.             if (progp) {
  259.                 if (++nprogs >= MAXPROGS)
  260.                     Fatal ("Too many program files.\n");
  261.                 strcpy (&progfiles[nprogs - 1], argv[i]);
  262.                 }
  263.             else    {
  264.                 if (++nlibs > (MAXLIBS - 2)) /* leave room for defaults */
  265.                     Fatal ("Too many library files.\n");
  266.                 strcpy (&libfiles[nlibs - 1], argv[i]);
  267.                 }
  268.             }
  269.         }
  270.     if (ovlp) strcpy (&mainfunct, &progfiles[0]);
  271.     if (!objset) strcpy (&objname, &progfiles[0]);
  272.     strcpy (&libfiles[nlibs++], marcp ? "DEFFM" : "DEFF");
  273.     strcpy (&libfiles[nlibs++], marcp ? "DEFF2M" : "DEFF2");
  274.     }
  275.  
  276. getfiles(ffname, progp)        /* read a file of filenames */
  277.     char *ffname;
  278.     int progp;
  279. {
  280.     char buffer[FNAMESIZE], *p, *q;
  281.  
  282.     if (fopen (ffname, &symbuf) < 0)
  283.         {printf ("Could not open %s.\n", ffname);
  284.         return;
  285.         }
  286.     while (fgets (&buffer, &symbuf)) {
  287.         if (progp ? (++nprogs >= MAXPROGS) : (++nlibs > (MAXLIBS - 2)))
  288.             Fatal ("Too many %s files.", (progp ? "program" : "library"));
  289.         p = (progp ? &progfiles[nprogs - 1] : &libfiles[nlibs - 1]);
  290.         q = &buffer;
  291.         while (*q != '\n') *p++ = *q++;
  292.         *p = '\0';
  293.         }
  294.     fclose (&symbuf);
  295.     }
  296.  
  297. loadccc()                    /* load C.CCC (runtime library) */
  298. {
  299.     union ptr temp;
  300.     unsigned len;
  301.  
  302.     codend.b = lspace;
  303.     if (!ovlp) {
  304.         if (copen (&ibuf, marcp ? "CM.CCC" : "C.CCC") < 0)
  305.             Fatal ("Can't open C.CCC\n");
  306.         if (cread (&ibuf, lspace, 128) < 128)    /* read a sector */
  307.             Fatal ("C.CCC: read error!\n");
  308.         temp.b = lspace + 0x17;
  309.         len = *temp.w;                        /* how long is it? */
  310.         setmem (lspace + 128, len - 128, 0);    /* for file compares */
  311.         cread (&ibuf, lspace + 128, len - 128);
  312.         codend.b += len;
  313.         cclose (&ibuf);
  314.         }
  315.     else codend.i++->opcode = JMP;
  316.     cccsize = codend.b - lspace;
  317.     firstfree = codend.b;
  318.     }
  319.  
  320.  
  321. linkprog()                /* link in all program files */
  322. {
  323.     int i;
  324.     union ptr dirtmp;
  325.     struct funct *fnct;
  326.  
  327.     for (i = 0; i < nprogs; ++i) {
  328.         makeext (&progfiles[i], "CRL");
  329.         if (copen (&ibuf, progfiles[i]) < 0) {
  330.             printf ("Can't open %s\n", progfiles[i]);
  331.             continue;
  332.             }
  333.         printf ("<< Loading %s >>\n", &progfiles[i]);
  334.         readprog (i == 0);
  335.         for (dirtmp.b = &fdir; *dirtmp.b != 0x80;) {
  336.             fnct = intern (dirtmp.b);            /* for each module */
  337.             skip7 (&dirtmp);                    /* in directory */
  338.             if (fnct->flinkedp) {
  339.                 puts ("Duplicate program function '");
  340.                 puts (&fnct->fname);
  341.                 puts ("', not linked.\n");
  342.                 }
  343.             else linkmod (fnct, *dirtmp.w - 0x205);
  344.             dirtmp.w++;
  345.             }                                /* intern & link it */
  346.         cclose (&ibuf);
  347.         }
  348.     }
  349.  
  350.  
  351. linklibs()                /* link in library files */
  352. {
  353.     int ifile;
  354.  
  355.     for (ifile = 0; ifile < nlibs; ++ifile) scanlib (ifile);
  356.     while (missingp ()) {
  357.         puts ("Enter the name of a file to be searched: ");
  358.         gets (&libfiles[nlibs]);
  359.         scanlib (nlibs++);
  360.         }
  361.     acodend.b = codend.b - lspace + buforg;        /* save that number! */
  362.     if (!exts.b) exts.b = acodend.b;
  363.     }
  364.  
  365.  
  366. missingp()                /* are any functions missing?  print them out */
  367. {
  368.     int foundp;
  369.     struct funct *fptr;
  370.  
  371.     foundp = FALSE;
  372.     for (fptr = ftab - 1; fptr >= ftabend; --fptr)
  373.         if (!fptr->flinkedp) {
  374.             if (!foundp) puts ("*** Missing functions:\n");
  375.             puts (&fptr->fname);
  376.             puts ("\n");
  377.             foundp = TRUE;
  378.             }
  379.     return (foundp);
  380.     }
  381.  
  382.  
  383. dofixups()                /* perform reverse scan for fixups */
  384. {
  385.     unsigned n;
  386.     struct funct *fptr;
  387.  
  388.     puts ("\n** Processing fixups **\n");
  389.     if (cwrite (&obuf, lspace, codend.b - lspace) == -1  ||
  390.         cflush (&obuf) < 0) Fatal ("Disk write error!\n");
  391.     while (buforg != origin) {
  392.         buforg -= origin;    /* make relative to actual file */
  393.         buforg += 0x100;    /* insures overlap and record boundary */
  394.         buforg &= ~0x7f;
  395.         n = (lspcend - lspace) & ~0x7f;    /* even records */
  396.         n = min (n, buforg);
  397.         buforg -= n;
  398.         if (buforg == 0)    /* let hackccc win */
  399.             n = max (n, (cccsize + 0x7f) & ~0x7f);
  400.         if (cseek (&obuf, buforg, ABSOLUTE) < 0  ||
  401.             cread (&obuf, lspace, n) != n) Fatal ("Disk I/O error!\n");
  402.         codend.b = lspace + n;
  403.         buforg += origin;
  404.         if (debug) printf ("Fixing from 0x%x through 0x%x...\n",
  405.                         buforg, buforg + n - 1);
  406.         for (fptr = ftab - 1; fptr >= ftabend; --fptr)
  407.             if (fptr->flinkedp == LINKED) chase (fptr);
  408.         if (buforg == origin) hackccc ();
  409.         if (cseek (&obuf, buforg - origin, ABSOLUTE) < 0  ||
  410.             cwrite (&obuf, lspace, n) < 0)
  411.             Fatal ("Couldn't write fixups back!");
  412.         }
  413.      cclose (&obuf);
  414.      stats (STDOUT);
  415.      }
  416.  
  417.  
  418. readprog (mainp)            /* read in a program file */
  419.     FLAG mainp;
  420. {
  421.     char extp;                            /* was -e used? */
  422.     char *extstmp;
  423.     union ptr dir;
  424.     unsigned len;
  425.  
  426.     if (cread (&ibuf, &fdir, 512) < 512)            /* read directory */
  427.         Fatal ("-- read error!\n");
  428.     if (mainp) {
  429.         cread (&ibuf, &extp, 1);
  430.         cread (&ibuf, &extstmp, 2);
  431.         cread (&ibuf, &extspc, 2);
  432.         if (extp) exts.b = extstmp;
  433.         else exts.b = 0;                        /* will be set later */
  434.         }
  435.     else cseek (&ibuf, 5, RELATIVE);
  436.     for (dir.b = &fdir; *dir.b != 0x80; nextd (&dir)); /* find end of dir */
  437.     ++dir.b;
  438.     len = *dir.w - 0x205;
  439.     readobj (len);
  440.     }
  441.  
  442.  
  443. readobj (len)                /* read in an object (program or lib funct) */
  444.     unsigned len;
  445. {
  446.     if (codend.b + len >= lspcend) {
  447.         pushout ();
  448.         if (codend.b + len >= lspcend)
  449.             Fatal ("Module won't fit in memory at all!\n");
  450.         }
  451.     lodstart = codend.b;
  452.     if (cread (&ibuf, lodstart, len) < len) Fatal ("-- read error!\n");
  453.     firstfree = codend.b + len;
  454.     }
  455.  
  456.  
  457. pushout ()
  458. {
  459.     if (!needfixups) {
  460.         puts ("\n** Out of memory -- fixup scan required **\n");
  461.         needfixups = TRUE;
  462.         }
  463.     if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
  464.         Fatal ("Disk write error!\n");
  465.     buforg += codend.b - lspace;
  466.     codend.b = lspace;
  467.     }
  468.  
  469. scanlib (ifile)
  470.     int ifile;
  471. {
  472.     struct funct *fptr;
  473.     union ptr dirtmp;
  474.  
  475.     makeext (&libfiles[ifile], "CRL");
  476.     if (copen (&ibuf, libfiles[ifile]) < 0) {
  477.         printf ("Can't open %s\n", libfiles[ifile]);
  478.         return;
  479.         }
  480.     printf ("<< Scanning %s >>\n", &libfiles[ifile]);
  481.     if (cread (&ibuf, &fdir, 512) < 512)    /* read directory */
  482.         Fatal ("-- Read error!\n");
  483.     for (fptr = ftab - 1; fptr >= ftabend; --fptr)
  484.         if (!fptr->flinkedp  &&
  485.             (dirtmp.b = dirsearch (&fptr->fname))) {
  486.             readfunct (dirtmp.b);
  487.             linkmod (fptr, 0);
  488.             }
  489.     cclose (&ibuf);
  490.     }
  491.  
  492.  
  493. readfunct (direntry)            /* read a function (from a library) */
  494.     union ptr direntry;
  495. {
  496.     unsigned start, len;
  497.  
  498.     skip7 (&direntry);
  499.     start = *direntry.w++;
  500.     skip7 (&direntry);
  501.     len = *direntry.w - start;
  502.     if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
  503.     readobj (len);
  504.     }
  505.  
  506.  
  507. linkmod (fnct, offset)                    /* link in a module */
  508.     struct funct *fnct;
  509.     unsigned offset;
  510. {
  511.     union ptr finalloc, temp, body, code, jump;
  512.     unsigned flen, nrelocs, jtsiz;
  513.     struct funct *fptr;
  514.  
  515.     fnct->flinkedp = LINKED;
  516.     finalloc.u = fnct->faddr = buforg + (codend.b - lspace);
  517.     chase (fnct);
  518.     if (debug)
  519.         printf ("Linking function %s, bufptr = %x, fileptr = %x\n",
  520.                &fnct->fname, codend.u, finalloc.u);
  521.     body.u = offset + strlen (&lodstart[offset]) + 3;
  522.         /* only an offset here! */
  523.  
  524.     /* NOTE: everything is done relative to lodstart so that a possible
  525.        relocation performed by intern does not screw things up */
  526.     jump.i = body.i + (lodstart[offset] ? 1 : 0);
  527.     for (temp.u = offset; lodstart[temp.u];) {
  528.         fptr = intern (&lodstart[temp.u]);
  529.         jump.b = lodstart + jump.u;
  530.         jump.i++->address = fptr;
  531.         jump.u = jump.b - lodstart;
  532.         temp.b = lodstart + temp.u;
  533.         skip7 (&temp.b);
  534.         temp.u = temp.b - lodstart;
  535.         }
  536.     temp.b = lodstart + temp.u;
  537.     ++temp.b;
  538.  
  539.     flen = *temp.w;
  540.     code.b = lodstart + jump.u;
  541.     body.b = lodstart + body.u;    /* now a pointer */
  542.     temp.b = body.b + flen;        /* loc. of reloc parameters */
  543.     nrelocs = *temp.w++;
  544.     jtsiz = code.b - body.b;
  545.     while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
  546.                            finalloc.b, code.b, flen);
  547.     flen -= jtsiz;
  548.     jtsaved += jtsiz;
  549.     movmem (code.b, codend.b, flen);
  550.     codend.b += flen;
  551.     }
  552.  
  553.  
  554. relocate (param, body, jtsiz, base, code, flen)    /* do a relocation!! */
  555.     unsigned param, jtsiz, base, flen;
  556.     union ptr body, code;
  557. {
  558.     union ptr instr,                    /* instruction involved */
  559.             ref;                        /* jump table link */
  560.     struct funct *fnct;
  561.  
  562.     if (param == 1) return;                /* don't reloc jt skip */
  563.     instr.b = body.b + param - 1;
  564.     if (instr.i->address >= jtsiz)
  565.         instr.i->address += base - jtsiz;            /* vanilla case */
  566.     else {
  567.         ref.b = instr.i->address + body.u;
  568.         if (instr.i->opcode == LHLD) {
  569.             instr.i->opcode = LXIH;
  570.             --ref.b;
  571.             }
  572.         fnct = ref.i->address;
  573.         if (fnct->flinkedp) instr.i->address = fnct->faddr;
  574.         else    {
  575.             instr.i->address = fnct->fchain;
  576.             fnct->fchain = base + (instr.b + 1 - code.b);
  577.             }
  578.         }
  579.     }
  580.  
  581.  
  582. intern (name)                /* intern a function name in the table */
  583.     char *name;
  584. {
  585.     struct funct *fptr;
  586.     int hashcode;
  587.     char *temp;
  588.     unsigned amt;
  589.  
  590.     if (*name == 0x9D) name = "MAIN";        /* Why, Leor, WHY??? */
  591.     hashcode = 0;
  592.     temp = name;
  593.     do {    if (*temp) hashcode += (hashcode + (*temp & 0x7F));
  594.         else break;
  595.         } while (!(*temp++ & 0x80));
  596.     while (hashcode & ~0xFF) hashcode = (hashcode & 0xFF) + (hashcode >> 8);
  597.     for (fptr = hashtab[hashcode]; fptr != NULL; fptr = fptr->next)
  598.         if (!strcmp7 (name, fptr->fname)) return (fptr);
  599.  
  600.     lspcend = fptr = --ftabend;
  601.     if (ftabend < firstfree) {
  602.         pushout ();
  603.         amt = firstfree - lodstart;
  604.         movmem (lodstart, lspace, amt);
  605.         lodstart = lspace;
  606.         firstfree = lodstart + amt;
  607.         if (ftabend < firstfree) Fatal ("No more symbol room.\n");
  608.         }
  609.  
  610.     strcpy7 (fptr->fname, name);
  611.     str7tont (fptr->fname);
  612.     fptr->flinkedp = FALSE;
  613.     fptr->faddr = 0;
  614.     fptr->fchain = 0;
  615.     fptr->next = hashtab[hashcode];
  616.     return (hashtab[hashcode] = fptr);
  617.     }
  618.  
  619.  
  620. dirsearch (name)            /* search directory for a function */
  621.     char *name;
  622. {
  623.     union ptr temp;
  624.  
  625.     for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
  626.         if (!strcmp7 (name, temp.b)) return (temp.b);
  627.     return (NULL);
  628.     }
  629.  
  630.  
  631. nextd (ptrp)                /* move this pointer to the next dir entry */
  632.     union ptr *ptrp;
  633. {
  634.     skip7 (ptrp);
  635.     ++(*ptrp).w;
  636.     }
  637.  
  638.  
  639. chase (fptr)                /* chase chain of refs to function */
  640.     struct funct *fptr;
  641. {
  642.     union ptr temp;
  643.  
  644.     while (fptr->fchain >= buforg) {
  645.         if ((temp.b = lspace + (fptr->fchain - buforg)) >= codend.b)
  646.             Fatal ("Chase error, function '%s', chain = 0x%x.\n",
  647.                   &fptr->fname, fptr->fchain);
  648.         fptr->fchain = *temp.w;
  649.         *temp.w = fptr->faddr;
  650.         }
  651.     }
  652.  
  653.  
  654. wrtcom()                    /* write out com file (from in-mem link) */
  655. {
  656.     hackccc();
  657.     if (cwrite (&obuf, lspace, codend.b - lspace) == -1  ||
  658.         cflush (&obuf) < 0) Fatal ("Disk write error!\n");
  659.     cclose (&obuf);
  660.     stats (STDOUT);
  661.     }
  662.  
  663.  
  664. hackccc()                    /* store various goodies in C.CCC code */
  665. {
  666.     union ptr temp;
  667.     struct funct *fptr;
  668.  
  669.     temp.b = lspace;
  670.     fptr = intern (&mainfunct);
  671.     if (!ovlp) {
  672.         if (!marcp) {
  673.             temp.i->opcode = LHLD;
  674.             temp.i->address = 6;
  675.             (++temp.i)->opcode = SPHL;
  676.             temp.b = lspace + 0xF;            /* main function address */
  677.             temp.i->address = fptr->faddr;
  678.             }
  679.         temp.b = lspace + 0x15;
  680.         *temp.w++ = exts.u;
  681.         ++temp.w;
  682.         *temp.w++ = acodend.u;
  683.         *temp.w++ = exts.u + extspc;
  684.         }
  685.     else temp.i->address = fptr->faddr;        /* that's a JMP */
  686. #ifdef MARC
  687.     if (maxmemp) {
  688.         temp.b = lspace + 0x258;
  689.         temp.i->opcode = CALL;
  690.         temp.i->address = 0x50;
  691.         }
  692. #endif
  693.     }
  694.  
  695.  
  696. wrtsyms()                    /* write out symbol table */
  697. {
  698.     int i, fd, compar();
  699.     struct funct *fptr;
  700.     
  701.     qsort (ftabend, ftab - ftabend, sizeof (*ftab), &compar);
  702.     makeext (&objname, "SYM");
  703.     if (fcreat (&objname, &symbuf) < 0)
  704.         Fatal ("Can't create .SYM file\n");
  705.     for (fptr = ftabend; fptr < ftab; ++fptr) {
  706.         puthex (fptr->faddr, &symbuf);
  707.         putc (' ', &symbuf);
  708.         fputs (&fptr->fname, &symbuf);
  709.         if (i % 4 == 3) fputs ("\n", &symbuf);
  710.         else {
  711.             if (strlen (&fptr->fname) < 3) putc ('\t', &symbuf);
  712.             putc ('\t', &symbuf);
  713.             }
  714.         }
  715.     if (i % 4) fputs ("\n", &symbuf);    
  716.     if (appstatsp) stats (&symbuf);
  717.     putc (CPMEOF, &symbuf);
  718.     fflush (&symbuf);
  719.     fclose (&symbuf);
  720.     if (sepstatsp) {
  721.         makeext (&objname, "LNK");
  722.         if (fcreat (&objname, &symbuf) < 0)
  723.             Fatal ("Can't create .LNK file\n");
  724.         stats (&symbuf);
  725.         putc (CPMEOF, &symbuf);
  726.         fflush (&symbuf);
  727.         fclose (&symbuf);
  728.         }
  729.     }
  730.  
  731.  
  732. compar (f1, f2)            /* compare two symbol table entries by name */
  733.     struct funct *f1, *f2;
  734. {
  735. /*    return (strcmp (&f1->fname, &f2->fname));    alphabetical order */
  736.     return (f1->faddr > f2->faddr);            /* memory order */
  737.     }
  738.  
  739.  
  740. #ifdef OVERLAYS
  741. loadsyms()                /* load base symbol table (for overlay) */
  742. {                        /* symbol table must be empty! */
  743.     int nread;
  744.     FLAG done;
  745.     char *c;
  746.     
  747.     makeext (&symsfile, "SYM");
  748.     if (fopen (&symsfile, &symbuf) < 0) 
  749.         Fatal ("Can't open %s.\n", &symsfile);
  750.     done = FALSE;
  751.     while (!done) {
  752.         if (lspcend - lspace < 0x80) Fatal ("No more room for symbols.");
  753.         nread = fscanf (&symbuf, "%x%s\t%x%s\t%x%s\t%x%s\n",
  754.                      &(ftabend[-1].faddr), &(ftabend[-1].fname),
  755.                      &(ftabend[-2].faddr), &(ftabend[-2].fname),
  756.                      &(ftabend[-3].faddr), &(ftabend[-3].fname),
  757.                      &(ftabend[-4].faddr), &(ftabend[-4].fname));
  758.         nread /= 2;
  759.         if (nread < 4) done = TRUE;
  760.         while (nread-- > 0) (--ftabend)->flinkedp = EXTERNAL;
  761.         lspcend = ftabend;
  762.         }
  763.     fclose (&symbuf);
  764.     }
  765. #endif
  766.  
  767.  
  768. stats (chan)                /* print statistics on chan */
  769.     int chan;
  770. {
  771.     unsigned temp;
  772.  
  773.     fprintf (chan, "\n\nLink statistics:\n");
  774.     fprintf (chan, "  Number of functions: %d\n", ftab - ftabend);
  775.     fprintf (chan, "  Code ends at: 0x%x\n", acodend.u);
  776.     fprintf (chan, "  Externals begin at: 0x%x\n", exts.u);
  777.     fprintf (chan, "  Externals end at: 0x%x\n", exts.u + extspc);
  778.     fprintf (chan, "  Jump table bytes saved: 0x%x\n", jtsaved);
  779.     temp = lspcend;
  780.     if (!needfixups)
  781.         fprintf (chan,
  782.                 "  Link space remaining: %dK\n", (temp - codend.u) / 1024);
  783.     }
  784.  
  785.  
  786. makeext (fname, ext)        /* force a file extension to ext */
  787.     char *fname, *ext;
  788. {
  789.     while (*fname && (*fname != '.')) {
  790.         *fname = toupper (*fname);        /* upcase as well */
  791.         ++fname;
  792.         }
  793.     *fname++ = '.';
  794.     strcpy (fname, ext);
  795.     }
  796.  
  797.  
  798. strcmp7 (s1, s2)            /* compare two bit-7-terminated strings */
  799.     char *s1, *s2;            /* also works for non-null NUL-term strings */
  800. {
  801. /*    char c1, c2, end1, end2;        (These are now global for speed) */
  802.  
  803.     while (TRUE) {
  804.          _c1 = *s1++;
  805.         _c2 = *s2++;
  806.         _end1 = (_c1 & 0x80) | !*s1;
  807.         _end2 = (_c2 & 0x80) | !*s2;
  808.         if ((_c1 &= 0x7F) < (_c2 &= 0x7F)) return (-1);
  809.         if (_c1 > _c2  ||  (_end2  &&  !_end1)) return (1);
  810.         if (_end1  &&  !_end2) return (-1);
  811.         if (_end1  &&  _end2) return (0);
  812.         }
  813.     }
  814.  
  815.  
  816. strcpy7 (s1, s2)            /* copy s2 into s1 */
  817.     char *s1, *s2;
  818. {
  819.     do {
  820.         *s1 = *s2;
  821.         if (!*(s2+1)) {                /* works even if */
  822.             *s1 |= 0x80;                /* s2 is null-term */
  823.             break;
  824.             }
  825.         ++s1;
  826.         } while (!(*s2++ & 0x80));
  827.     }
  828.  
  829.  
  830. skip7 (ptr7)                /* move this pointer past a string */
  831.     char **ptr7;
  832. {
  833.     while (!(*(*ptr7)++ & 0x80));
  834.     }
  835.  
  836.  
  837. str7tont (s)                /* add null at end */
  838.     char *s;
  839. {
  840.     while (!(*s & 0x80)) {
  841.         if (!*s) return;        /* already nul term! */
  842.         s++;
  843.         }
  844.     *s = *s & 0x7F;
  845.     *++s = NUL;
  846.     }
  847.  
  848.  
  849. puthex (n, obuf)            /* output a hex word, with leading 0s */
  850.     unsigned n;
  851.     char *obuf;
  852. {
  853.     int i, nyb;
  854.     
  855.     for (i = 3; i >= 0; --i) {
  856.         nyb = (n >> (i * 4)) & 0xF;
  857.         nyb += (nyb > 9) ? 'A' - 10 : '0';
  858.         putc (nyb, obuf);
  859.         }
  860.     }
  861.  
  862.  
  863. Fatal (arg1, arg2, arg3, arg4)    /* lose, lose */
  864.     char *arg1, *arg2, *arg3, *arg4;
  865. {
  866.     printf (arg1, arg2, arg3, arg4);
  867.     exit (1);
  868.     }
  869.  
  870.  
  871. exit (status)                /* exit the program */
  872.     int status;
  873. {
  874.     if (status == 1) {
  875. #ifdef SDOS
  876.         unlink ("a:$$$$.cmd");
  877. #else
  878.         unlink ("a:$$$.sub");
  879. #endif
  880.         }
  881.     bios (1);                    /* bye! */
  882.     }
  883.  
  884.  
  885.  
  886. /* END OF L2.C */
  887.