* as/link/aslink.h: added LKOBJEXT
[fw/sdcc] / as / link / z80 / lkmain.c
1 /* lkmain.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  */
11
12 /*
13  * Extensions: P. Felber
14  */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include "aslink.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_main()
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 functions 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_main()     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(int argc, char *argv[])
186 {
187         register char *p;
188         register int c, i;
189
190 #ifdef WIN32T
191     Timer(0, "");
192 #endif
193
194 #ifdef GAMEBOY
195         nb_rom_banks = 2;
196         nb_ram_banks = 0;
197         mbc_type = 0;
198         symflag=0;
199
200         for(i = 0; default_basep[i] != NULL; i++) {
201                 if(basep == NULL) {
202                         basep = (struct base *)new(sizeof(struct base));
203                         bsp = basep;
204                 } else {
205                         bsp->b_base = (struct base *)new(sizeof(struct base));
206                         bsp = bsp->b_base;
207                 }
208                 bsp->b_strp = default_basep[i];
209         }
210         for(i = 0; default_globlp[i] != NULL; i++) {
211                 if(globlp == NULL) {
212                         globlp = (struct globl *)new(sizeof(struct globl));
213                         gsp = globlp;
214                 } else {
215                         gsp->g_globl = (struct globl *)new(sizeof(struct globl));
216                         gsp = gsp->g_globl;
217                 }
218                 gsp->g_strp = default_globlp[i];
219         }
220 #endif /* GAMEBOY */
221 #ifndef SDK
222         fprintf(stdout, "\n");
223 #endif /* SDK */
224
225         startp = (struct lfile *) new (sizeof (struct lfile));
226
227         pflag = 1;
228         for (i=1; i<argc; ++i) {
229                 p = argv[i];
230                 if (*p == '-') {
231                         while (ctype[c = *(++p)] & LETTER) {
232                                 switch(c) {
233
234                                 case 'c':
235                                 case 'C':
236                                         startp->f_type = F_STD;
237                                         break;
238
239                                 case 'f':
240                                 case 'F':
241                                         startp->f_type = F_LNK;
242                                         break;
243
244                                 case 'n':
245                                 case 'N':
246                                         pflag = 0;
247                                         break;
248
249                                 case 'p':
250                                 case 'P':
251                                         pflag = 1;
252                                         break;
253
254                                 default:
255                                         usage();
256                                 }
257                         }
258
259 #ifdef SDK
260                         if(c == '-') {
261                                 startp->f_type = F_CMD;
262                                 startp->f_idp = (char *)&argv[i+1];
263                                 break;
264                         }
265 #endif /* SDK */
266
267                 } else {
268                         if (startp->f_type == F_LNK) {
269                                 startp->f_idp = p;
270                         }
271                 }
272         }
273         if (startp->f_type == F_INV)
274                 usage();
275         if (startp->f_type == F_LNK && startp->f_idp == NULL)
276                 usage();
277 #ifdef SDK
278         if (startp->f_type == F_CMD && startp->f_idp == NULL)
279                 usage();
280 #endif /* SDK */
281
282         cfp = NULL;
283         sfp = NULL;
284         filep = startp;
285         while (1) {
286                 ip = ib;
287                 if (lk_getline() == 0)
288                         break;
289                 if (pflag && sfp != stdin)
290                         fprintf(stdout, "%s\n", ip);
291                 if (*ip == '\0' || parse())
292                         break;
293         }
294
295         if (sfp) {
296                 fclose(sfp);
297                 sfp = NULL;
298         }
299
300         if (linkp == NULL)
301                 usage();
302 #ifdef SDK
303         if (linkp->f_flp == NULL)
304                 usage();
305 #endif /* SDK */
306
307 #ifdef GAMEBOY
308         for(i = 1; i < nb_rom_banks; i++) {
309                 bsp->b_base = (struct base *)new(sizeof(struct base));
310                 bsp = bsp->b_base;
311                 bsp->b_strp = (char *)malloc(18);
312                 sprintf(bsp->b_strp, "_CODE_%d=0x4000", i);
313         }
314         for(i = 0; i < nb_ram_banks; i++) {
315                 bsp->b_base = (struct base *)new(sizeof(struct base));
316                 bsp = bsp->b_base;
317                 bsp->b_strp = (char *)malloc(18);
318                 sprintf(bsp->b_strp, "_DATA_%d=0xA000", i);
319         }
320 #endif /* GAMEBOY */
321
322         syminit();
323         for (pass=0; pass<2; ++pass) {
324                 cfp = NULL;
325                 sfp = NULL;
326 #ifdef SDK
327                 filep = linkp->f_flp;
328 #else /* SDK */
329                 filep = linkp;
330 #endif /* SDK */
331                 hp = NULL;
332                 radix = 10;
333
334                 while (lk_getline()) {
335                         ip = ib;
336                         link_main();
337                 }
338                 if (pass == 0) {
339                         /*
340                          * Search libraries for global symbols
341                          */
342                         search();
343                         /*
344                          * Set area base addresses.
345                          */
346                         setbas();
347                         /*
348                          * Link all area addresses.
349                          */
350                         lnkarea();
351                         /*
352                          * Process global definitions.
353                          */
354                         setgbl();
355                         /*
356                          * Check for undefined globals.
357                          */
358                         symdef(stderr);
359 #ifdef SDK
360                         if (symflag)
361                                 sym();
362 #endif
363                         /*
364                          * Output Link Map if requested.
365                          */
366                         if (mflag)
367                                 map();
368                         /*
369                          * Open output file
370                          */
371                         if (oflag == 1) {
372 #ifdef SDK
373                                 ofp = afile(linkp->f_idp, "ihx", 1);
374 #else /* SDK */
375                                 ofp = afile(linkp->f_idp, "IHX", 1);
376 #endif /* SDK */
377                                 if (ofp == NULL) {
378                                         lkexit(1);
379                                 }
380                         } else
381                         if (oflag == 2) {
382 #ifdef SDK
383                                 ofp = afile(linkp->f_idp, "s19", 1);
384 #else /* SDK */
385                                 ofp = afile(linkp->f_idp, "S19", 1);
386 #endif /* SDK */
387                                 if (ofp == NULL) {
388                                         lkexit(1);
389                                 }
390 #ifdef SDK
391                         } else
392                         if (oflag == 3) {
393                                 binary = 1;
394                                 ofp = afile(linkp->f_idp, "", 1);
395                                 binary = 0;
396                                 if (ofp == NULL) {
397                                         lkexit(1);
398                                 }
399 #endif /* SDK */
400                         }
401                 } else {
402                         /*
403                          * Link in library files
404                          */
405                         library();
406                         reloc('E');
407                 }
408         }
409 #ifdef WIN32T
410     Timer(1, "Linker execution time");
411 #endif
412
413         lkexit(lkerr);
414
415         /* Never get here. */
416         return 0;
417 }
418
419 /*)Function     VOID    lkexit(i)
420  *
421  *                      int     i       exit code
422  *
423  *      The function lkexit() explicitly closes all open
424  *      files and then terminates the program.
425  *
426  *      local variables:
427  *              none
428  *
429  *      global variables:
430  *              FILE *  mfp             file handle for .map
431  *              FILE *  ofp             file handle for .ihx/.s19
432  *              FILE *  rfp             file hanlde for .rst
433  *              FILE *  sfp             file handle for .rel
434  *              FILE *  tfp             file handle for .lst
435  *
436  *      functions called:
437  *              int     fclose()        c_library
438  *              VOID    exit()          c_library
439  *
440  *      side effects:
441  *              All files closed. Program terminates.
442  */
443
444 VOID
445 lkexit(int i)
446 {
447         if (mfp != NULL) fclose(mfp);
448         if (ofp != NULL) fclose(ofp);
449         if (rfp != NULL) fclose(rfp);
450         if (sfp != NULL) fclose(sfp);
451         if (tfp != NULL) fclose(tfp);
452         exit(i);
453 }
454
455 /*)Function     link_main()
456  *
457  *      The function link_main() evaluates the directives for each line of
458  *      text read from the .rel file(s).  The valid directives processed
459  *      are:
460  *              X, D, Q, H, M, A, S, T, R, and P.
461  *
462  *      local variables:
463  *              int     c               first non blank character of a line
464  *
465  *      global variables:
466  *              head    *headp          The pointer to the first
467  *                                      head structure of a linked list
468  *              head    *hp             Pointer to the current
469  *                                      head structure
470  *              int     pass            linker pass number
471  *              int     radix           current number conversion radix
472  *
473  *      functions called:
474  *              char    endline()       lklex.c
475  *              VOID    module()        lkhead.c
476  *              VOID    newarea()       lkarea.c
477  *              VOID    newhead()       lkhead.c
478  *              sym *   newsym()        lksym.c
479  *              VOID    reloc()         lkreloc.c
480  *
481  *      side effects:
482  *              Head, area, and symbol structures are created and
483  *              the radix is set as the .rel file(s) are read.
484  */
485
486 VOID
487 link_main()
488 {
489         register char c;
490
491         if ((c=endline()) == 0) { return; }
492         switch (c) {
493
494         case 'O': /*For some important sdcc options*/
495                 if (pass == 0)
496                 {
497                         if(strlen(sdccopt)==0)
498                         {
499                                 strcpy(sdccopt, &ip[1]);
500                                 strcpy(sdccopt_module, curr_module);
501                         }
502                         else
503                         {
504                                 if(strcmp(sdccopt, &ip[1])!=0)
505                                 {
506                                         fprintf(stderr,
507                                                 "?ASlink-Warning-Conflicting sdcc options:\n"
508                                                 "   \"%s\" in module \"%s\" and\n"
509                                                 "   \"%s\" in module \"%s\".\n",
510                                                 sdccopt, sdccopt_module, &ip[1], curr_module);
511                                         lkerr++;
512                                 }
513                         }
514                 }
515                 break;
516
517         case 'X':
518                 radix = 16;
519                 break;
520
521         case 'D':
522                 radix = 10;
523                 break;
524
525         case 'Q':
526                 radix = 8;
527                 break;
528
529         case 'H':
530                 if (pass == 0) {
531                         newhead();
532                 } else {
533                         if (hp == 0) {
534                                 hp = headp;
535                         } else {
536                                 hp = hp->h_hp;
537                         }
538                 }
539                 sdp.s_area = NULL;
540                 sdp.s_areax = NULL;
541                 sdp.s_addr = 0;
542                 break;
543
544         case 'M':
545                 if (pass == 0)
546         {
547             strcpy(curr_module, &ip[1]);
548                         module();
549         }
550                 break;
551
552         case 'A':
553                 if (pass == 0)
554                         newarea();
555                 if (sdp.s_area == NULL) {
556                         sdp.s_area = areap;
557                         sdp.s_areax = areap->a_axp;
558                         sdp.s_addr = 0;
559                 }
560                 break;
561
562         case 'S':
563                 if (pass == 0)
564                         newsym();
565                 break;
566
567         case 'T':
568         case 'R':
569         case 'P':
570                 if (pass == 0)
571                         break;
572                 reloc(c);
573                 break;
574
575         default:
576                 break;
577         }
578         if (c == 'X' || c == 'D' || c == 'Q') {
579                 if ((c = get()) == 'H') {
580                         hilo = 1;
581                 } else
582                 if (c == 'L') {
583                         hilo = 0;
584                 }
585         }
586 }
587
588 /*)Function     VOID    map()
589  *
590  *      The function map() opens the output map file and calls the various
591  *      routines to
592  *      (1) output the variables in each area,
593  *      (2) list the files processed with module names,
594  *      (3) list the libraries file processed,
595  *      (4) list base address definitions,
596  *      (5) list global variable definitions, and
597  *      (6) list any undefined variables.
598  *
599  *      local variables:
600  *              int     i               counter
601  *              head *  hdp             pointer to head structure
602  *              lbfile *lbfh            pointer to library file structure
603  *
604  *      global variables:
605  *              area    *ap             Pointer to the current
606  *                                      area structure
607  *              area    *areap          The pointer to the first
608  *                                      area structure of a linked list
609  *              base    *basep          The pointer to the first
610  *                                      base structure
611  *              base    *bsp            Pointer to the current
612  *                                      base structure
613  *              lfile   *filep          The pointer *filep points to the
614  *                                      beginning of a linked list of
615  *                                      lfile structures.
616  *              globl   *globlp         The pointer to the first
617  *                                      globl structure
618  *              globl   *gsp            Pointer to the current
619  *                                      globl structure
620  *              head    *headp          The pointer to the first
621  *                                      head structure of a linked list
622  *              lbfile  *lbfhead        The pointer to the first
623  *                                      lbfile structure of a linked list
624  *              lfile   *linkp          pointer to first lfile structure
625  *                                      containing an input REL file
626  *                                      specification
627  *              int     lop             current line number on page
628  *              FILE    *mfp            Map output file handle
629  *              int     page            current page number
630  *
631  *      functions called:
632  *              FILE *  afile()         lkmain.c
633  *              int     fprintf()       c_library
634  *              VOID    lkexit()        lkmain.c
635  *              VOID    lstarea()       lklist.c
636  *              VOID    newpag()        lklist.c
637  *              VOID    symdef()        lksym.c
638  *
639  *      side effects:
640  *              The map file is created.
641  */
642
643 #ifndef MLH_MAP
644 VOID
645 map()
646 {
647         register int i;
648         register struct head *hdp;
649         register struct lbfile *lbfh;
650
651         /*
652          * Open Map File
653          */
654 #ifdef SDK
655         mfp = afile(linkp->f_idp, "map", 1);
656 #else /* SDK */
657         mfp = afile(linkp->f_idp, "MAP", 1);
658 #endif /* SDK */
659         if (mfp == NULL) {
660                 lkexit(1);
661         }
662
663         /*
664          * Output Map Area Lists
665          */
666         page = 0;
667         lop  = NLPP;
668         ap = areap;
669         while (ap) {
670                 lstarea(ap);
671                 ap = ap->a_ap;
672         }
673         /*
674          * List Linked Files
675          */
676         newpag(mfp);
677         fprintf(mfp, "\nFiles Linked      [ module(s) ]\n\n");
678         hdp = headp;
679 #ifdef SDK
680         filep = linkp->f_flp;
681 #else /* SDK */
682         filep = linkp;
683 #endif /* SDK */
684         while (filep) {
685                 fprintf(mfp, "%-16s", filep->f_idp);
686                 i = 0;
687                 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
688                         if (i % 5) {
689                             fprintf(mfp, ", %8.8s", hdp->m_id);
690                         } else {
691                             if (i) {
692                                 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
693                             } else {
694                                 fprintf(mfp, "  [ %8.8s", hdp->m_id);
695                             }
696                         }
697                         hdp = hdp->h_hp;
698                         i++;
699                 }
700                 if (i)
701                         fprintf(mfp, " ]");
702                 fprintf(mfp, "\n");
703                 filep = filep->f_flp;
704         }
705         /*
706          * List Linked Libraries
707          */
708         if (lbfhead != NULL) {
709                 fprintf(mfp,
710         "\nLibraries Linked                    [   object  file   ]\n\n");
711                 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
712                         fprintf(mfp, "%-32s    [ %16.16s ]\n",
713                                 lbfh->libspc, lbfh->relfil);
714                 }
715                 fprintf(mfp, "\n");
716         }
717         /*
718          * List Base Address Definitions
719          */
720         if (basep) {
721                 newpag(mfp);
722                 fprintf(mfp, "\nUser Base Address Definitions\n\n");
723                 bsp = basep;
724                 while (bsp) {
725                         fprintf(mfp, "%s\n", bsp->b_strp);
726                         bsp = bsp->b_base;
727                 }
728         }
729         /*
730          * List Global Definitions
731          */
732         if (globlp) {
733                 newpag(mfp);
734                 fprintf(mfp, "\nUser Global Definitions\n\n");
735                 gsp = globlp;
736                 while (gsp) {
737                         fprintf(mfp, "%s\n", gsp->g_strp);
738                         gsp = gsp->g_globl;
739                 }
740         }
741         fprintf(mfp, "\n\f");
742         symdef(mfp);
743 }
744 #else
745 VOID map()
746 {
747         register struct head *hdp;
748         register struct lbfile *lbfh;
749
750         /*
751          * Open Map File
752          */
753 #ifdef SDK
754         mfp = afile(linkp->f_idp, "map", 1);
755 #else /* SDK */
756         mfp = afile(linkp->f_idp, "MAP", 1);
757 #endif /* SDK */
758         if (mfp == NULL) {
759                 lkexit(1);
760         }
761
762         /*
763          *Output Map Area Lists
764          */
765         page = 0;
766         lop  = NLPP;
767         ap = areap;
768         while (ap) {
769                 lstarea(ap);
770                 ap = ap->a_ap;
771         }
772         /*
773          * List Linked Files
774          */
775         hdp = headp;
776 #ifdef SDK
777         filep = linkp->f_flp;
778 #else /* SDK */
779         filep = linkp;
780 #endif /* SDK */
781         if (filep) {
782                 fprintf( mfp, "MODULES\n");
783         }
784         while (filep) {
785                 fprintf(mfp, "\tFILE %s\n", filep->f_idp);
786                 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
787                         if (strlen(hdp->m_id)>0)
788                                 fprintf(mfp, "\t\tNAME %s\n", hdp->m_id);
789                         hdp = hdp->h_hp;
790                 }
791                 filep = filep->f_flp;
792         }
793         /*
794          * List Linked Libraries
795          */
796         if (lbfhead != NULL) {
797                 fprintf(mfp, "LIBRARIES\n");
798                 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
799                         fprintf(mfp,    "\tLIBRARY %s\n"
800                                         "\t\tMODULE %s\n",
801                                 lbfh->libspc, lbfh->relfil);
802                 }
803         }
804         /*
805          * List Base Address Definitions
806          */
807         if (basep) {
808                 fprintf(mfp, "USERBASEDEF\n");
809                 bsp = basep;
810                 while (bsp) {
811                         fprintf(mfp, "\t%s\n", bsp->b_strp);
812                         bsp = bsp->b_base;
813                 }
814         }
815         /*
816          * List Global Definitions
817          */
818         if (globlp) {
819                 fprintf(mfp, "USERGLOBALDEF\n");
820                 gsp = globlp;
821                 while (gsp) {
822                         fprintf(mfp, "\t%s\n", gsp->g_strp);
823                         gsp = gsp->g_globl;
824                 }
825         }
826         symdef(mfp);
827 #ifdef SDK
828         if (mfp!=NULL) {
829                 fclose(mfp);
830                 mfp = NULL;
831         }
832 #endif
833 }
834 #endif /* MLH_MAP */
835
836 #ifdef SDK
837 /* PENDING */
838 VOID lstareatosym(struct area *xp);
839
840 VOID sym()
841 {
842         /*
843          * Open sym File
844          */
845         mfp = afile(linkp->f_idp, "sym", 1);
846         if (mfp == NULL) {
847                 lkexit(1);
848         }
849         fprintf( mfp,   "; no$gmb format .sym file\n"
850                         "; Generated automagically by ASxxxx linker %s (SDK " SDK_VERSION_STRING ")\n"
851                 , VERSION );
852         /*
853          * Output sym Area Lists
854          */
855         page = 0;
856         lop  = NLPP;
857         ap = areap;
858         while (ap) {
859                 lstareatosym(ap);
860                 ap = ap->a_ap;
861         }
862         if (mfp!=NULL) {
863                 fclose(mfp);
864                 mfp = NULL;
865         }
866 }
867 #endif /* SDK */
868
869 /*)Function     int     parse()
870  *
871  *      The function parse() evaluates all command line or file input
872  *      linker directives and updates the appropriate variables.
873  *
874  *      local variables:
875  *              int     c               character value
876  *              char    fid[]           file id string
877  *
878  *      global variables:
879  *              char    ctype[]         array of character types, one per
880  *                                      ASCII character
881  *              lfile   *lfp            pointer to current lfile structure
882  *                                      being processed by parse()
883  *              lfile   *linkp          pointer to first lfile structure
884  *                                      containing an input REL file
885  *                                      specification
886  *              int     mflag           Map output flag
887  *              int     oflag           Output file type flag
888  *              int     pflag           print linker command file flag
889  *              FILE *  stderr          c_library
890  *              int     uflag           Relocated listing flag
891  *              int     xflag           Map file radix type flag
892  *
893  *      Functions called:
894  *              VOID    addlib()        lklibr.c
895  *              VOID    addpath()       lklibr.c
896  *              VOID    bassav()        lkmain.c
897  *              int     fprintf()       c_library
898  *              VOID    gblsav()        lkmain.c
899  *              VOID    getfid()        lklex.c
900  *              char    getnb()         lklex.c
901  *              VOID    lkexit()        lkmain.c
902  *              char *  strcpy()        c_library
903  *              int     strlen()        c_library
904  *
905  *      side effects:
906  *              Various linker flags are updated and the linked
907  *              structure lfile is created.
908  */
909
910 int
911 parse()
912 {
913         register int c;
914         char fid[NINPUT];
915
916         while ((c = getnb()) != 0) {
917                 if (c == ';')
918                         return(0);
919                 if ( c == '-') {
920                         while (ctype[c=get()] & LETTER) {
921                                 switch(c) {
922
923                                 case 'i':
924                                 case 'I':
925                                         oflag = 1;
926                                         break;
927
928                                 case 's':
929                                 case 'S':
930                                         oflag = 2;
931                                         break;
932 #ifdef GAMEBOY
933                                 case 'y':
934                                 case 'Y':
935                                         c = get();
936                                         if(c == 'O' || c == 'o')
937                                                 nb_rom_banks = expr(0);
938                                         else if(c == 'A' || c == 'a')
939                                                 nb_ram_banks = expr(0);
940                                         else if(c == 'T' || c == 't')
941                                                 mbc_type = expr(0);
942                                         else if(c == 'N' || c == 'n') {
943                                                 int i = 0;
944                                                 if(getnb() != '=' || getnb() != '"') {
945                                                         fprintf(stderr, "Syntax error in -YN=\"name\" flag\n");
946                                                         lkexit(1);
947                                                 }
948                                                 while((c = get()) != '"' && i < 16) {
949                                                         cart_name[i++] = c;
950                                                 }
951                                                 if(i < 16)
952                                                         cart_name[i] = 0;
953                                                 else
954                                                         while(get() != '"')
955                                                                 ;
956                                         } else if(c == 'P' || c == 'p') {
957                                                 patch *p = patches;
958
959                                                 patches = (patch *)malloc(sizeof(patch));
960                                                 patches->next = p;
961                                                 patches->addr = expr(0);
962                                                 if(getnb() != '=') {
963                                                         fprintf(stderr, "Syntax error in -YHaddr=val flag\n");
964                                                         lkexit(1);
965                                                 }
966                                                 patches->value = expr(0);
967                                         } else {
968                                                 fprintf(stderr, "Invalid option\n");
969                                                 lkexit(1);
970                                         }
971                                         break;
972
973 #endif /* GAMEBOY */
974 #ifdef SDK
975                                 case 'j':
976                                 case 'J':
977                                         ++symflag;
978                                         break;
979                                 case 'z':
980                                 case 'Z':
981                                         oflag = 3;
982                                         break;
983 #endif /* SDK */
984                                 case 'm':
985                                 case 'M':
986                                         ++mflag;
987                                         break;
988
989                                 case 'u':
990                                 case 'U':
991                                         uflag = 1;
992                                         break;
993
994                                 case 'x':
995                                 case 'X':
996                                         xflag = 0;
997                                         break;
998
999                                 case 'q':
1000                                 case 'Q':
1001                                         xflag = 1;
1002                                         break;
1003
1004                                 case 'd':
1005                                 case 'D':
1006                                         xflag = 2;
1007                                         break;
1008
1009                                 case 'e':
1010                                 case 'E':
1011                                         return(1);
1012
1013                                 case 'n':
1014                                 case 'N':
1015                                         pflag = 0;
1016                                         break;
1017
1018                                 case 'p':
1019                                 case 'P':
1020                                         pflag = 1;
1021                                         break;
1022
1023                                 case 'b':
1024                                 case 'B':
1025                                         bassav();
1026                                         return(0);
1027
1028                                 case 'g':
1029                                 case 'G':
1030                                         gblsav();
1031                                         return(0);
1032
1033                                 case 'k':
1034                                 case 'K':
1035                                         addpath();
1036                                         return(0);
1037
1038                                 case 'l':
1039                                 case 'L':
1040                                         addlib();
1041                                         return(0);
1042
1043                                 default:
1044                                         fprintf(stderr, "Invalid option\n");
1045                                         lkexit(1);
1046                                 }
1047                         }
1048                         if (c == ';')
1049                                 return(0);
1050                 } else if (ctype[c] & ILL) {
1051                         fprintf(stderr, "Invalid input");
1052                         lkexit(1);
1053                 } else {
1054                         if (linkp == NULL) {
1055                                 linkp = (struct lfile *)
1056                                         new (sizeof (struct lfile));
1057                                 lfp = linkp;
1058                         } else {
1059                                 lfp->f_flp = (struct lfile *)
1060                                                 new (sizeof (struct lfile));
1061                                 lfp = lfp->f_flp;
1062                         }
1063                         getfid(fid, c);
1064                         lfp->f_idp = (char *) new (strlen(fid)+1);
1065                         strcpy(lfp->f_idp, fid);
1066                         lfp->f_type = F_REL;
1067                 }
1068         }
1069         return(0);
1070 }
1071
1072 /*)Function     VOID    bassav()
1073  *
1074  *      The function bassav() creates a linked structure containing
1075  *      the base address strings input to the linker.
1076  *
1077  *      local variables:
1078  *              none
1079  *
1080  *      global variables:
1081  *              base    *basep          The pointer to the first
1082  *                                      base structure
1083  *              base    *bsp            Pointer to the current
1084  *                                      base structure
1085  *              char    *ip             pointer into the REL file
1086  *                                      text line in ib[]
1087  *
1088  *       functions called:
1089  *              char    getnb()         lklex.c
1090  *              VOID *  new()           lksym.c
1091  *              int     strlen()        c_library
1092  *              char *  strcpy()        c_library
1093  *              VOID    unget()         lklex.c
1094  *
1095  *      side effects:
1096  *              The basep structure is created.
1097  */
1098
1099 VOID
1100 bassav()
1101 {
1102         if (basep == NULL) {
1103                 basep = (struct base *)
1104                         new (sizeof (struct base));
1105                 bsp = basep;
1106         } else {
1107                 bsp->b_base = (struct base *)
1108                                 new (sizeof (struct base));
1109                 bsp = bsp->b_base;
1110         }
1111         unget(getnb());
1112         bsp->b_strp = (char *) new (strlen(ip)+1);
1113         strcpy(bsp->b_strp, ip);
1114 }
1115
1116 /*)Function     VOID    setbas()
1117  *
1118  *      The function setbas() scans the base address lines in the
1119  *      basep structure, evaluates the arguments, and sets beginning
1120  *      address of the specified areas.
1121  *
1122  *      local variables:
1123  *              int     v               expression value
1124  *              char    id[]            base id string
1125  *
1126  *      global variables:
1127  *              area    *ap             Pointer to the current
1128  *                                      area structure
1129  *              area    *areap          The pointer to the first
1130  *                                      area structure of a linked list
1131  *              base    *basep          The pointer to the first
1132  *                                      base structure
1133  *              base    *bsp            Pointer to the current
1134  *                                      base structure
1135  *              char    *ip             pointer into the REL file
1136  *                                      text line in ib[]
1137  *              int     lkerr           error flag
1138  *
1139  *       functions called:
1140  *              Addr_T  expr()          lkeval.c
1141  *              int     fprintf()       c_library
1142  *              VOID    getid()         lklex.c
1143  *              char    getnb()         lklex.c
1144  *              int     symeq()         lksym.c
1145  *
1146  *      side effects:
1147  *              The base address of an area is set.
1148  */
1149
1150 VOID
1151 setbas()
1152 {
1153         register int v;
1154         char id[NCPS];
1155
1156         bsp = basep;
1157         while (bsp) {
1158                 ip = bsp->b_strp;
1159                 getid(id, -1);
1160                 if (getnb() == '=') {
1161                         v = expr(0);
1162                         for (ap = areap; ap != NULL; ap = ap->a_ap) {
1163                                 if (symeq(id, ap->a_id))
1164                                         break;
1165                         }
1166                         if (ap == NULL) {
1167 #ifndef SDK
1168                                 fprintf(stderr,
1169                                 "ASlink-Warning-No definition of area %s\n", id);
1170                                 lkerr++;
1171 #endif /* SDK */
1172                         } else {
1173                                 ap->a_addr = v;
1174                         }
1175                 } else {
1176                         fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1177                         lkerr++;
1178                 }
1179                 bsp = bsp->b_base;
1180         }
1181 }
1182
1183 /*)Function     VOID    gblsav()
1184  *
1185  *      The function gblsav() creates a linked structure containing
1186  *      the global variable strings input to the linker.
1187  *
1188  *      local variable:
1189  *              none
1190  *
1191  *      global variables:
1192  *              globl   *globlp         The pointer to the first
1193  *                                      globl structure
1194  *              globl   *gsp            Pointer to the current
1195  *                                      globl structure
1196  *              char    *ip             pointer into the REL file
1197  *                                      text line in ib[]
1198  *              int     lkerr           error flag
1199  *
1200  *      functions called:
1201  *              char    getnb()         lklex.c
1202  *              VOID *  new()           lksym.c
1203  *              int     strlen()        c_library
1204  *              char *  strcpy()        c_library
1205  *              VOID    unget()         lklex.c
1206  *
1207  *      side effects:
1208  *              The globlp structure is created.
1209  */
1210
1211 VOID
1212 gblsav()
1213 {
1214         if (globlp == NULL) {
1215                 globlp = (struct globl *)
1216                         new (sizeof (struct globl));
1217                 gsp = globlp;
1218         } else {
1219                 gsp->g_globl = (struct globl *)
1220                                 new (sizeof (struct globl));
1221                 gsp = gsp->g_globl;
1222         }
1223         unget(getnb());
1224         gsp->g_strp = (char *) new (strlen(ip)+1);
1225         strcpy(gsp->g_strp, ip);
1226 }
1227
1228 /*)Function     VOID    setgbl()
1229  *
1230  *      The function setgbl() scans the global variable lines in the
1231  *      globlp structure, evaluates the arguments, and sets a variable
1232  *      to this value.
1233  *
1234  *      local variables:
1235  *              int     v               expression value
1236  *              char    id[]            base id string
1237  *              sym *   sp              pointer to a symbol structure
1238  *
1239  *      global variables:
1240  *              char    *ip             pointer into the REL file
1241  *                                      text line in ib[]
1242  *              globl   *globlp         The pointer to the first
1243  *                                      globl structure
1244  *              globl   *gsp            Pointer to the current
1245  *                                      globl structure
1246  *              FILE *  stderr          c_library
1247  *              int     lkerr           error flag
1248  *
1249  *       functions called:
1250  *              Addr_T  expr()          lkeval.c
1251  *              int     fprintf()       c_library
1252  *              VOID    getid()         lklex.c
1253  *              char    getnb()         lklex.c
1254  *              sym *   lkpsym()        lksym.c
1255  *
1256  *      side effects:
1257  *              The value of a variable is set.
1258  */
1259
1260 VOID
1261 setgbl()
1262 {
1263         register int v;
1264         register struct sym *sp;
1265         char id[NCPS];
1266
1267         gsp = globlp;
1268         while (gsp) {
1269                 ip = gsp->g_strp;
1270                 getid(id, -1);
1271                 if (getnb() == '=') {
1272                         v = expr(0);
1273                         sp = lkpsym(id, 0);
1274                         if (sp == NULL) {
1275 #ifndef SDK
1276                                 fprintf(stderr,
1277                                 "No definition of symbol %s\n", id);
1278                                 lkerr++;
1279 #endif /* SDK */
1280                         } else {
1281 #ifndef SDK
1282                                 if (sp->s_flag & S_DEF) {
1283                                         fprintf(stderr,
1284                                         "Redefinition of symbol %s\n", id);
1285                                         lkerr++;
1286                                         sp->s_axp = NULL;
1287                                 }
1288 #endif /* SDK */
1289                                 sp->s_addr = v;
1290                                 sp->s_type |= S_DEF;
1291                         }
1292                 } else {
1293                         fprintf(stderr, "No '=' in global expression");
1294                         lkerr++;
1295                 }
1296                 gsp = gsp->g_globl;
1297         }
1298 }
1299
1300 /*)Function     FILE *  afile(fn,, ft, wf)
1301  *
1302  *              char *  fn              file specification string
1303  *              char *  ft              file type string
1304  *              int     wf              read(0)/write(1) flag
1305  *
1306  *      The function afile() opens a file for reading or writing.
1307  *              (1)     If the file type specification string ft
1308  *                      is not NULL then a file specification is
1309  *                      constructed with the file path\name in fn
1310  *                      and the extension in ft.
1311  *              (2)     If the file type specification string ft
1312  *                      is NULL then the file specification is
1313  *                      constructed from fn.  If fn does not have
1314  *                      a file type then the default .rel file
1315  *                      type is appended to the file specification.
1316  *
1317  *      afile() returns a file handle for the opened file or aborts
1318  *      the assembler on an open error.
1319  *
1320  *      local variables:
1321  *              int     c               character value
1322  *              char    fb[]            constructed file specification string
1323  *              FILE *  fp              filehandle for opened file
1324  *              char *  p1              pointer to filespec string fn
1325  *              char *  p2              pointer to filespec string fb
1326  *              char *  p3              pointer to filetype string ft
1327  *
1328  *      global variables:
1329  *              int     lkerr           error flag
1330  *
1331  *      functions called:
1332  *              FILE *  fopen()         c_library
1333  *              int     fprintf()       c_library
1334  *
1335  *      side effects:
1336  *              File is opened for read or write.
1337  */
1338
1339 FILE *
1340 afile(char *fn, char *ft, int wf)
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[PATH_MAX];
1350
1351 #if 0
1352         p1 = fn;
1353         p2 = fb;
1354         p3 = ft;
1355         while ((c = *p1++) != 0 && c != FSEPX) {
1356                 if (p2 < &fb[PATH_MAX-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         "Libraries:",
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   Hexadecimal (default),  -d  Decimal,  -q  Octal",
1454         "Output:",
1455         "  -i   Intel Hex as file[IHX]",
1456         "  -s   Motorola S19 as file[S19]",
1457 #ifdef SDK
1458 #ifdef GAMEGEAR
1459         "  -z   Gamegear image as file[GG]",
1460 #else
1461         "  -z   Gameboy image as file[GB]",
1462 #endif /* GAMEGEAR */
1463 #endif /* SDK */
1464         "List:",
1465         "  -u   Update listing file(s) with link data as file(s)[.RST]",
1466         "End:",
1467         "  -e   or null line terminates input",
1468         "",
1469         0
1470 };
1471
1472 /*)Function     VOID    usage()
1473  *
1474  *      The function usage() outputs to the stderr device the
1475  *      assembler name and version and a list of valid assembler options.
1476  *
1477  *      local variables:
1478  *              char ** dp              pointer to an array of
1479  *                                      text string pointers.
1480  *
1481  *      global variables:
1482  *              FILE *  stderr          c_library
1483  *
1484  *      functions called:
1485  *              int     fprintf()       c_library
1486  *
1487  *      side effects:
1488  *              none
1489  */
1490
1491 VOID
1492 usage()
1493 {
1494         register char   **dp;
1495
1496         fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1497         for (dp = usetxt; *dp; dp++)
1498                 fprintf(stderr, "%s\n", *dp);
1499         lkexit(1);
1500 }
1501
1502 /*)Function VOID    copyfile()
1503  *
1504  *      FILE    *dest           destination file
1505  *      FILE    *src            source file
1506  *
1507  *      function will copy source file to destination file
1508  *
1509  *
1510  *  functions called:
1511  *      int     fgetc()         c_library
1512  *      int     fputc()         c_library
1513  *
1514  *  side effects:
1515  *      none
1516  */
1517 VOID copyfile (dest,src)
1518 FILE *src,*dest ;
1519 {
1520     int ch;
1521
1522     while ((ch = fgetc(src)) != EOF) {
1523         fputc(ch,dest);
1524     }
1525 }