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