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