* link/z80/lkmain.c (afile): allow periods in directory names
[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
111     if(packflag)
112     {
113             for (j=0; rel2[j][0]!=0; j++)
114             {
115                     ip=rel2[j];
116                     link_main();
117             }
118     }
119     else
120     {
121             for (j=0; rel[j][0]!=0; j++)
122             {
123                     ip=rel[j];
124                     link_main();
125             }
126     }
127         
128         /*Set the start address of the default areas:*/
129         for(ap=areap; ap; ap=ap->a_ap)
130         {
131                 /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr=0x00; ap->a_type=1; }
132                 else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr=0x08; ap->a_type=1; }
133                 else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; }
134                 else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; }
135                 else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; }
136                 else if (!strcmp(ap->a_id, "SSEG"))
137         {
138             if(stacksize) ap->a_axp->a_size=stacksize;
139         }
140         }
141 }
142
143 /*)Function     VOID    main(argc,argv)
144  *
145  *              int     argc            number of command line arguments + 1
146  *              char *  argv[]          array of pointers to the command line
147  *                                      arguments
148  *
149  *      The function main() evaluates the command line arguments to
150  *      determine if the linker parameters are to input through 'stdin'
151  *      or read from a command file.  The functiond getline() and parse()
152  *      are to input and evaluate the linker parameters.  The linking process
153  *      proceeds by making the first pass through each .rel file in the order
154  *      presented to the linker.  At the end of the first pass the setbase(),
155  *      lnkarea(), setgbl(), and symdef() functions are called to evaluate
156  *      the base address terms, link all areas, define global variables,
157  *      and look for undefined symbols.  Following these routines a linker
158  *      map file may be produced and the linker output files may be opened.
159  *      The second pass through the .rel files will output the linked data
160  *      in one of the four supported formats.
161  *
162  *      local variables:
163  *              char *  p               pointer to an argument string
164  *              int     c               character from argument string
165  *              int     i               loop counter
166  *
167  *      global variables:
168  *                                              text line in ib[]
169  *              lfile   *cfp            The pointer *cfp points to the
170  *                                              current lfile structure
171  *              char    ctype[]         array of character types, one per
172  *                                              ASCII character
173  *              lfile   *filep                  The pointer *filep points to the
174  *                                              beginning of a linked list of
175  *                                              lfile structures.
176  *              head    *hp             Pointer to the current
177  *                                              head structure
178  *              char    ib[NINPUT]      .rel file text line
179  *              char    *ip             pointer into the .rel file
180  *              lfile   *linkp          pointer to first lfile structure
181  *                                              containing an input .rel file
182  *                                              specification
183  *              int     lkerr           error flag
184  *              int     mflag           Map output flag
185  *              int     oflag           Output file type flag
186  *              FILE    *ofp            Output file handle
187  *                                              for word formats
188  *              FILE    *ofph           Output file handle
189  *                                              for high byte format
190  *              FILE    *ofpl           Output file handle
191  *                                              for low byte format
192  *              int     pass            linker pass number
193  *              int     pflag           print linker command file flag
194  *              int     radix           current number conversion radix
195  *              FILE    *sfp            The file handle sfp points to the
196  *                                              currently open file
197  *              lfile   *startp         asmlnk startup file structure
198  *              FILE *  stdin           c_library
199  *              FILE *  stdout          c_library
200  *
201  *      functions called:
202  *              FILE *  afile()         lkmain.c
203  *              int     fclose()        c_library
204  *              int     fprintf()       c_library
205  *              int     getline()       lklex.c
206  *              VOID    library()       lklibr.c
207  *              VOID    link_main()     lkmain.c
208  *              VOID    lkexit()        lkmain.c
209  *              VOID    lnkarea()       lkarea.c
210  *              VOID    map()           lkmain.c
211  *              VOID    new()           lksym.c
212  *              int     parse()         lkmain.c
213  *              VOID    reloc()         lkreloc.c
214  *              VOID    search()        lklibr.c
215  *              VOID    setbas()        lkmain.c
216  *              VOID    setgbl()        lkmain.c
217  *              VOID    symdef()        lksym.c
218  *              VOID    usage()         lkmain.c
219  *
220  *      side effects:
221  *              Completion of main() completes the linking process
222  *              and may produce a map file (.map) and/or a linked
223  *              data files (.ihx or .s19) and/or one or more
224  *              relocated listing files (.rst).
225  */
226
227 int
228 main(argc, argv)
229 char *argv[];
230 {
231         register char *p;
232         register int c, i;
233
234 #ifdef WIN32T
235     Timer(0, "");
236 #endif
237
238         startp = (struct lfile *) new (sizeof (struct lfile));
239
240         pflag = 1;
241         for (i=1; i<argc; ++i) {
242                 p = argv[i];
243                 if (*p == '-') {
244                         while (ctype[c = *(++p)] & LETTER) {
245                                 switch(c) {
246
247                                 case 'c':
248                                 case 'C':
249                                         startp->f_type = F_STD;
250                                         break;
251
252                                 case 'f':
253                                 case 'F':
254                                         startp->f_type = F_LNK;
255                                         break;
256         
257                                 case 'n':
258                                 case 'N':
259                                         pflag = 0;
260                                         break;
261
262                                 case 'p':
263                                 case 'P':
264                                         pflag = 1;
265                                         break;
266
267                                 default:
268                                         usage();
269                                 }
270                         }
271                 } else {
272                         if (startp->f_type == F_LNK) {
273                                 startp->f_idp = p;
274                         }
275                 }
276         }
277        if (startp->f_type == 0)
278                 usage();
279         if (startp->f_type == F_LNK && startp->f_idp == NULL)
280                 usage();
281
282         cfp = NULL;
283         sfp = NULL;
284         filep = startp;
285         while (1) {
286                 ip = ib;
287                 if (getline() == 0)
288                         break;
289                 if (pflag && sfp != stdin)
290                         fprintf(stdout, "%s\n", ip);
291                if (*ip == '\0' || parse())
292                         break;
293         }
294
295         if (sfp) {
296             fclose(sfp);
297             sfp = NULL;
298         }
299
300         if (linkp == NULL)
301                 usage();
302
303         syminit();
304         
305         if (dflag){
306             //dfp = afile("temp", "cdb", 1);
307                 SaveLinkedFilePath(linkp->f_idp); //Must be the first one... 
308                 dfp = afile(linkp->f_idp,"cdb",1); //JCF: Nov 30, 2002
309             if (dfp == NULL) 
310                 lkexit(1);
311         }
312
313         for (pass=0; pass<2; ++pass) {
314                 cfp = NULL;
315                 sfp = NULL;
316                 filep = linkp;
317                 hp = NULL;
318                 radix = 10;
319                 
320                 Areas51(); /*JCF: Create the default 8051 areas in the right order*/
321
322                 while (getline()) {
323                         ip = ib;
324
325                         /* pass any "magic comments" to NoICE output */
326                         if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
327                                 fprintf( jfp, "%s\n", &ip[2] );
328                         }
329                         link_main();
330                 }
331                 if (pass == 0) {
332                         /*
333                          * Search libraries for global symbols
334                          */
335                         search();
336                         /*
337                          * Set area base addresses.
338                          */
339                         setbas();
340                         /*
341                          * Link all area addresses.
342                          */
343                         if(!packflag)
344                 lnkarea();
345             else
346                 lnkarea2();
347                         /*
348                          * Process global definitions.
349                          */
350                         setgbl();
351                         /*
352                          * Check for undefined globals.
353                          */
354                         symdef(stderr);
355
356                         /* Open NoICE output file if requested */
357                         if (jflag) {
358                                 jfp = afile(linkp->f_idp, "NOI", 1);
359                                 if (jfp == NULL) {
360                                         lkexit(1);
361                                 }
362                         }
363
364                         /*
365                          * Output Link Map if requested,
366                          * or if NoICE output requested (since NoICE
367                          * file is generated in part by map() processing)
368                          */
369                         if (mflag || jflag)
370                                 map();
371
372                         if (sflag) /*JCF: memory usage summary output*/
373             {
374                 if(!packflag)
375                 {
376                                     if(summary(areap)) lkexit(1);
377                 }
378                 else
379                 {
380                                     if(summary2(areap)) lkexit(1);
381                 }
382             }
383
384                         if ((iram_size) && (!packflag))
385                                 iramcheck();
386
387                         /*
388                          * Open output file
389                          */
390                         if (oflag == 1) {
391                                 ofp = afile(linkp->f_idp, "ihx", 1);
392                                 if (ofp == NULL) {
393                                         lkexit(1);
394                                 }
395                                 /* include NoICE command to load hex file */
396                                 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
397
398                         } else
399                         if (oflag == 2) {
400                                 ofp = afile(linkp->f_idp, "S19", 1);
401                                 if (ofp == NULL) {
402                                         lkexit(1);
403                                 }
404                                 /* include NoICE command to load hex file */
405                                 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
406                         }
407                 } else {
408                         /*
409                          * Link in library files
410                          */
411                         library();
412                         reloc('E');
413                 }
414         }
415         //JCF:
416         CreateAOMF51();
417
418 #ifdef WIN32T
419     Timer(1, "Linker execution time");
420 #endif
421
422         lkexit(lkerr);
423         return 0;
424 }
425
426 /*)Function     VOID    lkexit(i)
427  *
428  *                      int     i       exit code
429  *
430  *      The function lkexit() explicitly closes all open
431  *      files and then terminates the program.
432  *
433  *      local variables:
434  *              none
435  *
436  *      global variables:
437  *              FILE *  mfp             file handle for .map
438  *              FILE *  ofp             file handle for .ihx/.s19
439  *              FILE *  rfp             file hanlde for .rst
440  *              FILE *  sfp             file handle for .rel
441  *              FILE *  tfp             file handle for .lst
442  *
443  *      functions called:
444  *              int     fclose()        c_library
445  *              VOID    exit()          c_library
446  *
447  *      side effects:
448  *              All files closed. Program terminates.
449  */
450
451 VOID
452 lkexit(i)
453 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             unlink("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 int 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 hte
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 hte
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(fn, ft, wf)
1213 char *fn;
1214 char *ft;
1215 {
1216         FILE *fp;
1217         char fb[PATH_MAX];
1218         char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1219         int i;
1220
1221         /*Look backward the name path and get rid of the extension, if any*/
1222         i=strlen(fn);
1223         for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>=0); i--);
1224         if( (fn[i]=='.') && 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] != '.')
1236         {
1237                 strcat(fb, ".");
1238                 strcat(fb, strlen(ft)?ft:"rel");
1239         }
1240         
1241         fp = fopen(fb, omode);
1242         if (fp==NULL)
1243         {
1244             if (strcmp(ft,"adb"))/*Do not complaint for optional adb files*/
1245                 {
1246                         fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1247                         lkerr++;
1248             }
1249         }
1250         return (fp);
1251 }
1252
1253 /*)Function     VOID    iramsav()
1254  *
1255  *      The function iramsav() stores the size of the chip's internal RAM.
1256  *      This is used after linking to check that variable assignment to this
1257  *      dataspace didn't overflow into adjoining segments.  Variables in the
1258  *      DSEG, OSEG, and ISEG are assigned to this dataspace.
1259  *
1260  *      local variables:
1261  *              none
1262  *
1263  *      global variables:
1264  *              char    *ip             pointer into the REL file
1265  *                                              text line in ib[]
1266  *              unsigned int            size of chip's internal
1267  *                      iram_size               RAM segment
1268  *
1269  *       functions called:
1270  *              char    getnb()         lklex.c
1271  *              VOID    unget()         lklex.c
1272  *              Addr_T  expr()          lkeval.c
1273  *
1274  *      side effects:
1275  *              The iram_size may be modified.
1276  */
1277
1278 VOID
1279 iramsav()
1280 {
1281   unget(getnb());
1282   if (ip && *ip)
1283     //iram_size = atoi(ip);
1284     iram_size = expr(0);        /* evaluate size expression */
1285   else
1286     iram_size = 128;            /* Default is 128 (0x80) bytes */
1287 }
1288
1289 /*Similar to iramsav but for xram memory*/
1290 VOID
1291 xramsav()
1292 {
1293   unget(getnb());
1294   if (ip && *ip)
1295     xram_size = expr(0);        /* evaluate size expression */
1296   else
1297         xram_size = rflag?0x1000000:0x10000;
1298 }
1299
1300 /*Similar to iramsav but for code memory*/
1301 VOID
1302 codesav()
1303 {
1304   unget(getnb());
1305   if (ip && *ip)
1306     code_size = expr(0);        /* evaluate size expression */
1307   else
1308         code_size = rflag?0x1000000:0x10000;
1309 }
1310
1311
1312 /*)Function     VOID    iramcheck()
1313  *
1314  *      The function iramcheck() is used at the end of linking to check that
1315  *      the internal RAM area wasn't overflowed by too many variable
1316  *      assignments.  Variables in the DSEG, ISEG, and OSEG are assigned to
1317  *      the chip's internal RAM.
1318  *
1319  *      local variables:
1320  *              none
1321  *
1322  *      global variables:
1323  *              unsigned int            size of chip's internal
1324  *                      iram_size               RAM segment
1325  *              struct area             linked list of memory
1326  *                      *areap                  areas
1327  *
1328  *       functions called:
1329  *
1330  *      side effects:
1331  */
1332
1333 VOID
1334 iramcheck()
1335 {
1336   register unsigned int last_addr;
1337   register struct area *ap;
1338
1339   for (ap = areap; ap; ap=ap->a_ap) {
1340     if ((ap->a_size != 0) &&
1341         (!strcmp(ap->a_id, "DSEG") ||
1342          !strcmp(ap->a_id, "OSEG") ||
1343          !strcmp(ap->a_id, "ISEG")
1344         )
1345        )
1346     {
1347       last_addr = ap->a_addr + ap->a_size - 1;
1348       if (last_addr >= iram_size)
1349         fprintf(stderr,
1350                 "\nWARNING! Segment %s extends past the end\n"
1351                 "         of internal RAM.  Check map file.\n",
1352                 ap->a_id);
1353     }
1354   }
1355 }
1356
1357 char *usetxt[] = {
1358         "Startup:",
1359         "  -c   Command line input",
1360         "  -f   file[LNK] File input",
1361         "  -p   Prompt and echo of file[LNK] to stdout (default)",
1362         "  -n   No echo of file[LNK] to stdout",
1363 /*      "Usage: [-Options] file [file ...]", */
1364         "Libraries:",
1365         "  -k   Library path specification, one per -k",
1366         "  -l   Library file specification, one per -l",
1367         "Relocation:",
1368         "  -b   area base address = expression",
1369         "  -g   global symbol = expression",
1370         "Map format:",
1371         "  -m   Map output generated as file[MAP]",
1372         "  -x   Hexadecimal (default),  -d  Decimal,  -q  Octal",
1373         "Output:",
1374         "  -i   Intel Hex as file[IHX]",
1375         "  -s   Motorola S19 as file[S19]",
1376         "  -j   Produce NoICE debug as file[NOI]",
1377         "  -z   Produce SDCdb debug as file[cdb]",
1378 /*      "List:", */
1379         "  -u   Update listing file(s) with link data as file(s)[.RST]",
1380         "Miscellaneous:\n"
1381         "  -a   [iram-size] Check for internal RAM overflow",
1382         "  -v   [xram-size] Check for external RAM overflow",
1383         "  -w   [code-size] Check for code overflow",
1384         "  -y   Generate memory usage summary file[mem]",
1385         "  -Y   Pack internal ram",
1386         "  -A   [stack-size] Allocate space for stack",
1387         "End:",
1388         "  -e   or null line terminates input",
1389         0
1390 };
1391
1392 /*)Function     VOID    usage()
1393  *
1394  *      The function usage() outputs to the stderr device the
1395  *      assembler name and version and a list of valid assembler options.
1396  *
1397  *      local variables:
1398  *              char ** dp              pointer to an array of
1399  *                                      text string pointers.
1400  *
1401  *      global variables:
1402  *              FILE *  stderr          c_library
1403  *
1404  *      functions called:
1405  *              int     fprintf()       c_library
1406  *
1407  *      side effects:
1408  *              none
1409  */
1410
1411 VOID
1412 usage()
1413 {
1414         register char   **dp;
1415
1416         fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1417         for (dp = usetxt; *dp; dp++)
1418                 fprintf(stderr, "%s\n", *dp);
1419         lkexit(1);
1420 }
1421
1422 /*)Function     VOID    copyfile()
1423  *              
1424  *              FILE    *dest           destination file
1425  *              FILE    *src            source file
1426  *
1427  *      function will copy source file to destination file
1428  *
1429  *
1430  *      functions called:
1431  *              int     fgetc()         c_library
1432  *              int     fputc()         c_library
1433  *
1434  *      side effects:
1435  *              none
1436  */
1437 VOID copyfile (dest,src)
1438 FILE *src,*dest ;
1439 {    
1440     int ch;
1441     while ((ch = fgetc(src)) != EOF) {
1442
1443         fputc(ch,dest);
1444     }
1445 }