* as/link/aslink.h: added LKOBJEXT
[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 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 /*)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     return 0;
425 }
426
427 /*)Function VOID    lkexit(i)
428  *
429  *      int     i       exit code
430  *
431  *  The function lkexit() explicitly closes all open
432  *  files and then terminates the program.
433  *
434  *  local variables:
435  *      none
436  *
437  *  global variables:
438  *      FILE *  mfp     file handle for .map
439  *      FILE *  ofp     file handle for .ihx/.s19
440  *      FILE *  rfp     file hanlde for .rst
441  *      FILE *  sfp     file handle for .rel
442  *      FILE *  tfp     file handle for .lst
443  *
444  *  functions called:
445  *      int     fclose()    c_library
446  *      VOID    exit()      c_library
447  *
448  *  side effects:
449  *      All files closed. Program terminates.
450  */
451
452 VOID
453 lkexit(int i)
454 {
455     if (mfp != NULL) fclose(mfp);
456     if (jfp != NULL) fclose(jfp);
457     if (ofp != NULL) fclose(ofp);
458     if (rfp != NULL) fclose(rfp);
459     if (sfp != NULL) fclose(sfp);
460     if (tfp != NULL) fclose(tfp);
461     if (dfp != NULL) fclose(dfp);
462     /*if (dfp != NULL)
463         FILE *xfp = afile(linkp->f_idp,"cdb",1);
464         dfp = freopen("temp.cdb","r",dfp);
465         copyfile(xfp,dfp);
466         fclose(xfp);
467         fclose(dfp);
468         remove("temp.cdb");
469     }*/
470     exit(i);
471 }
472
473 /*)Function link_main()
474  *
475  *  The function link_main() evaluates the directives for each line of
476  *  text read from the .rel file(s).  The valid directives processed
477  *  are:
478  *      X, D, Q, H, M, A, S, T, R, and P.
479  *
480  *  local variables:
481  *      int     c           first non blank character of a line
482  *
483  *  global variables:
484  *      head    *headp      The pointer to the first
485  *                          head structure of a linked list
486  *      head    *hp         Pointer to the current
487  *                          head structure
488  *      int     pass        linker pass number
489  *      int     radix       current number conversion radix
490  *
491  *  functions called:
492  *      char    endline()   lklex.c
493  *      VOID    module()    lkhead.c
494  *      VOID    newarea()   lkarea.c
495  *      VOID    newhead()   lkhead.c
496  *      sym *   newsym()    lksym.c
497  *      VOID    reloc()     lkreloc.c
498  *
499  *  side effects:
500  *      Head, area, and symbol structures are created and
501  *      the radix is set as the .rel file(s) are read.
502  */
503
504 VOID
505 link_main()
506 {
507     register char c;
508
509     if ((c=endline()) == 0) { return; }
510     switch (c) {
511
512     case 'O': /*For some important sdcc options*/
513         if (pass == 0)
514         {
515             if(strlen(sdccopt)==0)
516             {
517                 strcpy(sdccopt, &ip[1]);
518                 strcpy(sdccopt_module, curr_module);
519             }
520             else
521             {
522                 if(strcmp(sdccopt, &ip[1])!=0)
523                 {
524                     fprintf(stderr,
525                     "?ASlink-Warning-Conflicting sdcc options:\n"
526                     "   \"%s\" in module \"%s\" and\n"
527                     "   \"%s\" in module \"%s\".\n",
528                     sdccopt, sdccopt_module, &ip[1], curr_module);
529                     lkerr++;
530                 }
531             }
532         }
533         break;
534
535     case 'X':
536         radix = 16;
537         break;
538
539     case 'D':
540         radix = 10;
541         break;
542
543     case 'Q':
544         radix = 8;
545         break;
546
547     case 'H':
548         if (pass == 0) {
549             newhead();
550         } else {
551             if (hp == 0) {
552                 hp = headp;
553             } else {
554                 hp = hp->h_hp;
555             }
556         }
557         sdp.s_area = NULL;
558         sdp.s_areax = NULL;
559         sdp.s_addr = 0;
560         break;
561
562     case 'M':
563         if (pass == 0)
564         {
565             strcpy(curr_module, &ip[1]);
566             module();
567         }
568         break;
569
570     case 'A':
571         if (pass == 0)
572             newarea();
573         if (sdp.s_area == NULL) {
574             sdp.s_area = areap;
575             sdp.s_areax = areap->a_axp;
576             sdp.s_addr = 0;
577         }
578         break;
579
580     case 'S':
581         if (pass == 0)
582             newsym();
583         break;
584
585     case 'T':
586     case 'R':
587     case 'P':
588         if (pass == 0)
589             break;
590         reloc(c);
591         break;
592
593     default:
594         break;
595     }
596     if (c == 'X' || c == 'D' || c == 'Q') {
597         if ((c = get()) == 'H') {
598             hilo = 1;
599         } else
600         if (c == 'L') {
601             hilo = 0;
602         }
603     }
604 }
605
606
607 /*)Function VOID    map()
608  *
609  *  The function map() opens the output map file and calls the various
610  *  routines to
611  *  (1) output the variables in each area,
612  *  (2) list the files processed with module names,
613  *  (3) list the libraries file processed,
614  *  (4) list base address definitions,
615  *  (5) list global variable definitions, and
616  *  (6) list any undefined variables.
617  *
618  *  local variables:
619  *      int     i           counter
620  *      head *  hdp         pointer to head structure
621  *      lbfile *lbfh        pointer to library file structure
622  *
623  *  global variables:
624  *      area    *ap         Pointer to the current
625  *                          area structure
626  *      area    *areap      The pointer to the first
627  *                          area structure of a linked list
628  *      base    *basep      The pointer to the first
629  *                          base structure
630  *      base    *bsp        Pointer to the current
631  *                          base structure
632  *      lfile   *filep      The pointer *filep points to the
633  *                          beginning of a linked list of
634  *                          lfile structures.
635  *      globl   *globlp     The pointer to the first
636  *                          globl structure
637  *      globl   *gsp        Pointer to the current
638  *                          globl structure
639  *      head    *headp      The pointer to the first
640  *                          head structure of a linked list
641  *      lbfile  *lbfhead    The pointer to the first
642  *                          lbfile structure of a linked list
643  *      lfile   *linkp      pointer to first lfile structure
644  *                          containing an input REL file
645  *                          specification
646  *      int     lop         current line number on page
647  *      FILE    *mfp        Map output file handle
648  *      int     page        current page number
649  *
650  *  functions called:
651  *      FILE *  afile()     lkmain.c
652  *      int     fprintf()   c_library
653  *      VOID    lkexit()    lkmain.c
654  *      VOID    lstarea()   lklist.c
655  *      VOID    newpag()    lklist.c
656  *      VOID    symdef()    lksym.c
657  *
658  *  side effects:
659  *      The map file is created.
660  */
661
662 VOID
663 map()
664 {
665     register int i;
666     register struct head *hdp;
667     register struct lbfile *lbfh;
668
669     /*
670      * Open Map File
671      */
672     mfp = afile(linkp->f_idp, "map", 1);
673     if (mfp == NULL) {
674         lkexit(1);
675     }
676
677     /*
678      * Output Map Area Lists
679      */
680     page = 0;
681     lop  = NLPP;
682     ap = areap;
683     while (ap) {
684         lstarea(ap);
685         ap = ap->a_ap;
686     }
687     /*
688      * List Linked Files
689      */
690     newpag(mfp);
691     fprintf(mfp, "\nFiles Linked      [ module(s) ]\n\n");
692     hdp = headp;
693     filep = linkp;
694     while (filep) {
695         fprintf(mfp, "%-16s", filep->f_idp);
696         i = 0;
697         while ((hdp != NULL) && (hdp->h_lfile == filep)) {
698             if (i % 5) {
699                 fprintf(mfp, ", %8.8s", hdp->m_id);
700             } else {
701                 if (i) {
702                 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
703                 } else {
704                 fprintf(mfp, "  [ %8.8s", hdp->m_id);
705                 }
706             }
707             hdp = hdp->h_hp;
708             i++;
709         }
710         if (i)
711             fprintf(mfp, " ]");
712         fprintf(mfp, "\n");
713         filep = filep->f_flp;
714     }
715     /*
716      * List Linked Libraries
717      */
718     if (lbfhead != NULL) {
719         fprintf(mfp,
720             "\nLibraries Linked            [   object  file   ]\n\n");
721         for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
722             fprintf(mfp, "%-32s    [ %16.16s ]\n",
723                 lbfh->libspc, lbfh->relfil);
724         }
725         fprintf(mfp, "\n");
726     }
727     /*
728      * List Base Address Definitions
729      */
730     if (basep) {
731         newpag(mfp);
732         fprintf(mfp, "\nUser Base Address Definitions\n\n");
733         bsp = basep;
734         while (bsp) {
735             fprintf(mfp, "%s\n", bsp->b_strp);
736             bsp = bsp->b_base;
737         }
738     }
739     /*
740      * List Global Definitions
741      */
742     if (globlp) {
743         newpag(mfp);
744         fprintf(mfp, "\nUser Global Definitions\n\n");
745         gsp = globlp;
746         while (gsp) {
747             fprintf(mfp, "%s\n", gsp->g_strp);
748             gsp = gsp->g_globl;
749         }
750     }
751     fprintf(mfp, "\n\f");
752     symdef(mfp);
753 }
754
755 /*)Function int parse()
756  *
757  *  The function parse() evaluates all command line or file input
758  *  linker directives and updates the appropriate variables.
759  *
760  *  local variables:
761  *      int     c           character value
762  *      char    fid[]       file id string
763  *
764  *  global variables:
765  *      char    ctype[]     array of character types, one per
766  *                          ASCII character
767  *      lfile   *lfp        pointer to current lfile structure
768  *                          being processed by parse()
769  *      lfile   *linkp      pointer to first lfile structure
770  *                          containing an input REL file
771  *                          specification
772  *      int     mflag       Map output flag
773  *      int     oflag       Output file type flag
774  *      int     pflag       print linker command file flag
775  *      FILE *  stderr      c_library
776  *      int     uflag       Relocated listing flag
777  *      int     xflag       Map file radix type flag
778  *
779  *  Functions called:
780  *      VOID    addlib()    lklibr.c
781  *      VOID    addpath()   lklibr.c
782  *      VOID    bassav()    lkmain.c
783  *      int     fprintf()   c_library
784  *      VOID    gblsav()    lkmain.c
785  *      VOID    getfid()    lklex.c
786  *      char    getnb()     lklex.c
787  *      VOID    lkexit()    lkmain.c
788  *      char *  strcpy()    c_library
789  *      int     strlen()    c_library
790  *
791  *  side effects:
792  *      Various linker flags are updated and the linked
793  *      structure lfile is created.
794  */
795
796 int
797 parse()
798 {
799     register int c;
800     char fid[NINPUT];
801
802     while ((c = getnb()) != 0) {
803         if ( c == ';')
804             return(0);
805         if ( c == '-') {
806             while (ctype[c=get()] & LETTER) {
807                 switch(c) {
808
809                 case 'i':
810                 case 'I':
811                     oflag = 1;
812                     break;
813
814                 case 's':
815                 case 'S':
816                     oflag = 2;
817                     break;
818
819                 case 'm':
820                 case 'M':
821                     ++mflag;
822                     break;
823
824                 case 'y': /*JCF: memory usage summary output*/
825                     ++sflag;
826                     break;
827
828                 case 'Y':
829                     unget(getnb());
830                     packflag=1;
831                     break;
832
833                 case 'A':
834                     unget(getnb());
835                     if (ip && *ip)
836                     {
837                         stacksize=expr(0);
838                         if(stacksize>256) stacksize=256;
839                         else if(stacksize<0) stacksize=0;
840                     }
841                     return(0);
842
843                 case 'j':
844                 case 'J':
845                     jflag = 1;
846                     break;
847
848                 case 'u':
849                 case 'U':
850                     uflag = 1;
851                     break;
852                 case 'r':
853                 case 'R':
854                     rflag = 1;
855                     break;
856                 case 'x':
857                 case 'X':
858                     xflag = 0;
859                     break;
860
861                 case 'q':
862                 case 'Q':
863                     xflag = 1;
864                     break;
865
866                 case 'd':
867                 case 'D':
868                     xflag = 2;
869                     break;
870
871                 case 'e':
872                 case 'E':
873                     return(1);
874
875                 case 'n':
876                 case 'N':
877                     pflag = 0;
878                     break;
879
880                 case 'p':
881                 case 'P':
882                     pflag = 1;
883                     break;
884
885                 case 'b':
886                 case 'B':
887                     bassav();
888                     return(0);
889
890                 case 'g':
891                 case 'G':
892                     gblsav();
893                     return(0);
894
895                 case 'k':
896                 case 'K':
897                     addpath();
898                     return(0);
899
900                 case 'l':
901                 case 'L':
902                     addlib();
903                     return(0);
904
905                 case 'a':
906                     iramsav();
907                     return(0);
908
909                 case 'v':
910                 case 'V':
911                     xramsav();
912                     return(0);
913
914                 case 'w':
915                 case 'W':
916                     codesav();
917                     return(0);
918
919                 case 'z':
920                 case 'Z':
921                         dflag = 1;
922                     return(0);
923                 default:
924                     fprintf(stderr, "Invalid option\n");
925                     lkexit(1);
926                 }
927             }
928             if ( c == ';')
929                 return(0);
930         } else
931                if (ctype[c] & ILL) {
932                        fprintf(stderr, "Invalid input");
933                        lkexit(1);
934                } else {
935             if (linkp == NULL) {
936                 linkp = (struct lfile *)
937                     new (sizeof (struct lfile));
938                 lfp = linkp;
939             } else {
940                 lfp->f_flp = (struct lfile *)
941                         new (sizeof (struct lfile));
942                 lfp = lfp->f_flp;
943             }
944             getfid(fid, c);
945             lfp->f_idp = (char *) new (strlen(fid)+1);
946             strcpy(lfp->f_idp, fid);
947             lfp->f_type = F_REL;
948         }
949     }
950     return(0);
951 }
952
953 /*)Function VOID    bassav()
954  *
955  *  The function bassav() creates a linked structure containing
956  *  the base address strings input to the linker.
957  *
958  *  local variables:
959  *      none
960  *
961  *  global variables:
962  *      base    *basep      The pointer to the first
963  *                          base structure
964  *      base    *bsp        Pointer to the current
965  *                          base structure
966  *      char    *ip         pointer into the REL file
967  *                          text line in ib[]
968  *
969  *   functions called:
970  *      char    getnb()     lklex.c
971  *      VOID *  new()       lksym.c
972  *      int     strlen()    c_library
973  *      char *  strcpy()    c_library
974  *      VOID    unget()     lklex.c
975  *
976  *  side effects:
977  *      The basep structure is created.
978  */
979
980 VOID
981 bassav()
982 {
983     if (basep == NULL) {
984         basep = (struct base *)
985             new (sizeof (struct base));
986         bsp = basep;
987     } else {
988         bsp->b_base = (struct base *)
989                 new (sizeof (struct base));
990         bsp = bsp->b_base;
991     }
992     unget(getnb());
993     bsp->b_strp = (char *) new (strlen(ip)+1);
994     strcpy(bsp->b_strp, ip);
995 }
996
997 /*)Function VOID    setbas()
998  *
999  *  The function setbas() scans the base address lines in the
1000  *  basep structure, evaluates the arguments, and sets beginning
1001  *  address of the specified areas.
1002  *
1003  *  local variables:
1004  *      int     v           expression value
1005  *      char    id[]        base id string
1006  *
1007  *  global variables:
1008  *      area    *ap         Pointer to the current
1009  *                          area structure
1010  *      area    *areap      The pointer to the first
1011  *                          area structure of a linked list
1012  *      base    *basep      The pointer to the first
1013  *                          base structure
1014  *      base    *bsp        Pointer to the current
1015  *                          base structure
1016  *      char    *ip         pointer into the REL file
1017  *                          text line in ib[]
1018  *      int     lkerr       error flag
1019  *
1020  *   functions called:
1021  *      Addr_T  expr()      lkeval.c
1022  *      int     fprintf()   c_library
1023  *      VOID    getid()     lklex.c
1024  *      char    getnb()     lklex.c
1025  *      int     symeq()     lksym.c
1026  *
1027  *  side effects:
1028  *      The base address of an area is set.
1029  */
1030
1031 VOID
1032 setbas()
1033 {
1034     register int v;
1035     char id[NCPS];
1036
1037     bsp = basep;
1038     while (bsp) {
1039         ip = bsp->b_strp;
1040         getid(id, -1);
1041         if (getnb() == '=') {
1042             v = expr(0);
1043             for (ap = areap; ap != NULL; ap = ap->a_ap) {
1044                 if (symeq(id, ap->a_id))
1045                     break;
1046             }
1047             if (ap == NULL) {
1048                 fprintf(stderr,
1049                 "ASlink-Warning-No definition of area %s\n", id);
1050                 lkerr++;
1051             } else {
1052                 ap->a_addr = v;
1053                 ap->a_type = 1; /* JLH: value set */
1054             }
1055         } else {
1056             fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1057             lkerr++;
1058         }
1059         bsp = bsp->b_base;
1060     }
1061 }
1062
1063 /*)Function VOID    gblsav()
1064  *
1065  *  The function gblsav() creates a linked structure containing
1066  *  the global variable strings input to the linker.
1067  *
1068  *  local variable:
1069  *      none
1070  *
1071  *  global variables:
1072  *      globl   *globlp     The pointer to the first
1073  *                          globl structure
1074  *      globl   *gsp        Pointer to the current
1075  *                          globl structure
1076  *      char    *ip         pointer into the REL file
1077  *                          text line in ib[]
1078  *      int     lkerr       error flag
1079  *
1080  *  functions called:
1081  *      char    getnb()     lklex.c
1082  *      VOID *  new()       lksym.c
1083  *      int     strlen()    c_library
1084  *      char *  strcpy()    c_library
1085  *      VOID    unget()     lklex.c
1086  *
1087  *  side effects:
1088  *      The globlp structure is created.
1089  */
1090
1091 VOID
1092 gblsav()
1093 {
1094     if (globlp == NULL) {
1095         globlp = (struct globl *)
1096             new (sizeof (struct globl));
1097         gsp = globlp;
1098     } else {
1099         gsp->g_globl = (struct globl *)
1100                 new (sizeof (struct globl));
1101         gsp = gsp->g_globl;
1102     }
1103     unget(getnb());
1104     gsp->g_strp = (char *) new (strlen(ip)+1);
1105     strcpy(gsp->g_strp, ip);
1106 }
1107
1108 /*)Function VOID    setgbl()
1109  *
1110  *  The function setgbl() scans the global variable lines in the
1111  *  globlp structure, evaluates the arguments, and sets a variable
1112  *  to this value.
1113  *
1114  *  local variables:
1115  *      int     v           expression value
1116  *      char    id[]        base id string
1117  *      sym *   sp          pointer to a symbol structure
1118  *
1119  *  global variables:
1120  *      char    *ip         pointer into the REL file
1121  *                          text line in ib[]
1122  *      globl   *globlp     The pointer to the first
1123  *                          globl structure
1124  *      globl   *gsp        Pointer to the current
1125  *                          globl structure
1126  *      FILE *  stderr      c_library
1127  *      int     lkerr       error flag
1128  *
1129  *   functions called:
1130  *      Addr_T  expr()      lkeval.c
1131  *      int     fprintf()   c_library
1132  *      VOID    getid()     lklex.c
1133  *      char    getnb()     lklex.c
1134  *      sym *   lkpsym()    lksym.c
1135  *
1136  *  side effects:
1137  *      The value of a variable is set.
1138  */
1139
1140 VOID
1141 setgbl()
1142 {
1143     register int v;
1144     register struct sym *sp;
1145     char id[NCPS];
1146
1147     gsp = globlp;
1148     while (gsp) {
1149         ip = gsp->g_strp;
1150         getid(id, -1);
1151         if (getnb() == '=') {
1152             v = expr(0);
1153             sp = lkpsym(id, 0);
1154             if (sp == NULL) {
1155                 fprintf(stderr,
1156                 "No definition of symbol %s\n", id);
1157                 lkerr++;
1158             } else {
1159                 if (sp->s_flag & S_DEF) {
1160                     fprintf(stderr,
1161                     "Redefinition of symbol %s\n", id);
1162                     lkerr++;
1163                     sp->s_axp = NULL;
1164                 }
1165                 sp->s_addr = v;
1166                 sp->s_type |= S_DEF;
1167             }
1168         } else {
1169             fprintf(stderr, "No '=' in global expression");
1170             lkerr++;
1171         }
1172         gsp = gsp->g_globl;
1173     }
1174 }
1175
1176 /*)Function FILE *  afile(fn,, ft, wf)
1177  *
1178  *      char *  fn      file specification string
1179  *      char *  ft      file type string
1180  *      int     wf      read(0)/write(1) flag
1181  *
1182  *  The function afile() opens a file for reading or writing.
1183  *      (1) If the file type specification string ft
1184  *          is not NULL then a file specification is
1185  *          constructed with the file path\name in fn
1186  *          and the extension in ft.
1187  *      (2) If the file type specification string ft
1188  *          is NULL then the file specification is
1189  *          constructed from fn.  If fn does not have
1190  *          a file type then the default .rel file
1191  *          type is appended to the file specification.
1192  *
1193  *  afile() returns a file handle for the opened file or aborts
1194  *  the assembler on an open error.
1195  *
1196  *  local variables:
1197  *      char    fb[]        constructed file specification string
1198  *      FILE *  fp          filehandle for opened file
1199  *
1200  *  global variables:
1201  *      int     lkerr       error flag
1202  *
1203  *  functions called:
1204  *      FILE *  fopen()     c_library
1205  *      int     fprintf()   c_library
1206  *
1207  *  side effects:
1208  *      File is opened for read or write.
1209  */
1210
1211 FILE *
1212 afile(char *fn, char *ft, int wf)
1213 {
1214     FILE *fp;
1215     char fb[PATH_MAX];
1216     char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1217     int i;
1218
1219     /*Look backward the name path and get rid of the extension, if any*/
1220     i=strlen(fn);
1221     for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>0); i--);
1222     if( (fn[i]=='.') && strcmp(ft, "lnk") )
1223     {
1224         strncpy(fb, fn, i);
1225         fb[i]=0;
1226     }
1227     else
1228     {
1229         strcpy(fb, fn);
1230     }
1231
1232     /*Add the extension*/
1233     if (fb[i] != '.')
1234     {
1235         strcat(fb, ".");
1236         strcat(fb, strlen(ft)?ft:"rel");
1237     }
1238
1239     fp = fopen(fb, omode);
1240     if (fp==NULL)
1241     {
1242         if (strcmp(ft,"adb"))/*Do not complaint for optional adb files*/
1243         {
1244             fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1245             lkerr++;
1246         }
1247     }
1248     return (fp);
1249 }
1250
1251 /*)Function VOID    iramsav()
1252  *
1253  *  The function iramsav() stores the size of the chip's internal RAM.
1254  *  This is used after linking to check that variable assignment to this
1255  *  dataspace didn't overflow into adjoining segments.  Variables in the
1256  *  DSEG, OSEG, and ISEG are assigned to this dataspace.
1257  *
1258  *  local variables:
1259  *      none
1260  *
1261  *  global variables:
1262  *      char    *ip         pointer into the REL file
1263  *                          text line in ib[]
1264  *      unsigned int        size of chip's internal
1265  *          iram_size       RAM segment
1266  *
1267  *   functions called:
1268  *      char    getnb()     lklex.c
1269  *      VOID    unget()     lklex.c
1270  *      Addr_T  expr()      lkeval.c
1271  *
1272  *  side effects:
1273  *      The iram_size may be modified.
1274  */
1275
1276 VOID
1277 iramsav()
1278 {
1279   unget(getnb());
1280   if (ip && *ip)
1281     iram_size = expr(0);    /* evaluate size expression */
1282   else
1283     iram_size = 128;        /* Default is 128 (0x80) bytes */
1284   if ((iram_size<=0) || (iram_size>256))
1285     iram_size = 128;        /* Default is 128 (0x80) bytes */
1286 }
1287
1288 /*Similar to iramsav but for xram memory*/
1289 VOID
1290 xramsav()
1291 {
1292   unget(getnb());
1293   if (ip && *ip)
1294     xram_size = expr(0);    /* evaluate size expression */
1295   else
1296     xram_size = rflag?0x1000000:0x10000;
1297 }
1298
1299 /*Similar to iramsav but for code memory*/
1300 VOID
1301 codesav()
1302 {
1303   unget(getnb());
1304   if (ip && *ip)
1305     code_size = expr(0);    /* evaluate size expression */
1306   else
1307     code_size = rflag?0x1000000:0x10000;
1308 }
1309
1310
1311 /*)Function VOID    iramcheck()
1312  *
1313  *  The function iramcheck() is used at the end of linking to check that
1314  *  the internal RAM area wasn't overflowed by too many variable
1315  *  assignments.  Variables in the DSEG, ISEG, and OSEG are assigned to
1316  *  the chip's internal RAM.
1317  *
1318  *  local variables:
1319  *      none
1320  *
1321  *  global variables:
1322  *      unsigned int        size of chip's internal
1323  *          iram_size       RAM segment
1324  *      struct area         linked list of memory
1325  *          *areap          areas
1326  *
1327  *   functions called:
1328  *
1329  *  side effects:
1330  */
1331
1332 VOID
1333 iramcheck()
1334 {
1335   register unsigned int last_addr;
1336   register struct area *ap;
1337
1338   for (ap = areap; ap; ap=ap->a_ap) {
1339     if ((ap->a_size != 0) &&
1340         (!strcmp(ap->a_id, "DSEG") ||
1341          !strcmp(ap->a_id, "OSEG") ||
1342          !strcmp(ap->a_id, "ISEG")
1343         )
1344        )
1345     {
1346       last_addr = ap->a_addr + ap->a_size - 1;
1347       if (last_addr >= iram_size)
1348         fprintf(stderr,
1349           "\nWARNING! Segment %s extends past the end\n"
1350           "         of internal RAM.  Check map file.\n",
1351           ap->a_id);
1352     }
1353   }
1354 }
1355
1356 char *usetxt[] = {
1357     "Startup:",
1358     "  -c   Command line input",
1359     "  -f   file[LNK] File input",
1360     "  -p   Prompt and echo of file[LNK] to stdout (default)",
1361     "  -n   No echo of file[LNK] to stdout",
1362 /*  "Usage: [-Options] file [file ...]", */
1363     "Libraries:",
1364     "  -k   Library path specification, one per -k",
1365     "  -l   Library file specification, one per -l",
1366     "Relocation:",
1367     "  -b   area base address = expression",
1368     "  -g   global symbol = expression",
1369     "Map format:",
1370     "  -m   Map output generated as file[MAP]",
1371     "  -x   Hexadecimal (default),  -d  Decimal,  -q  Octal",
1372     "Output:",
1373     "  -i   Intel Hex as file[IHX]",
1374     "  -s   Motorola S19 as file[S19]",
1375     "  -j   Produce NoICE debug as file[NOI]",
1376     "  -z   Produce SDCdb debug as file[cdb]",
1377 /*  "List:", */
1378     "  -u   Update listing file(s) with link data as file(s)[.RST]",
1379     "Miscellaneous:\n"
1380     "  -a   [iram-size] Check for internal RAM overflow",
1381     "  -v   [xram-size] Check for external RAM overflow",
1382     "  -w   [code-size] Check for code overflow",
1383     "  -y   Generate memory usage summary file[mem]",
1384     "  -Y   Pack internal ram",
1385     "  -A   [stack-size] Allocate space for stack",
1386     "End:",
1387     "  -e   or null line terminates input",
1388     0
1389 };
1390
1391 /*)Function VOID    usage()
1392  *
1393  *  The function usage() outputs to the stderr device the
1394  *  assembler name and version and a list of valid assembler options.
1395  *
1396  *  local variables:
1397  *      char ** dp          pointer to an array of
1398  *                          text string pointers.
1399  *
1400  *  global variables:
1401  *      FILE *  stderr      c_library
1402  *
1403  *  functions called:
1404  *      int     fprintf()   c_library
1405  *
1406  *  side effects:
1407  *      none
1408  */
1409
1410 VOID
1411 usage()
1412 {
1413     register char   **dp;
1414
1415     fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1416     for (dp = usetxt; *dp; dp++)
1417         fprintf(stderr, "%s\n", *dp);
1418     lkexit(1);
1419 }
1420
1421 /*)Function VOID    copyfile()
1422  *
1423  *      FILE    *dest           destination file
1424  *      FILE    *src            source file
1425  *
1426  *      function will copy source file to destination file
1427  *
1428  *
1429  *  functions called:
1430  *      int     fgetc()         c_library
1431  *      int     fputc()         c_library
1432  *
1433  *  side effects:
1434  *      none
1435  */
1436 VOID copyfile (dest,src)
1437 FILE *src,*dest ;
1438 {
1439     int ch;
1440
1441     while ((ch = fgetc(src)) != EOF) {
1442         fputc(ch,dest);
1443     }
1444 }