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