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