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