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