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