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