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