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