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