?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1.  
  2. #define TITLE   "L2 Linker v3.0\n"
  3.  
  4. /*      ********
  5.         * L2.C *        Auxilliary linker for BDS C
  6.         ********
  7.                         Written 1980 by Scott W. Layson
  8.                         This code is in the public domain.
  9.  
  10.         This is an improved linker for BDS C CRL format.
  11.  
  12.         Modified to v2.2.3, 11/27/1982 by David Kirkland
  13.         Version 2.2, as distributed by BDS C UG, was given the following
  14.         modifications:
  15.         -  The c debugger is supported.  This adds the "-NS", "-S", and
  16.            "-D" command line options.
  17.         -  DEFF3.CRL is scanned, if it is present on disk
  18.         -  New mechanism for default drive selection--the DEF_DRIVE macro added.
  19.         -  Minor changes to messages.
  20.         -  Eliminates need for SCOTT.C by change to fscanf format string
  21.            in function "loadsyms" when reading .SYM file for overlay processing.
  22.         -  Ability to rescan DEFF*.CRL if reply with a carriage return to prompt
  23.            message when functions are missing.
  24.         -  "-I" option, which allows interactive entry of command line
  25.            arguments.  If the command line ends in a "-i", then L2 treats
  26.            the command line as Incomplete, and prompts the user for more
  27.            arguments.  This is especially useful if you have a replacement
  28.            CCP which does not allow 127 character long command lines
  29.            (e.g., ZCPR).  This option orginally implemented, in a different
  30.            way, by Gil Shapiro.
  31.  
  32.         Modified to v2.2.4, 03/24/1983 by David Kirkland
  33.         -  "-N" option added to produce .COM files which do not perform a
  34.            warm boot after execution
  35.            As in clink, if both "-n" and "-t" are specified, "-t" is given
  36.            priority.
  37.         - "-NS" option removed/"-S" option changed.  Now the default is NO
  38.           system library files (see CDB docs for explanation of system
  39.           library files); system library functions made it impossible to set
  40.           a breakpoint at the return of library functions in certain instances.
  41.  
  42.         Modified to v3.0, 6/86 by Leor Zolman
  43.         -  Obtains all storage allocation by calling alloc()/free(), so as
  44.            not to conflict with buffered I/O storage allocation of BDS C v1.6.
  45.         -  Added SHORTL2 #definition, to allow a real short version that can't
  46.            handle the -w options or do overlays. This avoids dragging in the
  47.            BDS C buffered I/O package.
  48.  
  49.         Compilation/linkage instructions:
  50.                 cc l2.c -e5600       (use -e5300 if linking with L2.COM)
  51.                 cc chario.c
  52.  
  53.                 clink l2 chario
  54.           (or)  l2 l2 chario
  55.  
  56. The DEF_DRIVE macro is used to define the drive from which L2 will load C.CCC,
  57. DEFF.CRL, DEFF2.CRL, and DEFF3.CRL (if it exists). The macro takes as an
  58. argument the filename and extension, and "returns" the name with whatever drive
  59. designator is needed.  The macro also encloses the name in quotes; thus, the
  60. argument when the macro is invoked must NOT be within quotes.
  61. That is, to open C.CCC on the proper drive, we use the C code
  62.         if (ERROR==fopen(DEF_DRIVE(C.CCC), iobuf)) .....
  63.  */
  64.  
  65. #include <stdio.h>
  66. #define DEF_DRIVE(fn) "fn"      /* Make this "0/A:fn" for, say, user 0 on A */
  67. #define SUB_FILE   "$$$.SUB"    /* submit file to delete on error exit...
  68.                                  * if you use SDOS, use "a:$$$$.sub"; if you've
  69.                                  * hacked your CCP, you may need to change the
  70.                                  * drive designator letter */
  71. #define RST_NUM  6              /* C debugger RST number. Should be identical
  72.                                    to the RSTNUM symbol in CCC.ASM      */
  73. #define SHORTL2 0               /* For shorter L2 (no -w options or overlay
  74.                                    capability), make this 1 (else 0) */
  75. #define OVERLAYS 1              /* If SHORTL2 is 1, this must be 0 (false) */
  76.                                 /* Otherwise, 0 disables overlays, making L2
  77.                                                         a little shorter  */
  78. #define NDEFF   3               /* Number of DEFF?.CRL files in std library */
  79.  
  80. /* These #defines from NOBOOT.C for version 1.50 */
  81. #define SNOBSP 0x0138   /* Location of Set NoBoot SP routine in C.CCC   */
  82. #define NOBRET 0x013B   /* Location of NoBoot RETurn routine in C.CCC   */
  83.  
  84. #define NUL             0
  85. #define FLAG            char
  86. #define repeat  while (1)
  87.  
  88. #define STDOUT          1
  89.  
  90. /* Phase control */
  91. #define INMEM           1       /* while everything still fits */
  92. #define DISK1           2       /* overflow; finish building table */
  93. #define DISK2           3       /* use table to do window link */
  94. int phase;
  95.  
  96.  
  97. /* function table */
  98. struct funct {
  99.         char fname[9];
  100.         FLAG flinkedp;          /* in memory already? */
  101.         FLAG fdebug;            /* TRUE unless this routine required
  102.                                    only by a lib function after -s */
  103.         char *faddr;            /* address of first ref link if not linked */
  104.         } *ftab;
  105. int nfuncts;                    /* no. of functions in  table */
  106. int maxfuncts;                  /* table size */
  107.  
  108. #define LINKED          1       /* (flinkedp) function really here */
  109. #define EXTERNAL        2       /* function defined in separate symbol table */
  110.  
  111. char fdir [512];                /* CRL file function directory */
  112.  
  113. /* command line parameters etc. */
  114. int nprogs, nlibs;
  115. char progfiles [30] [15];       /* program file names */
  116. char libfiles [20] [15];        /* library file names */
  117. int deflibindex;                /* index of first default (DEFF*) library */
  118. FLAG symsp,                     /* write symbols to .sym file? */
  119.         appstatsp,              /* append stats to .sym file? */
  120.         sepstatsp;              /* write stats to .lnk file? */
  121.  
  122. char mainfunct[10];
  123. FLAG ovlp;                      /* make overlay? */
  124. char symsfile [15];             /* file to load symbols from (for overlays) */
  125.  
  126. /*  C debugger variables  */
  127. FLAG Dflag;
  128. FLAG SysStat;                   /* TRUE if "-s" option given & now active */
  129. int  SysNum;                    /* index into libfiles of "-s", or -1 if none */
  130.  
  131. FLAG Tflag;                     /* TRUE if "-t" option given    */
  132. FLAG Nflag;                     /* TRUE if "-n" option given    */
  133. unsigned Tval;                  /* arg to "-t", if present      */
  134.  
  135. /* useful things to have defined */
  136. struct inst {
  137.         char opcode;
  138.         char *address;
  139.         };
  140.  
  141. union ptr {
  142.         unsigned u;             /* an int */
  143.         unsigned *w;            /* a word ptr */
  144.         char *b;                /* a byte ptr */
  145.         struct inst *i;         /* an instruction ptr */
  146.         };
  147.  
  148.  
  149. /* Link control variables */
  150.  
  151. union ptr codend;               /* last used byte of code buffer + 1 */
  152. union ptr exts;                 /* start of externals */
  153. union ptr acodend;              /* actual code-end address */
  154. unsigned extspc;                /* size of externals */
  155. unsigned origin;                /* origin of code */
  156. unsigned buforg;                /* origin of code buffer */
  157. unsigned jtsaved;               /* bytes of jump table saved */
  158.  
  159. char *lspace;                   /* space to link in */
  160. char *lspcend;                  /* end of link area */
  161. char *lodstart;                 /* beginning of current file */
  162.  
  163.  
  164. /* i/o buffer */
  165. struct iobuf {
  166.         int fd;
  167.         int isect;              /* currently buffered sector */
  168.         int nextc;              /* index of next char in buffer */
  169.         char buff [128];
  170.         } ibuf, obuf;
  171.  
  172. FILE *symbuf;
  173.  
  174. /* seek opcodes */
  175. #define ABSOLUTE 0
  176. #define RELATIVE 1
  177.  
  178. #define INPUT 0
  179.  
  180. #define TRUE (-1)
  181. #define FALSE 0
  182. #define NULL 0
  183.  
  184. /* 8080 instructions */
  185. #define LHLD 0x2A
  186. #define LXISP 0x31
  187. #define LXIH 0x21
  188. #define SPHL 0xF9
  189. #define JMP  0xC3
  190. #define CALL 0xCD
  191.  
  192. #define PARMSIZE        400
  193. char parmtext[PARMSIZE];  /* "-i" command line args go here */
  194. int  parmindex;           /* first unused character in parmtext */
  195.  
  196. /* strcmp7 locals, made global for speed */
  197. char _c1, _c2, _end1, _end2;
  198.  
  199. /**************** End of Globals ****************/
  200.  
  201.  
  202. main (argc, argv)
  203.         int argc;
  204.         char **argv;
  205. {
  206.         char *argvv[40];
  207.  
  208.         puts (TITLE);
  209.         inc_proc(&argc, argv, &argvv);
  210.         setup (argc, argvv);
  211.         linkprog();
  212.         linklibs();
  213.         if (phase == DISK1) rescan();
  214.         else wrtcom();
  215. #if !SHORTL2
  216.         if (symsp) wrtsyms();
  217. #endif
  218.         }
  219.  
  220.  
  221. inc_proc(count, argv, argvv) int *count; char **argv, **argvv; {
  222.         /* process the "-i" argument by building a new argv vector
  223.          * in argvv.
  224.          */
  225.  
  226.         int i;
  227.  
  228.         for (i=0; i<*count; i++) argvv[i] = argv[i];
  229.  
  230.         while (!strcmp(argvv[*count-1],"-I"))
  231.                 buildvec(count, argvv);
  232. }
  233.  
  234. buildvec (count, argvv) int *count; char **argvv; {
  235.         char line[MAXLINE], *p;
  236.  
  237.         puts("Enter continuation\n*");
  238.         gets(line);
  239.  
  240.         for (p=line, --*count; ;) {
  241.                 while (isspace(*p)) p++;
  242.                 if (!*p) break;
  243.                 argvv[(*count)++] = &parmtext[parmindex];
  244.                 while (*p && !isspace(parmtext[parmindex] = toupper(*p++)) )
  245.                         parmindex++;
  246.                 parmtext[parmindex++] = 0;
  247.                 }
  248. }
  249.  
  250. setup (argc, argv)              /* initialize function table, etc. */
  251.         int argc;
  252.         char **argv;
  253. {
  254.         unsigned i;
  255.  
  256.         symsp = appstatsp = sepstatsp = FALSE;  /* default options */
  257.         ovlp = FALSE;
  258.         nprogs = 0;
  259.         nlibs = 0;
  260.         strcpy (&mainfunct, "MAIN");    /* default top-level function */
  261.         origin = 0x100;                 /* default origin */
  262.         maxfuncts = 200;                /* default function table size */
  263.         Tflag = Nflag = FALSE;          /* no "-t" or "-n" given yet */
  264.         SysNum = -1;
  265.         SysStat = FALSE;
  266.         Dflag = FALSE;
  267.         cmdline (argc, argv);
  268.  
  269.         ftab = alloc(maxfuncts * sizeof(*ftab));
  270.  
  271.         for (i = 40000; i > 3000; i -= 100)
  272.         {
  273.                 if (!(lspace = alloc(i)))
  274.                         continue;
  275.                 free(lspace);
  276.                 lspace = alloc(i - (NSECTS * SECSIZ + 1100));
  277.                 lspcend = alloc(0);
  278.                 break;
  279.         }
  280.         if (i < 3000)
  281.                 Fatal ("Sorry, not enough memory for L2\n");
  282.  
  283.         loadccc();
  284.         nfuncts = 0;
  285. #if OVERLAYS
  286.         if (ovlp) loadsyms();
  287. #endif
  288.         intern (&mainfunct);
  289.         phase = INMEM;
  290.         buforg = origin;
  291.         jtsaved = 0;
  292.         }
  293.  
  294. cmdline (argc, argv)            /* process command line */
  295.         int argc;
  296.         char **argv;
  297. {
  298.         int i, progp;
  299.  
  300.         if (argc == 1) {
  301.                 puts ("Usage is:\n");
  302.                 puts ("  l2 {program files} [-l {library files} ] ");
  303.                 puts ("[-s {library files} ]\n");
  304.                 puts ("\t[-m <main_name>] [-f <maxfuncts>] [-org <addr>]");
  305.                 puts (" [-t <addr>] [-n]\n");
  306.                 puts ("\t[-d] [-w | -wa | -ws]\n");
  307. #if OVERLAYS
  308.                 puts ("\t[-ovl <rootname> <addr>]");
  309. #endif
  310.                 puts ("\t[-i]");
  311.                 lexit (1);
  312.                 }
  313.         progp = TRUE;
  314.         for (i=1; i < argc; ++i) {
  315.                 if (argv[i][0] == '-') {
  316.                         if (!strcmp (argv[i], "-F")) {
  317.                                 if (++i>=argc) Fatal ("-f argument missing.\n");
  318.                                 sscanf (argv[i], "%d", &maxfuncts);
  319.                                 }
  320.                         else if (!strcmp (argv[i], "-L")) progp = FALSE;
  321.                         else if (!strcmp (argv[i], "-S")) {
  322.                                 progp = FALSE;
  323.                                 SysNum = nlibs;
  324.                                 }
  325.                         else if (!strcmp (argv[i], "-M")) {
  326.                                 if (++i>=argc) Fatal ("-m argument missing.\n");
  327.                                 strcpy (&mainfunct, argv[i]);
  328.                                 }
  329.                         else if (!strcmp (argv[i], "-ORG")) {
  330.                                 if (++i>=argc) Fatal ("-org argument missing.\n");
  331.                                 sscanf (argv[i], "%x", &origin);
  332.                                 }
  333.                         else if (!strcmp (argv[i], "-N")) Nflag = TRUE;
  334.                         else if (!strcmp (argv[i], "-T")) {
  335.                                 if (++i >= argc)
  336.                                         Fatal ("-t argument missing.\n");
  337.                                 Tflag = TRUE;
  338.                                 sscanf (argv[i], "%x", &Tval);
  339.                                 }
  340. #if OVERLAYS
  341.                         else if (!strcmp (argv[i], "-OVL")) {
  342.                                 ovlp = TRUE;
  343.                                 if (i + 2 >= argc)
  344.                                         Fatal ("-ovl argument missing.\n");
  345.                                 strcpy (&symsfile, argv[++i]);
  346.                                 sscanf (argv[++i], "%x", &origin);
  347.                                 }
  348. #endif
  349.                         else if (!strcmp (argv[i], "-D"))
  350.                                 Dflag = TRUE;
  351. #if !SHORTL2
  352.                         else if (!strcmp (argv[i], "-W"))
  353.                                 symsp = TRUE;
  354.                         else if (!strcmp (argv[i], "-WA"))
  355.                                 symsp = appstatsp = TRUE;
  356.                         else if (!strcmp (argv[i], "-WS"))
  357.                                 symsp = sepstatsp = TRUE;
  358. #endif
  359.                         else if (!strcmp (argv[i], "-I"))
  360.                                 printf("-I ignored, must be last on line\n");
  361.                         else printf ("Unknown option: '%s'\n", argv[i]);
  362.                         }
  363.                 else {
  364.                         if (progp) strcpy (&progfiles[nprogs++], argv[i]);
  365.                         else strcpy (&libfiles[nlibs++], argv[i]);
  366.                         }
  367.                 }
  368.         if (ovlp)
  369.                 strcpy(&mainfunct, &progfiles[0][2*(progfiles[0][1]==':')] );
  370.         if (Dflag || SysNum!=-1)
  371.                 Dflag = symsp = TRUE;
  372.  
  373.         deflibindex = nlibs;
  374.         strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF) );
  375.         strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF2) );
  376.         strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF3) );
  377.         }
  378.  
  379.  
  380. loadccc()                       /* load C.CCC (runtime library) */
  381. {
  382.         union ptr temp;
  383.         unsigned len;
  384.  
  385.         codend.b = lspace;
  386.         if (!ovlp) {
  387.                 if (copen (&ibuf, DEF_DRIVE(C.CCC) ) < 0)
  388.                         Fatal ("Can't open %s\n", DEF_DRIVE(C.CCC) );
  389.                 if (cread (&ibuf, lspace, 128) < 128)   /* read a sector */
  390.                         Fatal ("C.CCC: read error!\n");
  391.                 temp.b = lspace + 0x17;
  392.                 len = *temp.w;                          /* how long is it? */
  393.                 cread (&ibuf, lspace + 128, len - 128); /* read rest */
  394.                 codend.b += len;
  395.                 cclose (&ibuf);
  396.                 }
  397.         else codend.i++->opcode = JMP;
  398.         }
  399.  
  400.  
  401. linkprog()                              /* link in all program files */
  402. {
  403.         int i;
  404.         union ptr dirtmp;
  405.         struct funct *fnct;
  406.  
  407.         for (i=0; i<nprogs; ++i) {
  408.                 makeext (&progfiles[i], "CRL");
  409.                 if (copen (&ibuf, progfiles[i]) < 0) {
  410.                         printf ("Can't open %s\n", progfiles[i]);
  411.                         continue;
  412.                         }
  413.                 printf ("Loading  %s\n", &progfiles[i]);
  414.                 readprog (i==0);
  415.                 for (dirtmp.b=&fdir; *dirtmp.b != 0x80;) {
  416.                         fnct = intern (dirtmp.b);       /* for each module */
  417.                         skip7 (&dirtmp);                /* in directory */
  418.                         if (!fnct->flinkedp)
  419.                                 linkmod (fnct, lodstart + *dirtmp.w - 0x205);
  420.                         else if (phase != DISK2) {
  421.                                 puts ("Duplicate program function '");
  422.                                 puts (&fnct->fname);
  423.                                 puts ("', not linked.\n");
  424.                                 }
  425.                         dirtmp.w++;
  426.                         }                               /* intern & link it */
  427.                 cclose (&ibuf);
  428.                 }
  429.         }
  430.  
  431.  
  432. linklibs()                              /* link in library files */
  433. {
  434.         int ifile;
  435.  
  436.         for (ifile=0; ifile<nlibs; ++ifile) {
  437.                 if (ifile==SysNum) SysStat = TRUE;
  438.                 scanlib (ifile);
  439.                 }
  440.         while (missingp()) {
  441.                 puts ("Enter the name of a file to be searched or CR: ");
  442.                 gets (&libfiles[nlibs]);
  443.                 if (libfiles[nlibs][0]) {
  444.                         SysStat = FALSE;
  445.                         scanlib (nlibs);
  446.                         }
  447.                 else {
  448.                         if (SysNum!=-1)
  449.                                 SysStat = TRUE;
  450.                         for (ifile=0; ifile<NDEFF; ++ifile)
  451.                                 scanlib (deflibindex + ifile);
  452.                         }
  453.                 }
  454.         acodend.b = codend.b - lspace + buforg;         /* save that number! */
  455.         if (!exts.b) exts.b = acodend.b;
  456.         }
  457.  
  458.  
  459. missingp()              /* are any functions missing?  print them out */
  460. {
  461.         int i, foundp;
  462.  
  463.         foundp = FALSE;
  464.         for (i=0; i<nfuncts; ++i)
  465.                 if (!ftab[i].flinkedp) {
  466.                         if (!foundp) puts ("*** Missing functions:\n");
  467.                         puts (&ftab[i].fname);
  468.                         puts ("\n");
  469.                         foundp = TRUE;
  470.                         }
  471.         return (foundp);
  472.         }
  473.  
  474.  
  475. rescan()                /* perform second disk phase */
  476. {
  477.         int i;
  478.        
  479.         for (i=0; i < nfuncts; ++i)
  480.                 if (ftab[i].flinkedp == LINKED) ftab[i].flinkedp = FALSE;
  481.         phase = DISK2;
  482.         buforg = origin;
  483.         puts ("\n\n**** Beginning second disk pass ****\n");
  484.         if (!ovlp) makeext (&progfiles[0], "COM");
  485.         else makeext (&progfiles[0], "OVL");
  486.         ccreat (&obuf, &progfiles[0]);
  487.         loadccc();
  488.         hackccc();
  489.         linkprog();
  490.         linklibs();
  491.         if (cwrite (&obuf, lspace, codend.b - lspace) == -1
  492.             ||  cflush (&obuf) < 0) Fatal ("Disk write error!\n");
  493.         cclose (&obuf);
  494.         stats (STDOUT);
  495.         }
  496.  
  497.  
  498.  
  499. readprog (mainp)                        /* read in a program file */
  500.         FLAG mainp;
  501. {
  502.         char extp;                              /* was -e used? */
  503.         char *extstmp;
  504.         union ptr dir;
  505.         unsigned len;
  506.  
  507.         if (cread (&ibuf, &fdir, 512) < 512)            /* read directory */
  508.                 Fatal ("-- read error!\n");
  509.         if (phase == INMEM  &&  mainp) {
  510.                 cread (&ibuf, &extp, 1);
  511.                 cread (&ibuf, &extstmp, 2);
  512.                 cread (&ibuf, &extspc, 2);
  513.                 if (extp) exts.b = extstmp;
  514.                 else exts.b = 0;                /* will be set later */
  515.                 }
  516.         else cseek (&ibuf, 5, RELATIVE);
  517.         for (dir.b=&fdir; *dir.b != 0x80; nextd (&dir));  /* find end of dir */
  518.         ++dir.b;
  519.         len = *dir.w - 0x205;
  520.         readobj (len);
  521.         }
  522.  
  523.  
  524. readobj (len)                   /* read in an object (program or lib funct) */
  525.         unsigned len;
  526. {
  527.         if (phase == DISK1  ||  codend.b + len >= lspcend) {
  528.                 if (phase == INMEM) {
  529.                         puts("\n** Out of memory--switching to disk mode **\n");
  530.                         phase = DISK1;
  531.                         }
  532.                 if (phase == DISK2) {
  533.                         if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
  534.                                 Fatal ("Disk write error!\n");
  535.                         }
  536.                 buforg += codend.b - lspace;
  537.                 codend.b = lspace;
  538.                 if (codend.b + len >= lspcend)
  539.                         Fatal ("Module won't fit in memory at all!\n");
  540.                 }
  541.         lodstart = codend.b;
  542.         if (cread (&ibuf, lodstart, len) < len) Fatal ("-- read error!\n");
  543.         }
  544.  
  545.  
  546. scanlib (ifile)
  547.         int ifile;
  548. {
  549.         int i;
  550.         union ptr dirtmp;
  551.  
  552.         makeext (&libfiles[ifile], "CRL");
  553.         if (copen (&ibuf, libfiles[ifile]) < 0) {
  554.                 if (ifile != deflibindex + (NDEFF-1))
  555.                         printf ("Can't open %s\n", libfiles[ifile]);
  556.                 return;
  557.                 }
  558.         printf ("Scanning %s\n", &libfiles[ifile]);
  559.         if (cread (&ibuf, &fdir, 512) < 512)    /* read directory */
  560.                 Fatal ("-- Read error!\n");
  561.         for (i=0; i<nfuncts; ++i) {             /* scan needed functions */
  562.                 if (!ftab[i].flinkedp
  563.                     && (dirtmp.b = dirsearch (&ftab[i].fname))) {
  564.                         readfunct (dirtmp.b);
  565.                         linkmod (&ftab[i], lodstart);
  566.                         }
  567.                 }
  568.         cclose (&ibuf);
  569.         }
  570.  
  571.  
  572. readfunct (direntry)                    /* read a function (from a library) */
  573.         union ptr direntry;
  574. {
  575.         unsigned start, len;
  576.  
  577.         skip7 (&direntry);
  578.         start = *direntry.w++;
  579.         skip7 (&direntry);
  580.         len = *direntry.w - start;
  581.         if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
  582.         readobj (len);
  583.         }
  584.  
  585.  
  586. linkmod (fnct, modstart)                /* link in a module */
  587.         struct funct *fnct;
  588.         union ptr modstart;             /* loc. of module in memory */
  589.  
  590. {
  591.         union ptr temp,
  592.                         jump,           /* jump table temp */
  593.                         body,           /* loc. of function in memory */
  594.                         code,           /* loc. of code proper in mem. */
  595.                         finalloc;       /* runtime loc. of function */
  596.         unsigned flen, nrelocs, jtsiz, offset;
  597.  
  598.         fnct->flinkedp = LINKED;
  599.         if (phase != DISK2) {
  600.                 finalloc.b = codend.b - lspace + buforg;
  601.                 if (phase == INMEM) chase (fnct->faddr, finalloc.b);
  602.                 fnct->faddr = finalloc.b;
  603.                 }
  604.         else finalloc.b = fnct->faddr;
  605.         body.b = modstart.b + strlen(modstart.b) + 3; /* loc. of fn body */
  606.         jump.i = body.i + (*modstart.b ? 1 : 0);
  607.         for (temp.b = modstart.b; *temp.b; skip7(&temp)) {
  608.                 jump.i->address = intern (temp.b);
  609.                 ++jump.i;
  610.                 }
  611.         ++temp.b;
  612.         flen = *temp.w;
  613.         code.b = jump.b;
  614.         temp.b = body.b + flen;         /* loc. of reloc parameters */
  615.         nrelocs = *temp.w++;
  616.         jtsiz = code.b - body.b;
  617.         if (Dflag && fnct->fdebug) {
  618.                 if (phase!=DISK1) {
  619.                         codend.i->opcode = (0307 + (8*RST_NUM));
  620.                         codend.i->address = 0;
  621.                         finalloc.b += 3;
  622.                         }
  623.                 codend.b += 3;
  624.                 }
  625.         offset = code.b - codend.b;
  626.         if (phase != DISK1)
  627.                 while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
  628.                                                    finalloc.b, offset, flen);
  629.         flen -= jtsiz;
  630.         if (phase != DISK2) jtsaved += jtsiz;
  631.         if (phase != DISK1) movmem (code.b, codend.b, flen);
  632.         codend.b += flen;
  633.         }
  634.  
  635.  
  636. relocate (param, body, jtsiz, base, offset, flen)       /* do a relocation!! */
  637.         unsigned param, jtsiz, base, offset, flen;
  638.         union ptr body;
  639. {
  640.         union ptr instr,                        /* instruction involved */
  641.                         ref;                        /* jump table link */
  642.         struct funct *fnct;
  643.  
  644. /*      if (param == 1) return;                 /* don't reloc jt skip */*/
  645.         instr.b = body.b + param - 1;
  646.         if (instr.i->address >= jtsiz)
  647.                 instr.i->address += base - jtsiz;       /* vanilla case */
  648.         else {
  649.                 ref.b = instr.i->address + body.u;
  650.                 if (instr.i->opcode == LHLD) {
  651.                         instr.i->opcode = LXIH;
  652.                         --ref.b;
  653.                         }
  654.                 fnct = ref.i->address;
  655.                 instr.i->address = fnct->faddr;         /* link in */
  656.                 if (!fnct->flinkedp  &&  phase == INMEM)
  657.                         fnct->faddr = instr.b + 1 - offset;  /* new list head */
  658.                 }
  659.         }
  660.  
  661.  
  662. intern (name)                   /* intern a function name in the table */
  663.         char *name;
  664. {
  665.         struct funct *fptr;
  666.  
  667.         if (*name == 0x9D) name = "MAIN";               /* Why, Leor, WHY??? */
  668.         for (fptr = &ftab[nfuncts-1]; fptr >= ftab; --fptr)
  669.                 if (!strcmp7 (name, fptr->fname)) break;
  670.         if (fptr < ftab) {
  671.                 if (nfuncts >= maxfuncts)
  672.                         Fatal("Too many functions (limit is %d)!\n", maxfuncts);
  673.                 fptr = &ftab[nfuncts];
  674.                 strcpy7 (fptr->fname, name);
  675.                 str7tont (fptr->fname);
  676.                 fptr->flinkedp = FALSE;
  677.                 fptr->faddr = NULL;
  678.                 fptr->fdebug = !SysStat;
  679.                 ++nfuncts;
  680.                 }
  681.         return (fptr);
  682.         }
  683.  
  684.  
  685. dirsearch (name)                        /* search directory for a function */
  686.         char *name;
  687. {
  688.         union ptr temp;
  689.  
  690.         for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
  691.                 if (!strcmp7 (name, temp.b)) return (temp.b);
  692.         return (NULL);
  693.         }
  694.  
  695.  
  696. nextd (ptrp)                    /* move this pointer to the next dir entry */
  697.         union ptr *ptrp;
  698. {
  699.         skip7 (ptrp);
  700.         ++(*ptrp).w;
  701.         }
  702.  
  703.  
  704. chase (head, loc)               /* chase chain of refs to function */
  705.         union ptr head;
  706.         unsigned loc;
  707. {
  708.         union ptr temp;
  709.  
  710.         while (head.w) {
  711.                 temp.w = *head.w;
  712.                 *head.w = loc;
  713.                 head.u = temp.u;
  714.                 }
  715.         }
  716.  
  717.  
  718. wrtcom()                        /* write out com file (from in-mem link) */
  719. {
  720.         hackccc();
  721.         if (!ovlp) makeext (&progfiles[0], "COM");
  722.         else makeext (&progfiles[0], "OVL");
  723.         if (!ccreat (&obuf, &progfiles[0]) < 0
  724.             ||  cwrite (&obuf, lspace, codend.b - lspace) == -1
  725.             ||  cflush (&obuf) < 0)
  726.                 Fatal ("Disk write error!\n");
  727.         cclose (&obuf);
  728.         stats (STDOUT);
  729.         }
  730.  
  731.  
  732. hackccc()                       /* store various goodies in C.CCC code */
  733. {
  734.         union ptr temp;
  735.         struct funct *fptr;
  736.  
  737.         temp.b = lspace;
  738.         fptr = intern (&mainfunct);
  739.         if (!ovlp) {
  740.                         if (Tflag) {
  741.                                 temp.i->opcode = LXISP;
  742.                                 temp.i->address = Tval;
  743.                                 }
  744.                         else if (Nflag) {
  745.                                 temp.i->opcode = JMP;
  746.                                 temp.i->address = SNOBSP;
  747.                                 temp.b = lspace + 0x09;
  748.                                 temp.i->opcode = JMP;
  749.                                 temp.i->address = NOBRET;
  750.                                 }
  751.                         else {
  752.                                 temp.i->opcode = LHLD;
  753.                                 temp.i->address = origin - 0x100 + 6;
  754.                                 (++temp.i)->opcode = SPHL;
  755.                                 }
  756.  
  757.                         temp.b = lspace + 0xF;      /* main function address */
  758.                         temp.i->address = fptr->faddr;
  759.                 temp.b = lspace + 0x15;
  760.                 *temp.w++ = exts.u;
  761.                 ++temp.w;
  762.                 *temp.w++ = acodend.u;
  763.                 *temp.w++ = exts.u + extspc;
  764.                 }
  765.         else temp.i->address = fptr->faddr;             /* that's a JMP */
  766.         }
  767.  
  768.  
  769. #if !SHORTL2
  770. wrtsyms()                                       /* write out symbol table */
  771. {
  772.         int i, fd, compar();
  773.        
  774.         qsort (ftab, nfuncts, sizeof(*ftab), &compar);
  775.         makeext (&progfiles[0], "SYM");
  776.         if ((symbuf = fopen (&progfiles[0], "w")) < 0)
  777.                 Fatal ("Can't create .SYM file\n");
  778.         for (i=0; i < nfuncts; ++i) {
  779.                 puthex (ftab[i].faddr, symbuf);
  780.                 putc (' ', symbuf);
  781.                 fputs (&ftab[i].fname, symbuf);
  782.                 if (i % 4 == 3) fputs ("\n", symbuf);
  783.                 else {
  784.                         if (strlen (&ftab[i].fname) < 3) putc ('\t', symbuf);
  785.                         putc ('\t', symbuf);
  786.                         }
  787.                 }
  788.         if (i % 4) fputs ("\n", symbuf);       
  789.         if (appstatsp) stats (symbuf);
  790.         putc (CPMEOF, symbuf);
  791.         fclose (symbuf);
  792.         if (sepstatsp) {
  793.                 makeext (&progfiles[0], "LNK");
  794.                 if ((symbuf = fopen (&progfiles[0], "w")) < 0)
  795.                         Fatal ("Can't create .LNK file\n");
  796.                 stats (symbuf);
  797.                 putc (CPMEOF, symbuf);
  798.                 fclose (symbuf);
  799.                 }
  800.         }
  801. #endif
  802.  
  803. compar (f1, f2)                 /* compare two symbol table entries by name */
  804.         struct funct *f1, *f2;
  805. {
  806. /*      return (strcmp (&f1->fname, &f2->fname));       alphabetical order */
  807.         return (f1->faddr > f2->faddr);                 /* memory order */
  808.         }
  809.  
  810.  
  811. #if OVERLAYS
  812. loadsyms()                      /* load base symbol table (for overlay) */
  813. {                                   /* symbol table must be empty! */
  814.         int nread;
  815.         FLAG done;
  816.         char *c;
  817.        
  818.         makeext (&symsfile, "SYM");
  819.         if (fopen (&symsfile, &symbuf) < 0)
  820.                 Fatal ("Can't open %s.\n", &symsfile);
  821.         done = FALSE;
  822.         while (!done) {
  823.                 nread =
  824.                    fscanf (&symbuf, "%x %s\t%x %s\t%x %s\t%x %s\n",
  825.                            &(ftab[nfuncts].faddr), &(ftab[nfuncts].fname),
  826.                            &(ftab[nfuncts+1].faddr), &(ftab[nfuncts+1].fname),
  827.                            &(ftab[nfuncts+2].faddr), &(ftab[nfuncts+2].fname),
  828.                            &(ftab[nfuncts+3].faddr), &(ftab[nfuncts+3].fname));
  829.                 nread /= 2;
  830.                 if (nread < 4) done = TRUE;
  831.                 while (nread-- > 0) ftab[nfuncts++].flinkedp = EXTERNAL;
  832.                 }
  833.         fclose (&symbuf);
  834.         }
  835. #endif
  836.  
  837. stats (chan)                            /* print statistics on chan */
  838.         int chan;
  839. {
  840.         unsigned temp, *tptr;
  841.  
  842.         tptr = 6;
  843.         fprintf (chan, "\n\nLink statistics:\n");
  844.         fprintf (chan, "  Number of functions: %d\n", nfuncts);
  845.         fprintf (chan, "  Code ends at: 0x%x\n", acodend.u);
  846.         fprintf (chan, "  Externals begin at: 0x%x\n", exts.u);
  847.         fprintf (chan, "  Externals end at: 0x%x\n", exts.u + extspc);
  848.         fprintf (chan, "  End of current TPA: 0x%x\n", *tptr);
  849.         fprintf (chan, "  Jump table bytes saved: 0x%x\n", jtsaved);
  850.         temp = lspcend;
  851.         if (phase == INMEM)
  852.                 fprintf (chan,
  853.                    "  Link space remaining: %dK\n", (temp - codend.u) / 1024);
  854.         }
  855.  
  856.  
  857. makeext (fname, ext)            /* force a file extension to ext */
  858.         char *fname, *ext;
  859. {
  860.         while (*fname && (*fname != '.')) {
  861.                 *fname = toupper (*fname);              /* upcase as well */
  862.                 ++fname;
  863.                 }
  864.         *fname++ = '.';
  865.         strcpy (fname, ext);
  866.         }
  867.  
  868.  
  869. strcmp7 (s1, s2) char *s1, *s2; {
  870.  
  871.         /* compare two strings, either bit-7-terminated or null-terminated */
  872.  
  873.         for (; (_c1 = *s1) == *s2; s1++, s2++)
  874.                 if ( (0x80 & _c1) || !_c1) return 0;
  875.  
  876.         if ((_c1 &= 0x7F) < (_c2 = 0x7F & *s2)) return -1;
  877.         if (_c1 > _c2) return  1;
  878.  
  879.         _end1 = (*s1 & 0x80) || !*(s1+1);
  880.         _end2 = (*s2 & 0x80) || !*(s2+1);
  881.         if (_end2  &&  !_end1) return 1;
  882.         if (_end1  &&  !_end2) return -1;
  883.         /* if (_end1  &&  _end2) */ return 0;
  884. }
  885.  
  886. strcpy7 (s1, s2)                        /* copy s2 into s1 */
  887.         char *s1, *s2;
  888. {
  889.         do {
  890.                 *s1 = *s2;
  891.                 if (!*(s2+1)) {                 /* works even if */
  892.                         *s1 |= 0x80;                    /* s2 is null-term */
  893.                         break;
  894.                         }
  895.                 ++s1;
  896.                 } while (!(*s2++ & 0x80));
  897.         }
  898.  
  899.  
  900. skip7 (ptr7)                            /* move this pointer past a string */
  901.         char **ptr7;
  902. {
  903.         while (!(*(*ptr7)++ & 0x80));
  904.         }
  905.  
  906.  
  907. str7tont (s)                            /* add null at end */
  908.         char *s;
  909. {
  910.         while (!(*s & 0x80)) {
  911.                 if (!*s) return;                /* already nul term! */
  912.                 s++;
  913.                 }
  914.         *s = *s & 0x7F;
  915.         *++s = NUL;
  916.         }
  917.  
  918.  
  919. puthex (n, obuf)                        /* output a hex word, with leading 0s */
  920.         unsigned n;
  921.         char *obuf;
  922. {
  923.         int i, nyb;
  924.        
  925.         for (i = 3; i >= 0; --i) {
  926.                 nyb = (n >> (i * 4)) & 0xF;
  927.                 nyb += (nyb > 9) ? 'A' - 10 : '0';
  928.                 putc (nyb, obuf);
  929.                 }
  930.         }
  931.  
  932.  
  933. Fatal (arg1, arg2, arg3, arg4)  /* lose, lose */
  934.         char *arg1, *arg2, *arg3, *arg4;
  935. {
  936.         printf (arg1, arg2, arg3, arg4);
  937.         lexit (1);
  938.         }
  939.  
  940.  
  941. lexit (status)                          /* exit the program */
  942.         int status;
  943. {
  944.         if (status == 1)
  945.                 unlink (SUB_FILE);
  946.         exit();         /* bye! */
  947.         }
  948.  
  949.  
  950.  
  951. /* END OF L2.C */
  952.