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