* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[fw/sdcc] / as / link / mcs51 / lkmain.c
1 /* lkmain.c
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 /*
20  * 31-Oct-97 JLH:
21  *           - add jflag and jfp to control NoICE output file generation
22  *  3-Nov-97 JLH:
23  *           - use a_type == 0 as "virgin area" flag: set == 1 if -b
24  */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include "aslink.h"
30
31 #ifdef WIN32T
32 #include <time.h>
33
34 void Timer(int action, char * message)
35 {
36     static double start, end, total=0.0;
37     static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
38
39     if(action==0) start=clock()*secs_per_tick;
40     else if(action==1)
41     {
42         end=clock() * secs_per_tick;
43         printf("%s \t%f seconds.\n", message, (end-start));
44         total+=end-start;
45     }
46     else
47     {
48         printf("Total time: \t%f seconds.\n", total);
49         total=0.0;
50     }
51 }
52 #endif
53
54 /*)Module   lkmain.c
55  *
56  *  The module lkmain.c contains the functions which
57  *  (1) input the linker options, parameters, and specifications
58  *  (2) perform a two pass link
59  *  (3) produce the appropriate linked data output and/or
60  *      link map file and/or relocated listing files.
61  *
62  *  lkmain.c contains the following functions:
63  *      FILE *  afile(fn,ft,wf)
64  *      VOID    bassav()
65  *      VOID    gblsav()
66  *      VOID    link_main()
67  *      VOID    lkexit()
68  *      VOID    main(argc,argv)
69  *      VOID    map()
70  *      int     parse()
71  *      VOID    setbas()
72  *      VOID    setgbl()
73  *      VOID    usage()
74  *
75  *  lkmain.c contains the following local variables:
76  *      char *  usetext[]   array of pointers to the
77  *                          command option tect lines
78  *
79  */
80
81 /*JCF:  Creates some of the default areas so they are allocated in the right order.*/
82 void Areas51 (void)
83 {
84     char * rel[]={
85         "XH",
86         "H 7 areas 0 global symbols",
87         "A _CODE size 0 flags 0",       /*Each .rel has one, so...*/
88         "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
89         "A REG_BANK_1 size 0 flags 4",
90         "A REG_BANK_2 size 0 flags 4",
91         "A REG_BANK_3 size 0 flags 4",
92         "A BSEG size 0 flags 80",       /*BSEG must be just before BITS*/
93         "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
94         ""
95     };
96
97     char * rel2[]={
98         "XH",
99         "H C areas 0 global symbols",
100         "A _CODE size 0 flags 0",       /*Each .rel has one, so...*/
101         "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
102         "A REG_BANK_1 size 0 flags 4",
103         "A REG_BANK_2 size 0 flags 4",
104         "A REG_BANK_3 size 0 flags 4",
105         "A BSEG size 0 flags 80",       /*BSEG must be just before BITS*/
106         "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
107         "A BIT_BANK size 0 flags 4",    /*Bit register bank is overlayable*/
108         "A DSEG size 0 flags 0",
109         "A OSEG size 0 flags 4",
110         "A ISEG size 0 flags 0",
111         "A SSEG size 0 flags 4",
112         ""
113     };
114     int j;
115     struct sym * sp;
116
117     if(packflag)
118     {
119         for (j=0; rel2[j][0]!=0; j++)
120         {
121             ip=rel2[j];
122             link_main();
123         }
124     }
125     else
126     {
127         for (j=0; rel[j][0]!=0; j++)
128         {
129             ip=rel[j];
130             link_main();
131         }
132     }
133
134     /*Set the start address of the default areas:*/
135     for(ap=areap; ap; ap=ap->a_ap)
136     {
137         /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr=0x00; ap->a_type=1; }
138         else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr=0x08; ap->a_type=1; }
139         else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; }
140         else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; }
141         else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; }
142         else if (!strcmp(ap->a_id, "SSEG"))
143         {
144             if(stacksize) ap->a_axp->a_size=stacksize;
145         }
146     }
147
148     sp = lkpsym("l_IRAM", 1);
149     sp->s_addr = ((iram_size>0) && (iram_size<=0x100)) ? iram_size : 0x0100;
150     sp->s_axp = NULL;
151     sp->s_type |= S_DEF;
152 }
153
154 /*)Function VOID    main(argc,argv)
155  *
156  *      int     argc        number of command line arguments + 1
157  *      char *  argv[]      array of pointers to the command line
158  *                          arguments
159  *
160  *  The function main() evaluates the command line arguments to
161  *  determine if the linker parameters are to input through 'stdin'
162  *  or read from a command file.  The functions lk_getline() and parse()
163  *  are to input and evaluate the linker parameters.  The linking process
164  *  proceeds by making the first pass through each .rel file in the order
165  *  presented to the linker.  At the end of the first pass the setbase(),
166  *  lnkarea(), setgbl(), and symdef() functions are called to evaluate
167  *  the base address terms, link all areas, define global variables,
168  *  and look for undefined symbols.  Following these routines a linker
169  *  map file may be produced and the linker output files may be opened.
170  *  The second pass through the .rel files will output the linked data
171  *  in one of the four supported formats.
172  *
173  *  local variables:
174  *      char *  p           pointer to an argument string
175  *      int     c           character from argument string
176  *      int     i           loop counter
177  *
178  *  global variables:
179  *                          text line in ib[]
180  *      lfile   *cfp        The pointer *cfp points to the
181  *                          current lfile structure
182  *      char    ctype[]     array of character types, one per
183  *                          ASCII character
184  *      lfile   *filep      The pointer *filep points to the
185  *                          beginning of a linked list of
186  *                          lfile structures.
187  *      head    *hp         Pointer to the current
188  *                          head structure
189  *      char    ib[NINPUT]  .rel file text line
190  *      char    *ip         pointer into the .rel file
191  *      lfile   *linkp      pointer to first lfile structure
192  *                          containing an input .rel file
193  *                          specification
194  *      int     lkerr       error flag
195  *      int     mflag       Map output flag
196  *      int     oflag       Output file type flag
197  *      FILE    *ofp        Output file handle
198  *                          for word formats
199  *      FILE    *ofph       Output file handle
200  *                          for high byte format
201  *      FILE    *ofpl       Output file handle
202  *                          for low byte format
203  *      int     pass        linker pass number
204  *      int     pflag       print linker command file flag
205  *      int     radix       current number conversion radix
206  *      FILE    *sfp        The file handle sfp points to the
207  *                          currently open file
208  *      lfile   *startp     asmlnk startup file structure
209  *      FILE *  stdin       c_library
210  *      FILE *  stdout      c_library
211  *
212  *  functions called:
213  *      FILE *  afile()     lkmain.c
214  *      int     fclose()    c_library
215  *      int     fprintf()   c_library
216  *      int     lk_getline()   lklex.c
217  *      VOID    library()   lklibr.c
218  *      VOID    link_main() lkmain.c
219  *      VOID    lkexit()    lkmain.c
220  *      VOID    lnkarea()   lkarea.c
221  *      VOID    map()       lkmain.c
222  *      VOID    new()       lksym.c
223  *      int     parse()     lkmain.c
224  *      VOID    reloc()     lkreloc.c
225  *      VOID    search()    lklibr.c
226  *      VOID    setbas()    lkmain.c
227  *      VOID    setgbl()    lkmain.c
228  *      VOID    symdef()    lksym.c
229  *      VOID    usage()     lkmain.c
230  *
231  *  side effects:
232  *      Completion of main() completes the linking process
233  *      and may produce a map file (.map) and/or a linked
234  *      data files (.ihx or .s19) and/or one or more
235  *      relocated listing files (.rst).
236  */
237
238 int
239 main(int argc, char *argv[])
240 {
241     register char *p;
242     register int c, i;
243
244 #ifdef WIN32T
245     Timer(0, "");
246 #endif
247
248     startp = (struct lfile *) new (sizeof (struct lfile));
249
250     pflag = 1;
251     for (i=1; i<argc; ++i) {
252         p = argv[i];
253         if (*p == '-') {
254             while (ctype[c = *(++p)] & LETTER) {
255                 switch(c) {
256
257                 case 'c':
258                 case 'C':
259                     startp->f_type = F_STD;
260                     break;
261
262                 case 'f':
263                 case 'F':
264                     startp->f_type = F_LNK;
265                     break;
266
267                 case 'n':
268                 case 'N':
269                     pflag = 0;
270                     break;
271
272                 case 'p':
273                 case 'P':
274                     pflag = 1;
275                     break;
276
277                 default:
278                     usage();
279                 }
280             }
281         } else {
282             if (startp->f_type == F_LNK) {
283                 startp->f_idp = p;
284             }
285         }
286     }
287     if (startp->f_type == 0)
288         usage();
289     if (startp->f_type == F_LNK && startp->f_idp == NULL)
290         usage();
291
292     cfp = NULL;
293     sfp = NULL;
294     filep = startp;
295     while (1) {
296         ip = ib;
297         if (lk_getline() == 0)
298             break;
299         if (pflag && sfp != stdin)
300             fprintf(stdout, "%s\n", ip);
301         if (*ip == '\0' || parse())
302             break;
303     }
304
305     if (sfp) {
306         fclose(sfp);
307         sfp = NULL;
308     }
309
310     if (linkp == NULL)
311         usage();
312
313     syminit();
314
315     if (dflag){
316         //dfp = afile("temp", "cdb", 1);
317         SaveLinkedFilePath(linkp->f_idp); //Must be the first one...
318         dfp = afile(linkp->f_idp,"cdb",1); //JCF: Nov 30, 2002
319         if (dfp == NULL)
320             lkexit(1);
321     }
322
323     for (pass=0; pass<2; ++pass) {
324         cfp = NULL;
325         sfp = NULL;
326         filep = linkp;
327         hp = NULL;
328         radix = 10;
329
330         Areas51(); /*JCF: Create the default 8051 areas in the right order*/
331
332         while (lk_getline()) {
333             ip = ib;
334
335             /* pass any "magic comments" to NoICE output */
336             if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
337                 fprintf( jfp, "%s\n", &ip[2] );
338             }
339             link_main();
340         }
341         if (pass == 0) {
342             /*
343              * Search libraries for global symbols
344              */
345             search();
346             /*
347              * Set area base addresses.
348              */
349             setbas();
350             /*
351              * Link all area addresses.
352              */
353             if(!packflag)
354                 lnkarea();
355             else
356                 lnkarea2();
357             /*
358              * Process global definitions.
359              */
360             setgbl();
361             /*
362              * Check for undefined globals.
363              */
364             symdef(stderr);
365
366             /* Open NoICE output file if requested */
367             if (jflag) {
368                 jfp = afile(linkp->f_idp, "NOI", 1);
369                 if (jfp == NULL) {
370                     lkexit(1);
371                 }
372             }
373
374             /*
375              * Output Link Map if requested,
376              * or if NoICE output requested (since NoICE
377              * file is generated in part by map() processing)
378              */
379             if (mflag || jflag)
380                 map();
381
382             if (sflag) /*JCF: memory usage summary output*/
383             {
384                 if(!packflag)
385                 {
386                     if(summary(areap)) lkexit(1);
387                 }
388                 else
389                 {
390                     if(summary2(areap)) lkexit(1);
391                 }
392             }
393
394             if ((iram_size) && (!packflag))
395                 iramcheck();
396
397             /*
398              * Open output file
399              */
400             if (oflag == 1) {
401                 ofp = afile(linkp->f_idp, "ihx", 1);
402                 if (ofp == NULL) {
403                     lkexit(1);
404                 }
405                 /* include NoICE command to load hex file */
406                 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
407
408             } else
409             if (oflag == 2) {
410                 ofp = afile(linkp->f_idp, "S19", 1);
411                 if (ofp == NULL) {
412                     lkexit(1);
413                 }
414                 /* include NoICE command to load hex file */
415                 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
416             }
417         } else {
418             /*
419              * Link in library files
420              */
421             library();
422             reloc('E');
423         }
424     }
425     //JCF:
426     CreateAOMF51();
427
428 #ifdef WIN32T
429     Timer(1, "Linker execution time");
430 #endif
431
432     lkexit(lkerr);
433
434     /* Never get here. */
435     return 0;
436 }
437
438 /*)Function VOID    lkexit(i)
439  *
440  *      int     i       exit code
441  *
442  *  The function lkexit() explicitly closes all open
443  *  files and then terminates the program.
444  *
445  *  local variables:
446  *      none
447  *
448  *  global variables:
449  *      FILE *  mfp     file handle for .map
450  *      FILE *  ofp     file handle for .ihx/.s19
451  *      FILE *  rfp     file hanlde for .rst
452  *      FILE *  sfp     file handle for .rel
453  *      FILE *  tfp     file handle for .lst
454  *
455  *  functions called:
456  *      int     fclose()    c_library
457  *      VOID    exit()      c_library
458  *
459  *  side effects:
460  *      All files closed. Program terminates.
461  */
462
463 VOID
464 lkexit(int i)
465 {
466     if (mfp != NULL) fclose(mfp);
467     if (jfp != NULL) fclose(jfp);
468     if (ofp != NULL) fclose(ofp);
469     if (rfp != NULL) fclose(rfp);
470     if (sfp != NULL) fclose(sfp);
471     if (tfp != NULL) fclose(tfp);
472     if (dfp != NULL) fclose(dfp);
473     exit(i);
474 }
475
476 /*)Function link_main()
477  *
478  *  The function link_main() evaluates the directives for each line of
479  *  text read from the .rel file(s).  The valid directives processed
480  *  are:
481  *      X, D, Q, H, M, A, S, T, R, and P.
482  *
483  *  local variables:
484  *      int     c           first non blank character of a line
485  *
486  *  global variables:
487  *      head    *headp      The pointer to the first
488  *                          head structure of a linked list
489  *      head    *hp         Pointer to the current
490  *                          head structure
491  *      int     pass        linker pass number
492  *      int     radix       current number conversion radix
493  *
494  *  functions called:
495  *      char    endline()   lklex.c
496  *      VOID    module()    lkhead.c
497  *      VOID    newarea()   lkarea.c
498  *      VOID    newhead()   lkhead.c
499  *      sym *   newsym()    lksym.c
500  *      VOID    reloc()     lkreloc.c
501  *
502  *  side effects:
503  *      Head, area, and symbol structures are created and
504  *      the radix is set as the .rel file(s) are read.
505  */
506
507 VOID
508 link_main()
509 {
510     register char c;
511
512     if ((c=endline()) == 0) { return; }
513     switch (c) {
514
515     case 'O': /*For some important sdcc options*/
516         if (pass == 0)
517         {
518             if(strlen(sdccopt)==0)
519             {
520                 strcpy(sdccopt, &ip[1]);
521                 strcpy(sdccopt_module, curr_module);
522             }
523             else
524             {
525                 if(strcmp(sdccopt, &ip[1])!=0)
526                 {
527                     fprintf(stderr,
528                     "?ASlink-Warning-Conflicting sdcc options:\n"
529                     "   \"%s\" in module \"%s\" and\n"
530                     "   \"%s\" in module \"%s\".\n",
531                     sdccopt, sdccopt_module, &ip[1], curr_module);
532                     lkerr++;
533                 }
534             }
535         }
536         break;
537
538     case 'X':
539         radix = 16;
540         break;
541
542     case 'D':
543         radix = 10;
544         break;
545
546     case 'Q':
547         radix = 8;
548         break;
549
550     case 'H':
551         if (pass == 0) {
552             newhead();
553         } else {
554             if (hp == 0) {
555                 hp = headp;
556             } else {
557                 hp = hp->h_hp;
558             }
559         }
560         sdp.s_area = NULL;
561         sdp.s_areax = NULL;
562         sdp.s_addr = 0;
563         break;
564
565     case 'M':
566         if (pass == 0)
567         {
568             strcpy(curr_module, &ip[1]);
569             module();
570         }
571         break;
572
573     case 'A':
574         if (pass == 0)
575             newarea();
576         if (sdp.s_area == NULL) {
577             sdp.s_area = areap;
578             sdp.s_areax = areap->a_axp;
579             sdp.s_addr = 0;
580         }
581         break;
582
583     case 'S':
584         if (pass == 0)
585             newsym();
586         break;
587
588     case 'T':
589     case 'R':
590     case 'P':
591         if (pass == 0)
592             break;
593         reloc(c);
594         break;
595
596     default:
597         break;
598     }
599     if (c == 'X' || c == 'D' || c == 'Q') {
600         if ((c = get()) == 'H') {
601             hilo = 1;
602         } else
603         if (c == 'L') {
604             hilo = 0;
605         }
606     }
607 }
608
609 /*)Function VOID    map()
610  *
611  *  The function map() opens the output map file and calls the various
612  *  routines to
613  *  (1) output the variables in each area,
614  *  (2) list the files processed with module names,
615  *  (3) list the libraries file processed,
616  *  (4) list base address definitions,
617  *  (5) list global variable definitions, and
618  *  (6) list any undefined variables.
619  *
620  *  local variables:
621  *      int     i           counter
622  *      head *  hdp         pointer to head structure
623  *      lbfile *lbfh        pointer to library file structure
624  *
625  *  global variables:
626  *      area    *ap         Pointer to the current
627  *                          area structure
628  *      area    *areap      The pointer to the first
629  *                          area structure of a linked list
630  *      base    *basep      The pointer to the first
631  *                          base structure
632  *      base    *bsp        Pointer to the current
633  *                          base structure
634  *      lfile   *filep      The pointer *filep points to the
635  *                          beginning of a linked list of
636  *                          lfile structures.
637  *      globl   *globlp     The pointer to the first
638  *                          globl structure
639  *      globl   *gsp        Pointer to the current
640  *                          globl structure
641  *      head    *headp      The pointer to the first
642  *                          head structure of a linked list
643  *      lbfile  *lbfhead    The pointer to the first
644  *                          lbfile structure of a linked list
645  *      lfile   *linkp      pointer to first lfile structure
646  *                          containing an input REL file
647  *                          specification
648  *      int     lop         current line number on page
649  *      FILE    *mfp        Map output file handle
650  *      int     page        current page number
651  *
652  *  functions called:
653  *      FILE *  afile()     lkmain.c
654  *      int     fprintf()   c_library
655  *      VOID    lkexit()    lkmain.c
656  *      VOID    lstarea()   lklist.c
657  *      VOID    newpag()    lklist.c
658  *      VOID    symdef()    lksym.c
659  *
660  *  side effects:
661  *      The map file is created.
662  */
663
664 VOID
665 map()
666 {
667     register int i;
668     register struct head *hdp;
669     register struct lbfile *lbfh;
670
671     /*
672      * Open Map File
673      */
674     mfp = afile(linkp->f_idp, "map", 1);
675     if (mfp == NULL) {
676         lkexit(1);
677     }
678
679     /*
680      * Output Map Area Lists
681      */
682     page = 0;
683     lop  = NLPP;
684     ap = areap;
685     while (ap) {
686         lstarea(ap);
687         ap = ap->a_ap;
688     }
689     /*
690      * List Linked Files
691      */
692     newpag(mfp);
693     fprintf(mfp, "\nFiles Linked      [ module(s) ]\n\n");
694     hdp = headp;
695     filep = linkp;
696     while (filep) {
697         fprintf(mfp, "%-16s", filep->f_idp);
698         i = 0;
699         while ((hdp != NULL) && (hdp->h_lfile == filep)) {
700             if (i % 5) {
701                 fprintf(mfp, ", %8.8s", hdp->m_id);
702             } else {
703                 if (i) {
704                 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
705                 } else {
706                 fprintf(mfp, "  [ %8.8s", hdp->m_id);
707                 }
708             }
709             hdp = hdp->h_hp;
710             i++;
711         }
712         if (i)
713             fprintf(mfp, " ]");
714         fprintf(mfp, "\n");
715         filep = filep->f_flp;
716     }
717     /*
718      * List Linked Libraries
719      */
720     if (lbfhead != NULL) {
721         fprintf(mfp,
722             "\nLibraries Linked            [   object  file   ]\n\n");
723         for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
724             fprintf(mfp, "%-32s    [ %16.16s ]\n",
725                 lbfh->libspc, lbfh->relfil);
726         }
727         fprintf(mfp, "\n");
728     }
729     /*
730      * List Base Address Definitions
731      */
732     if (basep) {
733         newpag(mfp);
734         fprintf(mfp, "\nUser Base Address Definitions\n\n");
735         bsp = basep;
736         while (bsp) {
737             fprintf(mfp, "%s\n", bsp->b_strp);
738             bsp = bsp->b_base;
739         }
740     }
741     /*
742      * List Global Definitions
743      */
744     if (globlp) {
745         newpag(mfp);
746         fprintf(mfp, "\nUser Global Definitions\n\n");
747         gsp = globlp;
748         while (gsp) {
749             fprintf(mfp, "%s\n", gsp->g_strp);
750             gsp = gsp->g_globl;
751         }
752     }
753     fprintf(mfp, "\n\f");
754     symdef(mfp);
755 }
756
757 /*)Function int parse()
758  *
759  *  The function parse() evaluates all command line or file input
760  *  linker directives and updates the appropriate variables.
761  *
762  *  local variables:
763  *      int     c           character value
764  *      char    fid[]       file id string
765  *
766  *  global variables:
767  *      char    ctype[]     array of character types, one per
768  *                          ASCII character
769  *      lfile   *lfp        pointer to current lfile structure
770  *                          being processed by parse()
771  *      lfile   *linkp      pointer to first lfile structure
772  *                          containing an input REL file
773  *                          specification
774  *      int     mflag       Map output flag
775  *      int     oflag       Output file type flag
776  *      int     pflag       print linker command file flag
777  *      FILE *  stderr      c_library
778  *      int     uflag       Relocated listing flag
779  *      int     xflag       Map file radix type flag
780  *
781  *  Functions called:
782  *      VOID    addlib()    lklibr.c
783  *      VOID    addpath()   lklibr.c
784  *      VOID    bassav()    lkmain.c
785  *      int     fprintf()   c_library
786  *      VOID    gblsav()    lkmain.c
787  *      VOID    getfid()    lklex.c
788  *      char    getnb()     lklex.c
789  *      VOID    lkexit()    lkmain.c
790  *      char *  strcpy()    c_library
791  *      int     strlen()    c_library
792  *
793  *  side effects:
794  *      Various linker flags are updated and the linked
795  *      structure lfile is created.
796  */
797
798 int
799 parse()
800 {
801     register int c;
802     char fid[NINPUT];
803
804     while ((c = getnb()) != 0) {
805         if ( c == ';')
806             return(0);
807         if ( c == '-') {
808             while (ctype[c=get()] & LETTER) {
809                 switch(c) {
810
811                 case 'i':
812                 case 'I':
813                     oflag = 1;
814                     break;
815
816                 case 's':
817                 case 'S':
818                     oflag = 2;
819                     break;
820
821                 case 'm':
822                 case 'M':
823                     ++mflag;
824                     break;
825
826                 case 'y': /*JCF: memory usage summary output*/
827                     ++sflag;
828                     break;
829
830                 case 'Y':
831                     unget(getnb());
832                     packflag=1;
833                     break;
834
835                 case 'A':
836                     unget(getnb());
837                     if (ip && *ip)
838                     {
839                         stacksize=expr(0);
840                         if(stacksize>256) stacksize=256;
841                         else if(stacksize<0) stacksize=0;
842                     }
843                     return(0);
844
845                 case 'j':
846                 case 'J':
847                     jflag = 1;
848                     break;
849
850                 case 'u':
851                 case 'U':
852                     uflag = 1;
853                     break;
854                 case 'r':
855                 case 'R':
856                     rflag = 1;
857                     break;
858
859                 case 'x':
860                 case 'X':
861                     xflag = 0;
862                     break;
863
864                 case 'q':
865                 case 'Q':
866                     xflag = 1;
867                     break;
868
869                 case 'd':
870                 case 'D':
871                     xflag = 2;
872                     break;
873
874                 case 'e':
875                 case 'E':
876                     return(1);
877
878                 case 'n':
879                 case 'N':
880                     pflag = 0;
881                     break;
882
883                 case 'p':
884                 case 'P':
885                     pflag = 1;
886                     break;
887
888                 case 'b':
889                 case 'B':
890                     bassav();
891                     return(0);
892
893                 case 'g':
894                 case 'G':
895                     gblsav();
896                     return(0);
897
898                 case 'k':
899                 case 'K':
900                     addpath();
901                     return(0);
902
903                 case 'l':
904                 case 'L':
905                     addlib();
906                     return(0);
907
908                 case 'a':
909                     iramsav();
910                     return(0);
911
912                 case 'v':
913                 case 'V':
914                     xramsav();
915                     return(0);
916
917                 case 'w':
918                 case 'W':
919                     codesav();
920                     return(0);
921
922                 case 'z':
923                 case 'Z':
924                         dflag = 1;
925                     return(0);
926                 default:
927                     fprintf(stderr, "Invalid option\n");
928                     lkexit(1);
929                 }
930             }
931             if ( c == ';')
932                 return(0);
933         } else
934         if (ctype[c] & ILL) {
935             fprintf(stderr, "Invalid input");
936             lkexit(1);
937         } else {
938             if (linkp == NULL) {
939                 linkp = (struct lfile *)
940                     new (sizeof (struct lfile));
941                 lfp = linkp;
942             } else {
943                 lfp->f_flp = (struct lfile *)
944                         new (sizeof (struct lfile));
945                 lfp = lfp->f_flp;
946             }
947             getfid(fid, c);
948             lfp->f_idp = (char *) new (strlen(fid)+1);
949             strcpy(lfp->f_idp, fid);
950             lfp->f_type = F_REL;
951         }
952     }
953     return(0);
954 }
955
956 /*)Function VOID    bassav()
957  *
958  *  The function bassav() creates a linked structure containing
959  *  the base address strings input to the linker.
960  *
961  *  local variables:
962  *      none
963  *
964  *  global variables:
965  *      base    *basep      The pointer to the first
966  *                          base structure
967  *      base    *bsp        Pointer to the current
968  *                          base structure
969  *      char    *ip         pointer into the REL file
970  *                          text line in ib[]
971  *
972  *   functions called:
973  *      char    getnb()     lklex.c
974  *      VOID *  new()       lksym.c
975  *      int     strlen()    c_library
976  *      char *  strcpy()    c_library
977  *      VOID    unget()     lklex.c
978  *
979  *  side effects:
980  *      The basep structure is created.
981  */
982
983 VOID
984 bassav()
985 {
986     if (basep == NULL) {
987         basep = (struct base *)
988             new (sizeof (struct base));
989         bsp = basep;
990     } else {
991         bsp->b_base = (struct base *)
992                 new (sizeof (struct base));
993         bsp = bsp->b_base;
994     }
995     unget(getnb());
996     bsp->b_strp = (char *) new (strlen(ip)+1);
997     strcpy(bsp->b_strp, ip);
998 }
999
1000 /*)Function VOID    setbas()
1001  *
1002  *  The function setbas() scans the base address lines in the
1003  *  basep structure, evaluates the arguments, and sets beginning
1004  *  address of the specified areas.
1005  *
1006  *  local variables:
1007  *      int     v           expression value
1008  *      char    id[]        base id string
1009  *
1010  *  global variables:
1011  *      area    *ap         Pointer to the current
1012  *                          area structure
1013  *      area    *areap      The pointer to the first
1014  *                          area structure of a linked list
1015  *      base    *basep      The pointer to the first
1016  *                          base structure
1017  *      base    *bsp        Pointer to the current
1018  *                          base structure
1019  *      char    *ip         pointer into the REL file
1020  *                          text line in ib[]
1021  *      int     lkerr       error flag
1022  *
1023  *   functions called:
1024  *      Addr_T  expr()      lkeval.c
1025  *      int     fprintf()   c_library
1026  *      VOID    getid()     lklex.c
1027  *      char    getnb()     lklex.c
1028  *      int     symeq()     lksym.c
1029  *
1030  *  side effects:
1031  *      The base address of an area is set.
1032  */
1033
1034 VOID
1035 setbas()
1036 {
1037     register int v;
1038     char id[NCPS];
1039
1040     bsp = basep;
1041     while (bsp) {
1042         ip = bsp->b_strp;
1043         getid(id, -1);
1044         if (getnb() == '=') {
1045             v = expr(0);
1046             for (ap = areap; ap != NULL; ap = ap->a_ap) {
1047                 if (symeq(id, ap->a_id))
1048                     break;
1049             }
1050             if (ap == NULL) {
1051                 fprintf(stderr,
1052                 "ASlink-Warning-No definition of area %s\n", id);
1053                 lkerr++;
1054             } else {
1055                 ap->a_addr = v;
1056                 ap->a_type = 1; /* JLH: value set */
1057             }
1058         } else {
1059             fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1060             lkerr++;
1061         }
1062         bsp = bsp->b_base;
1063     }
1064 }
1065
1066 /*)Function VOID    gblsav()
1067  *
1068  *  The function gblsav() creates a linked structure containing
1069  *  the global variable strings input to the linker.
1070  *
1071  *  local variable:
1072  *      none
1073  *
1074  *  global variables:
1075  *      globl   *globlp     The pointer to the first
1076  *                          globl structure
1077  *      globl   *gsp        Pointer to the current
1078  *                          globl structure
1079  *      char    *ip         pointer into the REL file
1080  *                          text line in ib[]
1081  *      int     lkerr       error flag
1082  *
1083  *  functions called:
1084  *      char    getnb()     lklex.c
1085  *      VOID *  new()       lksym.c
1086  *      int     strlen()    c_library
1087  *      char *  strcpy()    c_library
1088  *      VOID    unget()     lklex.c
1089  *
1090  *  side effects:
1091  *      The globlp structure is created.
1092  */
1093
1094 VOID
1095 gblsav()
1096 {
1097     if (globlp == NULL) {
1098         globlp = (struct globl *)
1099             new (sizeof (struct globl));
1100         gsp = globlp;
1101     } else {
1102         gsp->g_globl = (struct globl *)
1103                 new (sizeof (struct globl));
1104         gsp = gsp->g_globl;
1105     }
1106     unget(getnb());
1107     gsp->g_strp = (char *) new (strlen(ip)+1);
1108     strcpy(gsp->g_strp, ip);
1109 }
1110
1111 /*)Function VOID    setgbl()
1112  *
1113  *  The function setgbl() scans the global variable lines in the
1114  *  globlp structure, evaluates the arguments, and sets a variable
1115  *  to this value.
1116  *
1117  *  local variables:
1118  *      int     v           expression value
1119  *      char    id[]        base id string
1120  *      sym *   sp          pointer to a symbol structure
1121  *
1122  *  global variables:
1123  *      char    *ip         pointer into the REL file
1124  *                          text line in ib[]
1125  *      globl   *globlp     The pointer to the first
1126  *                          globl structure
1127  *      globl   *gsp        Pointer to the current
1128  *                          globl structure
1129  *      FILE *  stderr      c_library
1130  *      int     lkerr       error flag
1131  *
1132  *   functions called:
1133  *      Addr_T  expr()      lkeval.c
1134  *      int     fprintf()   c_library
1135  *      VOID    getid()     lklex.c
1136  *      char    getnb()     lklex.c
1137  *      sym *   lkpsym()    lksym.c
1138  *
1139  *  side effects:
1140  *      The value of a variable is set.
1141  */
1142
1143 VOID
1144 setgbl()
1145 {
1146     register int v;
1147     register struct sym *sp;
1148     char id[NCPS];
1149
1150     gsp = globlp;
1151     while (gsp) {
1152         ip = gsp->g_strp;
1153         getid(id, -1);
1154         if (getnb() == '=') {
1155             v = expr(0);
1156             sp = lkpsym(id, 0);
1157             if (sp == NULL) {
1158                 fprintf(stderr, "No definition of symbol %s\n", id);
1159                 lkerr++;
1160             } else {
1161                 if (sp->s_flag & S_DEF) {
1162                     fprintf(stderr, "Redefinition of symbol %s\n", id);
1163                     lkerr++;
1164                     sp->s_axp = NULL;
1165                 }
1166                 sp->s_addr = v;
1167                 sp->s_type |= S_DEF;
1168             }
1169         } else {
1170             fprintf(stderr, "No '=' in global expression");
1171             lkerr++;
1172         }
1173         gsp = gsp->g_globl;
1174     }
1175 }
1176
1177 /*)Function FILE *  afile(fn, ft, wf)
1178  *
1179  *      char *  fn      file specification string
1180  *      char *  ft      file type string
1181  *      int     wf      read(0)/write(1) flag
1182  *
1183  *  The function afile() opens a file for reading or writing.
1184  *      (1) If the file type specification string ft
1185  *          is not NULL then a file specification is
1186  *          constructed with the file path\name in fn
1187  *          and the extension in ft.
1188  *      (2) If the file type specification string ft
1189  *          is NULL then the file specification is
1190  *          constructed from fn.  If fn does not have
1191  *          a file type then the default .rel file
1192  *          type is appended to the file specification.
1193  *
1194  *  afile() returns a file handle for the opened file or aborts
1195  *  the assembler on an open error.
1196  *
1197  *  local variables:
1198  *      char    fb[]        constructed file specification string
1199  *      FILE *  fp          filehandle for opened file
1200  *
1201  *  global variables:
1202  *      int     lkerr       error flag
1203  *
1204  *  functions called:
1205  *      FILE *  fopen()     c_library
1206  *      int     fprintf()   c_library
1207  *
1208  *  side effects:
1209  *      File is opened for read or write.
1210  */
1211
1212 FILE *
1213 afile(char *fn, char *ft, int wf)
1214 {
1215     FILE *fp;
1216     char fb[PATH_MAX];
1217     char *omode;
1218     int i;
1219
1220     switch (wf) {
1221         case 0: omode = "r"; break;
1222         case 1: omode = "w"; break;
1223         case 2: omode = "a"; break;
1224         case 3: omode = "rb"; break;
1225         case 4: omode = "wb"; break;
1226         case 5: omode = "ab"; break;
1227         default: omode = "r"; break;
1228     }
1229
1230     /*Look backward the name path and get rid of the extension, if any*/
1231     i=strlen(fn);
1232     for(; (fn[i]!=FSEPX)&&(fn[i]!=LKDIRSEP)&&(fn[i]!='/')&&(i>0); i--);
1233     if( (fn[i]==FSEPX) && strcmp(ft, "lnk") )
1234     {
1235         strncpy(fb, fn, i);
1236         fb[i]=0;
1237     }
1238     else
1239     {
1240         strcpy(fb, fn);
1241     }
1242
1243     /*Add the extension*/
1244     if (fb[i] != FSEPX)
1245     {
1246         fb[i] = FSEPX;
1247         fb[i+1] = 0;
1248         strcat(fb, strlen(ft)?ft:LKOBJEXT);
1249     }
1250
1251     fp = fopen(fb, omode);
1252     if (fp==NULL)
1253     {
1254         if (strcmp(ft,"adb"))/*Do not complain for optional adb files*/
1255         {
1256             fprintf(stderr, "%s: cannot %s.\n", fb, (wf%3)==1?"create":"open");
1257             lkerr++;
1258         }
1259     }
1260     return (fp);
1261 }
1262
1263 /*)Function VOID    iramsav()
1264  *
1265  *  The function iramsav() stores the size of the chip's internal RAM.
1266  *  This is used after linking to check that variable assignment to this
1267  *  dataspace didn't overflow into adjoining segments.  Variables in the
1268  *  DSEG, OSEG, and ISEG are assigned to this dataspace.
1269  *
1270  *  local variables:
1271  *      none
1272  *
1273  *  global variables:
1274  *      char    *ip         pointer into the REL file
1275  *                          text line in ib[]
1276  *      unsigned int        size of chip's internal
1277  *          iram_size       RAM segment
1278  *
1279  *   functions called:
1280  *      char    getnb()     lklex.c
1281  *      VOID    unget()     lklex.c
1282  *      Addr_T  expr()      lkeval.c
1283  *
1284  *  side effects:
1285  *      The iram_size may be modified.
1286  */
1287
1288 VOID
1289 iramsav()
1290 {
1291   unget(getnb());
1292   if (ip && *ip)
1293     iram_size = expr(0);    /* evaluate size expression */
1294   else
1295     iram_size = 128;        /* Default is 128 (0x80) bytes */
1296   if ((iram_size<=0) || (iram_size>256))
1297     iram_size = 128;        /* Default is 128 (0x80) bytes */
1298 }
1299
1300 /*Similar to iramsav but for xram memory*/
1301 VOID
1302 xramsav()
1303 {
1304   unget(getnb());
1305   if (ip && *ip)
1306     xram_size = expr(0);    /* evaluate size expression */
1307   else
1308     xram_size = rflag?0x1000000:0x10000;
1309 }
1310
1311 /*Similar to iramsav but for code memory*/
1312 VOID
1313 codesav()
1314 {
1315   unget(getnb());
1316   if (ip && *ip)
1317     code_size = expr(0);    /* evaluate size expression */
1318   else
1319     code_size = rflag?0x1000000:0x10000;
1320 }
1321
1322
1323 /*)Function VOID    iramcheck()
1324  *
1325  *  The function iramcheck() is used at the end of linking to check that
1326  *  the internal RAM area wasn't overflowed by too many variable
1327  *  assignments.  Variables in the DSEG, ISEG, and OSEG are assigned to
1328  *  the chip's internal RAM.
1329  *
1330  *  local variables:
1331  *      none
1332  *
1333  *  global variables:
1334  *      unsigned int        size of chip's internal
1335  *          iram_size       RAM segment
1336  *      struct area         linked list of memory
1337  *          *areap          areas
1338  *
1339  *   functions called:
1340  *
1341  *  side effects:
1342  */
1343
1344 VOID
1345 iramcheck()
1346 {
1347   register unsigned int last_addr;
1348   register struct area *ap;
1349
1350   for (ap = areap; ap; ap=ap->a_ap) {
1351     if ((ap->a_size != 0) &&
1352         (!strcmp(ap->a_id, "DSEG") ||
1353          !strcmp(ap->a_id, "OSEG") ||
1354          !strcmp(ap->a_id, "ISEG")
1355         )
1356        )
1357     {
1358       last_addr = ap->a_addr + ap->a_size - 1;
1359       if (last_addr >= iram_size)
1360         fprintf(stderr,
1361           "\nWARNING! Segment %s extends past the end\n"
1362           "         of internal RAM.  Check map file.\n",
1363           ap->a_id);
1364     }
1365   }
1366 }
1367
1368 char *usetxt[] = {
1369     "Startup:",
1370     "  -c   Command line input",
1371     "  -f   file[LNK] File input",
1372     "  -p   Prompt and echo of file[LNK] to stdout (default)",
1373     "  -n   No echo of file[LNK] to stdout",
1374 /*  "Usage: [-Options] file [file ...]", */
1375     "Libraries:",
1376     "  -k   Library path specification, one per -k",
1377     "  -l   Library file specification, one per -l",
1378     "Relocation:",
1379     "  -b   area base address = expression",
1380     "  -g   global symbol = expression",
1381     "Map format:",
1382     "  -m   Map output generated as file[MAP]",
1383     "  -x   Hexadecimal (default),  -d  Decimal,  -q  Octal",
1384     "Output:",
1385     "  -i   Intel Hex as file[IHX]",
1386     "  -s   Motorola S19 as file[S19]",
1387     "  -j   Produce NoICE debug as file[NOI]",
1388     "  -z   Produce SDCdb debug as file[cdb]",
1389 /*  "List:", */
1390     "  -u   Update listing file(s) with link data as file(s)[.RST]",
1391     "Miscellaneous:\n"
1392     "  -a   [iram-size] Check for internal RAM overflow",
1393     "  -v   [xram-size] Check for external RAM overflow",
1394     "  -w   [code-size] Check for code overflow",
1395     "  -y   Generate memory usage summary file[mem]",
1396     "  -Y   Pack internal ram",
1397     "  -A   [stack-size] Allocate space for stack",
1398     "End:",
1399     "  -e   or null line terminates input",
1400     0
1401 };
1402
1403 /*)Function VOID    usage()
1404  *
1405  *  The function usage() outputs to the stderr device the
1406  *  assembler name and version and a list of valid assembler options.
1407  *
1408  *  local variables:
1409  *      char ** dp          pointer to an array of
1410  *                          text string pointers.
1411  *
1412  *  global variables:
1413  *      FILE *  stderr      c_library
1414  *
1415  *  functions called:
1416  *      int     fprintf()   c_library
1417  *
1418  *  side effects:
1419  *      none
1420  */
1421
1422 VOID
1423 usage()
1424 {
1425     register char   **dp;
1426
1427     fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1428     for (dp = usetxt; *dp; dp++)
1429         fprintf(stderr, "%s\n", *dp);
1430     lkexit(1);
1431 }
1432
1433 /*)Function VOID    copyfile()
1434  *
1435  *      FILE    *dest           destination file
1436  *      FILE    *src            source file
1437  *
1438  *      function will copy source file to destination file
1439  *
1440  *
1441  *  functions called:
1442  *      int     fgetc()         c_library
1443  *      int     fputc()         c_library
1444  *
1445  *  side effects:
1446  *      none
1447  */
1448 VOID copyfile (FILE *dest, FILE *src)
1449 {
1450     int ch;
1451
1452     while ((ch = fgetc(src)) != EOF) {
1453         fputc(ch,dest);
1454     }
1455 }