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