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