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