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