1 /* lkmain.c */
2 
3 /*
4  *  Copyright (C) 1989-2009  Alan R. Baldwin
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *
20  * Alan R. Baldwin
21  * 721 Berkeley St.
22  * Kent, Ohio  44240
23  */
24 
25 #include "aslink.h"
26 
27 /*)Module       lkmain.c
28  *
29  *      The module lkmain.c contains the functions which
30  *      (1) input the linker options, parameters, and specifications
31  *      (2) perform a two pass link
32  *      (3) produce the appropriate linked data output and/or
33  *          link map file and/or relocated listing files.
34  *
35  *      lkmain.c contains the following functions:
36  *              FILE *  afile()
37  *              VOID    bassav()
38  *              VOID    gblsav()
39  *              int     intsiz()
40  *              VOID    link_main()
41  *              VOID    lkexit()
42  *              int     fndext()
43  *              int     fndidx()
44  *              int     main()
45  *              VOID    map()
46  *              int     parse()
47  *              VOID    doparse()
48  *              VOID    setgbl()
49  *              VOID    usage()
50  *
51  *      lkmain.c contains the following local variables:
52  *              char *  usetext[]       array of pointers to the
53  *                                      command option tect lines
54  *
55  */
56 
57 /* sdld 8051 specific */
58 /*JCF:  Creates some of the default areas so they are allocated in the right order.*/
Areas51(void)59 void Areas51 (void)
60 {
61         char * rel[] = {
62                 "XH",
63                 "H 7 areas 0 global symbols",
64                 "A _CODE size 0 flags 0",               /*Each .rel has one, so...*/
65                 "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
66                 "A REG_BANK_1 size 0 flags 4",
67                 "A REG_BANK_2 size 0 flags 4",
68                 "A REG_BANK_3 size 0 flags 4",
69                 "A BSEG size 0 flags 80",               /*BSEG must be just before BITS*/
70                 "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
71                 ""
72         };
73 
74         char * rel2[] = {
75                 "XH",
76                 "H C areas 0 global symbols",
77                 "A _CODE size 0 flags 0",               /*Each .rel has one, so...*/
78                 "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
79                 "A REG_BANK_1 size 0 flags 4",
80                 "A REG_BANK_2 size 0 flags 4",
81                 "A REG_BANK_3 size 0 flags 4",
82                 "A BSEG size 0 flags 80",               /*BSEG must be just before BITS*/
83                 "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
84                 "A BIT_BANK size 0 flags 4",    /*Bit register bank is overlayable*/
85                 "A DSEG size 0 flags 0",
86                 "A OSEG size 0 flags 4",
87                 "A ISEG size 0 flags 0",
88                 "A SSEG size 0 flags 4",
89                 ""
90         };
91         int j;
92         struct sym * sp;
93 
94         if (packflag) {
95                 for (j = 0; rel2[j][0] != 0; j++) {
96                         ip = rel2[j];
97                         link_main();
98                 }
99         }
100         else {
101                 for (j = 0; rel[j][0] != 0; j++) {
102                         ip = rel[j];
103                         link_main();
104                 }
105         }
106 
107         /*Set the start address of the default areas:*/
108         for (ap = areap; ap; ap = ap->a_ap) {
109                 /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr = 0x00; ap->a_bset = 1; }
110                 else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr = 0x08; ap->a_bset = 1; }
111                 else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr = 0x10; ap->a_bset = 1; }
112                 else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr = 0x18; ap->a_bset = 1; }
113                 else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr = 0x20; ap->a_bset = 1; }
114                 else if (TARGET_IS_8051 && !strcmp(ap->a_id, "SSEG")) {
115                         if (stacksize) ap->a_axp->a_size = stacksize;
116                 }
117         }
118 
119         sp = lkpsym("l_IRAM", 1);
120         sp->s_addr = ((iram_size>0) && (iram_size<=0x100)) ? iram_size : 0x0100;
121         sp->s_axp = NULL;
122         sp->s_type |= S_DEF;
123 }
124 /* end sdld 8051 specific */
125 
126 /*)Function     int     main(argc,argv)
127  *
128  *              int     argc            number of command line arguments + 1
129  *              char *  argv[]          array of pointers to the command line
130  *                                      arguments
131  *
132  *      The function main() evaluates the command line arguments to
133  *      determine if the linker parameters are to input through 'stdin'
134  *      or read from a command file.  The functions nxtline() and parse()
135  *      are to input and evaluate the linker parameters.  The linking process
136  *      proceeds by making the first pass through each .rel file in the order
137  *      presented to the linker.  At the end of the first pass the setarea(),
138  *      lnkarea(), setgbl(), and symdef() functions are called to evaluate
139  *      the base address terms, link all areas, define global variables,
140  *      and look for undefined symbols.  Following these routines a linker
141  *      map file may be produced and the linker output files may be opened.
142  *      The second pass through the .rel files will output the linked data
143  *      in one of the supported formats.
144  *
145  *      local variables:
146  *              int     c               character from argument string
147  *              int     i               loop counter
148  *              int     j               loop counter
149  *              int     k               loop counter
150  *
151  *      global variables:
152  *                                      text line in ib[]
153  *              lfile   *cfp            The pointer *cfp points to the
154  *                                      current lfile structure
155  *              char    ctype[]         array of character types, one per
156  *                                      ASCII character
157  *              lfile   *filep          The pointer *filep points to the
158  *                                      beginning of a linked list of
159  *                                      lfile structures.
160  *              head    *hp             Pointer to the current
161  *                                      head structure
162  *              char    ib[NINPUT]      .rel file text line
163  *              char    *ip             pointer into the .rel file
164  *              lfile   *linkp          pointer to first lfile structure
165  *                                      containing an input .rel file
166  *                                      specification
167  *              int     lkerr           error flag
168  *              int     oflag           Output file type flag
169  *              int     objflg          Linked file/library output object flag
170  *              int     pass            linker pass number
171  *              int     pflag           print linker command file flag
172  *              int     radix           current number conversion radix
173  *              FILE    *sfp            The file handle sfp points to the
174  *                                      currently open file
175  *              lfile   *startp         aslink startup file structure
176  *              FILE *  stdout          c_library
177  *
178  *      functions called:
179  *              VOID    chkbank()       lkbank.c
180  *              int     fclose()        c_library
181  *              int     fprintf()       c_library
182  *              VOID    library()       lklibr.c
183  *              VOID    link_main()     lkmain.c
184  *              VOID    lkexit()        lkmain.c
185  *              VOID    lkfopen()       lkbank.c
186  *              VOID    lnkarea()       lkarea.c
187  *              VOID    map()           lkmain.c
188  *              VOID    new()           lksym.c
189  *              int     nxtline()       lklex.c
190  *              int     parse()         lkmain.c
191  *              VOID    reloc()         lkreloc.c
192  *              VOID    search()        lklibr.c
193  *              VOID    setarea()       lkarea.c
194  *              VOID    setbank()       lkbank.c
195  *              VOID    setgbl()        lkmain.c
196  *              char *  sprintf()       c_library
197  *              VOID    symdef()        lksym.c
198  *              VOID    usage()         lkmain.c
199  *              int     fndidx()        lkmain.c
200  *
201  *      side effects:
202  *              Completion of main() completes the linking process
203  *              and may produce a map file (.map) and/or a linked
204  *              data files (.ihx or .s19) and/or one or more
205  *              relocated listing files (.rst).
206  */
207 
208 int
main(int argc,char * argv[])209 main(int argc, char *argv[])
210 {
211         int c, i, j, k;
212 
213         if (intsiz() < 4) {
214                 fprintf(stderr, "?ASlink-Error-Size of INT32 is not 32 bits or larger.\n\n");
215                 exit(ER_FATAL);
216         }
217 
218         /* sdas specific */
219         /* sdas initialization */
220         sdld_init(argv[0]);
221 
222         /* use these defaults for parsing the .lnk script */
223         a_bytes = 4;
224         a_mask = 0xFFFFFFFF;
225         s_mask = 0x80000000;
226         v_mask = 0x7FFFFFFF;
227         /* end sdas specific */
228 
229         if (!is_sdld())
230                 fprintf(stdout, "\n");
231 
232         startp = (struct lfile *) new (sizeof (struct lfile));
233         startp->f_idp = "";
234 
235         pflag = 1;
236 
237         for(i=1; i<argc; i++) {
238                 ip = ib;
239                 if(argv[i][0] == '-') {
240                         j = i;
241                         k = 1;
242                         while((c = argv[j][k]) != '\0') {
243                                 ip = ib;
244                                 sprintf(ip, "-%c", c);
245                                 switch(c) {
246 
247                                 /*
248                                  * Options with arguments
249                                  */
250                                 case 'b':
251                                 case 'B':
252 
253                                 case 'g':
254                                 case 'G':
255 
256                                 case 'k':
257                                 case 'K':
258 
259                                 case 'l':
260                                 case 'L':
261 
262                                 case 'f':
263                                 case 'F':
264 
265                                 case 'I':
266                                 case 'X':
267                                 case 'C':
268                                 case 'S':
269                                         strcat(ip, " ");
270                                         if (i < argc - 1)
271                                                 strcat(ip, argv[++i]);
272 					else
273                                                 strcpy(ip, "");
274                                         break;
275                                 /*
276                                  * Preprocess these commands
277                                  */
278                                 case 'n':
279                                 case 'N':
280                                         pflag = 0;
281                                         break;
282 
283                                 case 'p':
284                                 case 'P':
285                                         pflag = 1;
286                                         break;
287 
288                                 /*
289                                  * Options without arguments
290                                  */
291                                 default:
292                                         break;
293                                 }
294                                 if(pflag)
295                                         fprintf(stdout, "ASlink >> %s\n", ip);
296                                 parse();
297                                 k++;
298                         }
299                 } else {
300                         strcpy(ip, argv[i]);
301                         if(pflag)
302                                 fprintf(stdout, "ASlink >> %s\n", ip);
303                         parse();
304                 }
305         }
306 
307         if (linkp == NULL)
308                 usage(ER_FATAL);
309 
310         /*
311          * If no input file is specified
312          * then assume a single file with
313          * the same name as the output file.
314          */
315         if (lfp == linkp) {
316                 lfp->f_flp = (struct lfile *) new (sizeof (struct lfile));
317                 lfp = lfp->f_flp;
318                 lfp->f_idp = strsto(linkp->f_idp);
319                 lfp->f_idx = fndidx(linkp->f_idp);
320                 lfp->f_obj = objflg;
321                 lfp->f_type = F_REL;
322         }
323 
324         syminit();
325 
326 #if SDCDB
327         /*
328          * Open SDCC Debug output file
329          */
330         SDCDBfopen();
331 #endif
332 
333         for (pass=0; pass<2; ++pass) {
334                 cfp = NULL;
335                 sfp = NULL;
336                 filep = linkp->f_flp;
337                 hp = NULL;
338                 radix = 10;
339 
340                 /* sdld specific */
341                 if (TARGET_IS_8051)
342                         Areas51(); /*JCF: Create the default 8051 areas in the right order*/
343                 /* end sdld specific */
344 
345                 while (nxtline()) {
346                         ip = ib;
347                         link_main();
348                 }
349                 if (pass == 0) {
350                         /*
351                          * Search libraries for global symbols
352                          */
353                         search();
354 
355                         /* sdas specific */
356                         /* use these defaults for parsing the .lk script */
357                         a_bytes = 4;
358                         a_mask = 0xFFFFFFFF;
359                         s_mask = 0x80000000;
360                         v_mask = 0x7FFFFFFF;
361                         /* end sdas specific */
362 
363                         /*
364                          * Set area base addresses.
365                          */
366                         setarea();
367                         /*
368                          * Set bank base addresses.
369                          */
370                         setbank();
371                         /*
372                          * Link all area addresses.
373                          */
374                         if (!packflag)
375                                 lnkarea();
376                         else {
377                                 /* sdld 8051 specific */
378                                 lnkarea2();
379                                 /* end sdld 8051 specific */
380                         }
381                         /*
382                          * Check bank size limits.
383                          */
384                         chkbank(stderr);
385                         /*
386                          * Process global definitions.
387                          */
388                         setgbl();
389                         /*
390                          * Check for undefined globals.
391                          */
392                         symdef(stderr);
393 #if NOICE
394                         /*
395                          * Open NoICE output file
396                          */
397                         NoICEfopen();
398 #endif
399                         /*
400                          * Output Link Map.
401                          */
402                         map();
403 
404                         /* sdld specific */
405                         if (sflag) {    /*JCF: memory usage summary output*/
406                                 if (!packflag) {
407                                         if (summary(areap)) lkexit(1);
408                                 }
409                                 else {
410                                         /* sdld 8051 specific */
411                                         if (summary2(areap)) lkexit(1);
412                                         /* end sdld 8051 specific */
413                                 }
414                         }
415 
416                         if ((iram_size) && (!packflag))
417                                 iramcheck();
418 
419                         /* end sdld specific */
420 
421                         /*
422                          * Open output file(s)
423                          */
424                         lkfopen();
425                 } else {
426                         /*
427                          * Link in library files
428                          */
429                         library();
430                         /*
431                          * Complete Processing
432                          */
433                         reloc('E');
434                 }
435         }
436 
437         if (TARGET_IS_PDK && get_sdld_target() != TARGET_ID_PDK) {
438                 unsigned ram = 0;
439                 unsigned rom = 0;
440                 for (struct area *it = areap; it; it = it->a_ap) {
441                         if (!strcmp(it->a_id, "DATA") ||
442                             !strcmp(it->a_id, "OSEG")) {
443                                 if (it->a_addr + it->a_size > ram) {
444                                         ram = it->a_addr + it->a_size;
445                                 }
446                         } else if (!strcmp(it->a_id, "CODE") ||
447                                    !strcmp(it->a_id, "CONST")) {
448                                 if (it->a_addr + it->a_size > rom) {
449                                         rom = it->a_addr + it->a_size;
450                                 }
451                         }
452                 }
453 
454                 enum sdld_target_e target = get_sdld_target();
455                 const unsigned max_ram =
456                     target == TARGET_ID_PDK13 ? 64 :
457                     target == TARGET_ID_PDK14 ? 128 : 256;
458                 const unsigned max_rom =
459                     target == TARGET_ID_PDK13 ? 2048 :
460                     target == TARGET_ID_PDK14 ? 4096 : 8192;
461                 if (ram > max_ram) {
462                         fprintf(stderr,
463                                 "?ASlink-Warning-"
464                                 "RAM value %u too large "
465                                 "(%uB max)\n", ram, max_ram);
466                 }
467                 if (rom > max_rom) {
468                         fprintf(stderr,
469                                 "?ASlink-Warning-"
470                                 "ROM value %u too large "
471                                 "(%uW max)\n", rom / 2, max_rom / 2);
472                 }
473         }
474         if (TARGET_IS_8051) {
475                 //JCF:
476                 CreateAOMF51();
477         }
478 
479         lkexit(lkerr ? ER_ERROR : ER_NONE);
480         return(0);
481 }
482 
483 /*)Function     int     intsiz()
484  *
485  *      The function intsiz() returns the size of INT32
486  *
487  *      local variables:
488  *              none
489  *
490  *      global variables:
491  *              none
492  *
493  *      functions called:
494  *              none
495  *
496  *      side effects:
497  *              none
498  */
499 
500 int
intsiz()501 intsiz()
502 {
503         return(sizeof(a_uint));
504 }
505 
506 /*)Function     VOID    lkexit(i)
507  *
508  *                      int     i       exit code
509  *
510  *      The function lkexit() explicitly closes all open
511  *      files and then terminates the program.
512  *
513  *      local variables:
514  *              none
515  *
516  *      global variables:
517  *              FILE *  jfp             file handle for .noi
518  *              FILE *  mfp             file handle for .map
519  *              FILE *  rfp             file hanlde for .rst
520  *              FILE *  sfp             file handle for .rel
521  *              FILE *  tfp             file handle for .lst
522  *
523  *      functions called:
524  *              int     fclose()        c_library
525  *              VOID    exit()          c_library
526  *              VOID    lkfclose()      lkbank.c
527  *
528  *      side effects:
529  *              All files closed. Program terminates.
530  */
531 
532 VOID
lkexit(i)533 lkexit(i)
534 int i;
535 {
536         lkfclose();
537 #if NOICE
538         if (jfp != NULL) fclose(jfp);
539 #endif
540         if (mfp != NULL) fclose(mfp);
541         if (rfp != NULL) fclose(rfp);
542         if (sfp != NULL) { if (sfp != stdin) fclose(sfp); }
543         if (tfp != NULL) fclose(tfp);
544 #if SDCDB
545         if (yfp != NULL) fclose(yfp);
546 #endif
547         exit(i);
548 }
549 
550 /*)Function     link_main()
551  *
552  *      The function link_main() evaluates the directives for each line of
553  *      text read from the .rel file(s).  The valid directives processed
554  *      are:
555  *              X, D, Q, H, M, A, S, T, R, and P.
556  *
557  *      local variables:
558  *              int     c               first non blank character of a line
559  *
560  *      global variables:
561  *              head    *headp          The pointer to the first
562  *                                      head structure of a linked list
563  *              head    *hp             Pointer to the current
564  *                                      head structure
565  *              int     a_bytes         T Line address bytes
566  *              int     hilo            Byte ordering
567  *              int     pass            linker pass number
568  *              int     radix           current number conversion radix
569  *
570  *      functions called:
571  *              char    endline()       lklex.c
572  *              VOID    module()        lkhead.c
573  *              VOID    newarea()       lkarea.c
574  *              VOID    newhead()       lkhead.c
575  *              sym *   newsym()        lksym.c
576  *              VOID    NoICEmagic()    lknoice.c
577  *              VOID    reloc()         lkreloc.c
578  *
579  *      side effects:
580  *              Head, area, and symbol structures are created and
581  *              the radix is set as the .rel file(s) are read.
582  */
583 
584 VOID
link_main()585 link_main()
586 {
587         char c;
588 
589         if ((c=endline()) == 0) { return; }
590         switch (c) {
591 
592         /* sdld specific */
593         case 'O': /* For some important sdcc options */
594                 if (is_sdld() && pass == 0) {
595                         if (NULL == optsdcc) {
596                                 optsdcc = strsto(&ip[1]);
597                                 optsdcc_module = hp->m_id;
598                         }
599                         else {
600                                 if (strcmp(optsdcc, &ip[1]) != 0) {
601                                         fprintf(stderr,
602                                                 "?ASlink-Warning-Conflicting sdcc options:\n"
603                                                 "   \"%s\" in module \"%s\" and\n"
604                                                 "   \"%s\" in module \"%s\".\n",
605                                                 optsdcc, optsdcc_module, &ip[1], hp->m_id);
606                                         lkerr++;
607                                 }
608                         }
609                 }
610                 break;
611         /* end sdld specific */
612 
613         case 'X':
614         case 'D':
615         case 'Q':
616                 ASxxxx_VERSION = 3;
617                 a_bytes = 2;    /* use default if unspecified */
618                 hilo = 0;       /* use default if unspecified */
619                 if (c == 'X') { radix = 16; } else
620                 if (c == 'D') { radix = 10; } else
621                 if (c == 'Q') { radix = 8;  }
622 
623                 while ((c = get()) != 0) {
624                         switch(c) {
625                         case 'H':
626                                 hilo = 1;
627                                 break;
628 
629                         case 'L':
630                                 hilo = 0;
631                                 break;
632 
633                         case '2':
634                                 a_bytes = 2;
635                                 break;
636 
637                         case '3':
638                                 a_bytes = 3;
639                                 break;
640 
641                         case '4':
642                                 a_bytes = 4;
643                                 break;
644 
645                         default:
646                                 break;
647                         }
648                 }
649 #ifdef  LONGINT
650                 switch(a_bytes) {
651                 default:
652                         a_bytes = 2;
653                 case 2:
654                         a_mask = 0x0000FFFFl;
655                         s_mask = 0x00008000l;
656                         v_mask = 0x00007FFFl;
657                         break;
658 
659                 case 3:
660                         a_mask = 0x00FFFFFFl;
661                         s_mask = 0x00800000l;
662                         v_mask = 0x007FFFFFl;
663                         break;
664 
665                 case 4:
666                         a_mask = 0xFFFFFFFFl;
667                         s_mask = 0x80000000l;
668                         v_mask = 0x7FFFFFFFl;
669                         break;
670                 }
671 #else
672                 switch(a_bytes) {
673                 default:
674                         a_bytes = 2;
675                 case 2:
676                         a_mask = 0x0000FFFF;
677                         s_mask = 0x00008000;
678                         v_mask = 0x00007FFF;
679                         break;
680 
681                 case 3:
682                         a_mask = 0x00FFFFFF;
683                         s_mask = 0x00800000;
684                         v_mask = 0x007FFFFF;
685                         break;
686 
687                 case 4:
688                         a_mask = 0xFFFFFFFF;
689                         s_mask = 0x80000000;
690                         v_mask = 0x7FFFFFFF;
691                         break;
692                 }
693 #endif
694                 break;
695 
696         case 'H':
697                 if (pass == 0) {
698                         newhead();
699                 } else {
700                         if (hp == 0) {
701                                 hp = headp;
702                         } else {
703                                 hp = hp->h_hp;
704                         }
705                 }
706                 sdp.s_area = NULL;
707                 sdp.s_areax = NULL;
708                 sdp.s_addr = 0;
709                 break;
710 
711         case 'M':
712                 if (pass == 0)
713                         module();
714                 break;
715 
716         case 'A':
717                 if (pass == 0)
718                         newarea();
719                 if (sdp.s_area == NULL) {
720                         sdp.s_area = areap;
721                         sdp.s_areax = areap->a_axp;
722                         sdp.s_addr = 0;
723                 }
724                 break;
725 
726         case 'S':
727                 if (pass == 0)
728                         newsym();
729                 break;
730 
731         case 'T':
732         case 'R':
733         case 'P':
734                 if (pass == 0)
735                         break;
736                 reloc(c);
737                 break;
738 
739 #if NOICE
740         case ';':
741                 unget(c);
742                 NoICEmagic();
743                 break;
744 #endif
745 
746         default:
747                 break;
748         }
749 }
750 
751 /*)Function     VOID    map()
752  *
753  *      The function map() opens the output map file and calls the various
754  *      routines to
755  *      (1) output the variables in each area,
756  *      (2) list the files processed with module names,
757  *      (3) list the libraries file processed,
758  *      (4) list base address definitions,
759  *      (5) list global variable definitions, and
760  *      (6) list any undefined variables.
761  *
762  *      local variables:
763  *              int     i               counter
764  *              head *  hdp             pointer to head structure
765  *              lbfile *lbfh            pointer to library file structure
766  *
767  *      global variables:
768  *              area    *ap             Pointer to the current
769  *                                      area structure
770  *              area    *areap          The pointer to the first
771  *                                      area structure of a linked list
772  *              base    *basep          The pointer to the first
773  *                                      base structure
774  *              base    *bsp            Pointer to the current
775  *                                      base structure
776  *              lfile   *filep          The pointer *filep points to the
777  *                                      beginning of a linked list of
778  *                                      lfile structures.
779  *              globl   *globlp         The pointer to the first
780  *                                      globl structure
781  *              globl   *gsp            Pointer to the current
782  *                                      globl structure
783  *              head    *headp          The pointer to the first
784  *                                      head structure of a linked list
785  *              lbfile  *lbfhead        The pointer to the first
786  *                                      lbfile structure of a linked list
787  *              lfile   *linkp          pointer to first lfile structure
788  *                                      containing an input REL file
789  *                                      specification
790  *              int     lop             current line number on page
791  *              int     mflag           Map output flag
792  *              FILE    *mfp            Map output file handle
793  *              int     page            current page number
794  *
795  *      functions called:
796  *              FILE *  afile()         lkmain.c
797  *              int     fprintf()       c_library
798  *              VOID    lkexit()        lkmain.c
799  *              VOID    lstarea()       lklist.c
800  *              VOID    newpag()        lklist.c
801  *              VOID    chkbank()       lkbank.c
802  *              VOID    symdef()        lksym.c
803  *
804  *      side effects:
805  *              The map file is created.
806  */
807 
808 VOID
map(void)809 map(void)
810 {
811         int i;
812         struct head *hdp;
813         struct lbfile *lbfh;
814 
815         if (mflag == 0) return;
816 
817         /*
818          * Open Map File
819          */
820         mfp = afile(linkp->f_idp, "map", 1);
821         if (mfp == NULL) {
822                 lkexit(ER_FATAL);
823         }
824 
825         /*
826          * Output Map Bank/Area Lists
827          */
828         page = 0;
829         lop  = NLPP;
830         for (bp = bankp; bp != NULL; bp = bp->b_bp) {
831                 for (ap = areap; ap != NULL; ap = ap->a_ap) {
832                         if (ap->a_bp == bp)
833                                 lstarea(ap, bp);
834                 }
835         }
836 
837         /*
838          * List Linked Files
839          */
840         newpag(mfp);
841         fprintf(mfp, "\nFiles Linked                              [ module(s) ]\n\n");
842         hdp = headp;
843         filep = linkp->f_flp;
844         while (filep) {
845                 if (strlen (filep->f_idp) > 40)
846                         fprintf(mfp, "%s\n%40s  [ ", filep->f_idp, "");
847                 else
848                         fprintf(mfp, "%-40.40s  [ ", filep->f_idp);
849                 i = 0;
850                 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
851                         if (i)
852                                 fprintf(mfp, ",\n%44s", "");
853                         fprintf(mfp, "%-.32s", hdp->m_id);
854                         hdp = hdp->h_hp;
855                         i++;
856                 }
857                 fprintf(mfp, " ]\n");
858                 filep = filep->f_flp;
859         }
860         fprintf(mfp, "\n");
861         /*
862          * List Linked Libraries
863          */
864         if (lbfhead != NULL) {
865                 fprintf(mfp, "\nLibraries Linked                          [ object file ]\n\n");
866                 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
867                         if (strlen (lbfh->libspc) > 40)
868                                 fprintf(mfp, "%s\n%40s  [ %-.32s ]\n",
869                                         lbfh->libspc, "", lbfh->relfil);
870                         else
871                                 fprintf(mfp, "%-40.40s  [ %-.32s ]\n",
872                                         lbfh->libspc, lbfh->relfil);
873                 }
874                 fprintf(mfp, "\n");
875         }
876         /*
877          * List Base Address Definitions
878          */
879         if (basep) {
880                 newpag(mfp);
881                 fprintf(mfp, "\nUser Base Address Definitions\n\n");
882                 bsp = basep;
883                 while (bsp) {
884                         fprintf(mfp, "%s\n", bsp->b_strp);
885                         bsp = bsp->b_base;
886                 }
887         }
888         /*
889          * List Global Definitions
890          */
891         if (globlp) {
892                 newpag(mfp);
893                 fprintf(mfp, "\nUser Global Definitions\n\n");
894                 gsp = globlp;
895                 while (gsp) {
896                         fprintf(mfp, "%s\n", gsp->g_strp);
897                         gsp = gsp->g_globl;
898                 }
899         }
900         fprintf(mfp, "\n\f");
901         chkbank(mfp);
902         symdef(mfp);
903 }
904 
905 /*)Function     int     parse()
906  *
907  *      The function parse() evaluates all command line or file input
908  *      linker directives and updates the appropriate variables.
909  *
910  *      local variables:
911  *              int     c               character value
912  *              int     sv_type         save type of processing
913  *              char    fid[]           file id string
914  *
915  *      global variables:
916  *              char    ctype[]         array of character types, one per
917  *                                      ASCII character
918  *              lfile   *lfp            pointer to current lfile structure
919  *                                      being processed by parse()
920  *              lfile   *linkp          pointer to first lfile structure
921  *                                      containing an input REL file
922  *                                      specification
923  *              int     mflag           Map output flag
924  *              int     oflag           Output file type flag
925  *              int     objflg          Linked file/library output object flag
926  *              int     pflag           print linker command file flag
927  *              FILE *  stderr          c_library
928  *              int     uflag           Relocated listing flag
929  *              int     xflag           Map file radix type flag
930  *              int     wflag           Wide listing format
931  *              int     zflag           Disable symbol case sensitivity
932  *
933  *      Functions called:
934  *              VOID    addlib()        lklibr.c
935  *              VOID    addpath()       lklibr.c
936  *              VOID    bassav()        lkmain.c
937  *              VOID    doparse()       lkmain.c
938  *              int     fprintf()       c_library
939  *              VOID    gblsav()        lkmain.c
940  *              VOID    getfid()        lklex.c
941  *              int     get()           lklex.c
942  *              int     getnb()         lklex.c
943  *              VOID    lkexit()        lkmain.c
944  *              char *  strsto()        lksym.c
945  *              int     strlen()        c_library
946  *              int     fndidx()        lkmain.c
947  *
948  *      side effects:
949  *              Various linker flags are updated and the linked
950  *              structure lfile is created.
951  */
952 
953 int
parse()954 parse()
955 {
956         int c;
957         int sv_type;
958         char fid[NINPUT];
959 
960         while ((c = getnb()) != 0) {
961                 /* sdld specific */
962                 if ( c == ';')
963                         return(0);
964                 /* end sdld specific */
965                 if ( c == '-') {
966                         while (ctype[c=get()] & LETTER) {
967                                 switch(c) {
968 
969                                 case 'C':
970                                         if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
971                                                 codesav();
972                                                 return(0);
973                                         }
974                                         // else fall through
975                                 case 'c':
976                                         if (startp->f_type != 0)
977                                                 break;
978                                         startp->f_type = F_STD;
979                                         doparse();
980                                         return(0);
981 
982                                 case 'f':
983                                 case 'F':
984                                         if (startp->f_type == F_LNK)
985                                                 return(0);
986                                         unget(getnb());
987                                         if (*ip == 0)
988                                                 usage(ER_FATAL);
989                                         sv_type = startp->f_type;
990                                         startp->f_idp = strsto(ip);
991                                         startp->f_idx = fndidx(ip);
992                                         startp->f_type = F_LNK;
993                                         doparse();
994                                         if (sv_type == F_STD) {
995                                                 cfp = NULL;
996                                                 sfp = NULL;
997                                                 startp->f_type = F_STD;
998                                                 filep = startp;
999                                         }
1000                                         return(0);
1001 
1002                                 case 'I':
1003                                         if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
1004                                                 iramsav();
1005                                                 return(0);
1006                                         }
1007                                         // else fall through
1008                                 case 'i':
1009                                         oflag = 1;
1010                                         break;
1011 
1012                                 case 'S':
1013                                         if (TARGET_IS_8051) {
1014                                                 unget(getnb());
1015                                                 if (ip && *ip)
1016                                                 {
1017                                                         stacksize = expr(0);
1018                                                         if (stacksize > 256) stacksize = 256;
1019                                                         else if (stacksize < 0) stacksize = 0;
1020                                                 }
1021                                                 return(0);
1022                                         }
1023                                         // else fall through
1024                                 case 's':
1025                                         oflag = 2;
1026                                         break;
1027 
1028                                 case 't':
1029                                 case 'T':
1030                                         oflag = 3;
1031                                         break;
1032 
1033                                 case 'o':
1034                                 case 'O':
1035                                         objflg = 0;
1036                                         break;
1037 
1038                                 case 'v':
1039                                 case 'V':
1040                                         objflg = 1;
1041                                         break;
1042 
1043                                 case 'M':
1044                                         /*JCF: memory usage summary output*/
1045                                         if (is_sdld()) {
1046                                                 sflag = 1;
1047                                                 break;
1048                                         }
1049                                         // else fall through
1050                                 case 'm':
1051                                         mflag = 1;
1052                                         break;
1053 
1054 #if NOICE
1055                                 case 'j':
1056                                 case 'J':
1057                                         jflag = 1;
1058                                         break;
1059 #endif
1060 
1061                                 case 'r':
1062                                 case 'R':
1063                                         if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB))
1064                                                 rflag = 1;
1065                                         else
1066                                                 goto err;
1067                                         break;
1068 
1069                                 case 'u':
1070                                 case 'U':
1071                                         uflag = 1;
1072                                         break;
1073 
1074                                 case 'X':
1075                                         if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
1076                                                 xramsav();
1077                                                 return(0);
1078                                         }
1079                                         // else fall through
1080                                 case 'x':
1081                                         xflag = 0;
1082                                         break;
1083 
1084                                 case 'q':
1085                                 case 'Q':
1086                                         xflag = 1;
1087                                         break;
1088 
1089                                 case 'd':
1090                                 case 'D':
1091                                         xflag = 2;
1092                                         break;
1093 
1094                                 case 'E':
1095                                         if (TARGET_IS_6808 || TARGET_IS_STM8) {
1096                                                 oflag = 4;
1097                                                 break;
1098                                         }
1099                                         // else fall through
1100                                 case 'e':
1101                                         return(1);
1102 
1103                                 case 'n':
1104                                 case 'N':
1105                                         pflag = 0;
1106                                         break;
1107 
1108                                 case 'p':
1109                                 case 'P':
1110                                         pflag = 1;
1111                                         break;
1112 
1113                                 case 'b':
1114                                 case 'B':
1115                                         bassav();
1116                                         return(0);
1117 
1118                                 case 'g':
1119                                 case 'G':
1120                                         gblsav();
1121                                         return(0);
1122 
1123                                 case 'k':
1124                                 case 'K':
1125                                         addpath();
1126                                         return(0);
1127 
1128                                 case 'l':
1129                                 case 'L':
1130                                         addlib();
1131                                         return(0);
1132 
1133                                 case 'w':
1134                                 case 'W':
1135                                         wflag = 1;
1136                                         break;
1137 
1138 #if SDCDB
1139                                 case 'Y':
1140                                         if (TARGET_IS_8051) {
1141                                                 unget(getnb());
1142                                                 packflag=1;
1143                                                 break;
1144                                         }
1145                                         // else fall through
1146                                 case 'y':
1147                                         yflag = 1;
1148                                         break;
1149 #endif
1150 
1151                                 case 'z':
1152                                 case 'Z':
1153                                         zflag = 1;
1154                                         break;
1155 
1156                                 default:
1157                                 err:
1158                                         fprintf(stderr,
1159                                             "Unknown option -%c ignored\n", c);
1160                                         break;
1161                                 }
1162                         }
1163                         /* sdld specific */
1164                         if ( c == ';')
1165                                 return(0);
1166                         /* end sdld specific */
1167                 } else
1168                 if (!(ctype[c] & ILL)) {
1169                         if (linkp == NULL) {
1170                                 linkp = (struct lfile *)
1171                                         new (sizeof (struct lfile));
1172                                 lfp = linkp;
1173                                 lfp->f_type = F_OUT;
1174                         } else {
1175                                 lfp->f_flp = (struct lfile *)
1176                                                 new (sizeof (struct lfile));
1177                                 lfp = lfp->f_flp;
1178                                 lfp->f_type = F_REL;
1179                         }
1180                         getfid(fid, c);
1181                         lfp->f_idp = strsto(fid);
1182                         lfp->f_obj = objflg;
1183                 } else {
1184                         fprintf(stderr, "Invalid input\n");
1185                         lkexit(ER_FATAL);
1186                 }
1187         }
1188         return(0);
1189 }
1190 
1191 /*)Function     VOID    doparse()
1192  *
1193  *      The function doparse() evaluates all interactive
1194  *      command line or file input linker directives and
1195  *      updates the appropriate variables.
1196  *
1197  *      local variables:
1198  *              none
1199  *
1200  *      global variables:
1201  *              FILE *  stdin           standard input
1202  *              FILE *  stdout          standard output
1203  *              lfile   *cfp            The pointer *cfp points to the
1204  *                                      current lfile structure
1205  *              FILE    *sfp            The file handle sfp points to the
1206  *                                      currently open file
1207  *              char    ib[NINPUT]      .rel file text line
1208  *              char    *ip             pointer into the .rel file
1209  *              lfile   *filep          The pointer *filep points to the
1210  *                                      beginning of a linked list of
1211  *                                      lfile structures.
1212  *              lfile   *startp         asmlnk startup file structure
1213  *              int     pflag           print linker command file flag
1214  *
1215  *      Functions called:
1216  *              int     fclose()        c_library
1217  *              int     fprintf()       c_library
1218  *              VOID    getfid()        lklex.c
1219  *              int     nxtline()       lklex.c
1220  *              int     parse()         lkmain.c
1221  *
1222  *      side effects:
1223  *              Various linker flags are updated and the linked
1224  *              structure lfile may be updated.
1225  */
1226 
1227 VOID
doparse()1228 doparse()
1229 {
1230         cfp = NULL;
1231         sfp = NULL;
1232         filep = startp;
1233         while (1) {
1234                 ip = ib;
1235                 if (nxtline() == 0)
1236                         break;
1237                 if (pflag && cfp->f_type != F_STD)
1238                         fprintf(stdout, "ASlink >> %s\n", ip);
1239                 if (*ip == 0 || parse())
1240                         break;
1241         }
1242         if((sfp != NULL) && (sfp != stdin)) {
1243                 fclose(sfp);
1244         }
1245         sfp = NULL;
1246         startp->f_idp = "";
1247         startp->f_idx = 0;
1248         startp->f_type = 0;
1249 }
1250 
1251 /*)Function     VOID    bassav()
1252  *
1253  *      The function bassav() creates a linked structure containing
1254  *      the base address strings input to the linker.
1255  *
1256  *      local variables:
1257  *              none
1258  *
1259  *      global variables:
1260  *              base    *basep          The pointer to the first
1261  *                                      base structure
1262  *              base    *bsp            Pointer to the current
1263  *                                      base structure
1264  *              char    *ip             pointer into the REL file
1265  *                                      text line in ib[]
1266  *
1267  *       functions called:
1268  *              int     getnb()         lklex.c
1269  *              VOID *  new()           lksym.c
1270  *              int     strlen()        c_library
1271  *              char *  strcpy()        c_library
1272  *              VOID    unget()         lklex.c
1273  *
1274  *      side effects:
1275  *              The basep structure is created.
1276  */
1277 
1278 VOID
bassav()1279 bassav()
1280 {
1281         if (basep == NULL) {
1282                 basep = (struct base *)
1283                         new (sizeof (struct base));
1284                 bsp = basep;
1285         } else {
1286                 bsp->b_base = (struct base *)
1287                                 new (sizeof (struct base));
1288                 bsp = bsp->b_base;
1289         }
1290         unget(getnb());
1291         bsp->b_strp = (char *) new (strlen(ip)+1);
1292         strcpy(bsp->b_strp, ip);
1293 }
1294 
1295 
1296 /*)Function     VOID    gblsav()
1297  *
1298  *      The function gblsav() creates a linked structure containing
1299  *      the global variable strings input to the linker.
1300  *
1301  *      local variable:
1302  *              none
1303  *
1304  *      global variables:
1305  *              globl   *globlp         The pointer to the first
1306  *                                      globl structure
1307  *              globl   *gsp            Pointer to the current
1308  *                                      globl structure
1309  *              char    *ip             pointer into the REL file
1310  *                                      text line in ib[]
1311  *              int     lkerr           error flag
1312  *
1313  *      functions called:
1314  *              int     getnb()         lklex.c
1315  *              VOID *  new()           lksym.c
1316  *              int     strlen()        c_library
1317  *              char *  strcpy()        c_library
1318  *              VOID    unget()         lklex.c
1319  *
1320  *      side effects:
1321  *              The globlp structure is created.
1322  */
1323 
1324 VOID
gblsav()1325 gblsav()
1326 {
1327         if (globlp == NULL) {
1328                 globlp = (struct globl *)
1329                         new (sizeof (struct globl));
1330                 gsp = globlp;
1331         } else {
1332                 gsp->g_globl = (struct globl *)
1333                                 new (sizeof (struct globl));
1334                 gsp = gsp->g_globl;
1335         }
1336         unget(getnb());
1337         gsp->g_strp = (char *) new (strlen(ip)+1);
1338         strcpy(gsp->g_strp, ip);
1339 }
1340 
1341 
1342 /*)Function     VOID    setgbl()
1343  *
1344  *      The function setgbl() scans the global variable lines in the
1345  *      globlp structure, evaluates the arguments, and sets a variable
1346  *      to this value.
1347  *
1348  *      local variables:
1349  *              int     v               expression value
1350  *              char    id[]            base id string
1351  *              sym *   sp              pointer to a symbol structure
1352  *
1353  *      global variables:
1354  *              char    *ip             pointer into the REL file
1355  *                                      text line in ib[]
1356  *              globl   *globlp         The pointer to the first
1357  *                                      globl structure
1358  *              globl   *gsp            Pointer to the current
1359  *                                      globl structure
1360  *              FILE *  stderr          c_library
1361  *              int     lkerr           error flag
1362  *
1363  *       functions called:
1364  *              a_uint  expr()          lkeval.c
1365  *              int     fprintf()       c_library
1366  *              VOID    getid()         lklex.c
1367  *              int     getnb()         lklex.c
1368  *              sym *   lkpsym()        lksym.c
1369  *
1370  *      side effects:
1371  *              The value of a variable is set.
1372  */
1373 
1374 VOID
setgbl()1375 setgbl()
1376 {
1377         int v;
1378         struct sym *sp;
1379         char id[NCPS];
1380 
1381         gsp = globlp;
1382         while (gsp) {
1383                 ip = gsp->g_strp;
1384                 getid(id, -1);
1385                 if (getnb() == '=') {
1386                         v = (int) expr(0);
1387                         sp = lkpsym(id, 0);
1388                         if (sp == NULL) {
1389                                 fprintf(stderr,
1390                                 "No definition of symbol %s\n", id);
1391                                 lkerr++;
1392                         } else {
1393                                 if (sp->s_type & S_DEF) {
1394                                         fprintf(stderr,
1395                                         "Redefinition of symbol %s\n", id);
1396                                         lkerr++;
1397                                         sp->s_axp = NULL;
1398                                 }
1399                                 sp->s_addr = v;
1400                                 sp->s_type |= S_DEF;
1401                         }
1402                 } else {
1403                         fprintf(stderr, "No '=' in global expression");
1404                         lkerr++;
1405                 }
1406                 gsp = gsp->g_globl;
1407         }
1408 }
1409 
1410 /*)Function     FILE *  afile(fn, ft, wf)
1411  *
1412  *              char *  fn              file specification string
1413  *              char *  ft              file type string
1414  *              int     wf              0 ==>> read
1415  *                                      1 ==>> write
1416  *                                      2 ==>> binary write
1417  *
1418  *      The function afile() opens a file for reading or writing.
1419  *              (1)     If the file type specification string ft
1420  *                      is not NULL then a file specification is
1421  *                      constructed with the file path\name in fn
1422  *                      and the extension in ft.
1423  *              (2)     If the file type specification string ft
1424  *                      is NULL then the file specification is
1425  *                      constructed from fn.  If fn does not have
1426  *                      a file type then the default .rel file
1427  *                      type is appended to the file specification.
1428  *
1429  *      afile() returns a file handle for the opened file or aborts
1430  *      the assembler on an open error.
1431  *
1432  *      local variables:
1433  *              int     c               character value
1434  *              FILE *  fp              filehandle for opened file
1435  *              char *  p1              pointer to filespec string fn
1436  *              char *  p2              pointer to filespec string fb
1437  *              char *  p3              pointer to filetype string ft
1438  *
1439  *      global variables:
1440  *              char    afspec[]        constructed file specification string
1441  *              int     lkerr           error flag
1442  *
1443  *      functions called:
1444  *              int     fndidx()        lkmain.c
1445  *              FILE *  fopen()         c_library
1446  *              int     fprintf()       c_library
1447  *
1448  *      side effects:
1449  *              File is opened for read or write.
1450  */
1451 
1452 FILE *
afile(char * fn,char * ft,int wf)1453 afile(char *fn, char *ft, int wf)
1454 {
1455         char *p1, *p2;
1456         int c;
1457         char * frmt;
1458         FILE *fp;
1459 
1460         if (strlen(fn) > (FILSPC-7)) {
1461                 fprintf(stderr, "?ASlink-Error-<filspc too long> : \"%s\"\n", fn);
1462                 lkerr++;
1463                 return(NULL);
1464         }
1465 
1466         /*
1467          * Skip The Path
1468          */
1469         strcpy(afspec, fn);
1470         c = fndidx(afspec);
1471 
1472         /*
1473          * Skip to File Extension separator
1474          */
1475         p1 = strrchr(&afspec[c], FSEPX);
1476 
1477         /*
1478          * Copy File Extension
1479          */
1480         p2 = ft ? ft : "";
1481         if (*p2 == 0) {
1482                 if (p1 == NULL) {
1483                         p2 = LKOBJEXT;
1484                 } else {
1485                         p2 = strrchr(&fn[c], FSEPX) + 1;
1486                 }
1487         }
1488         if (p1 == NULL) {
1489                 p1 = &afspec[strlen(afspec)];
1490         }
1491         *p1++ = FSEPX;
1492         while ((c = *p2++) != 0) {
1493                 if (p1 < &afspec[FILSPC-1])
1494                         *p1++ = c;
1495         }
1496         *p1++ = 0;
1497 
1498         /*
1499          * Select Read/Write/Binary Write
1500          */
1501         switch(wf) {
1502         default:
1503         case 0: frmt = "r";     break;
1504         case 1: frmt = "w";     break;
1505 #ifdef  DECUS
1506         case 2: frmt = "wn";    break;
1507 #else
1508         case 2: frmt = "wb";    break;
1509 #endif
1510         }
1511         if ((fp = fopen(afspec, frmt)) == NULL && strcmp(ft,"adb") != 0) { /* Do not complain for optional adb files */
1512                 fprintf(stderr, "?ASlink-Error-<cannot %s> : \"%s\"\n", wf?"create":"open", afspec);
1513                 lkerr++;
1514         }
1515         return (fp);
1516 }
1517 
1518 /*)Function     int     fndidx(str)
1519  *
1520  *              char *  str             file specification string
1521  *
1522  *      The function fndidx() scans the file specification string
1523  *      to find the index to the file name.  If the file
1524  *      specification contains a 'path' then the index will
1525  *      be non zero.
1526  *
1527  *      fndidx() returns the index value.
1528  *
1529  *      local variables:
1530  *              char *  p1              temporary pointer
1531  *              char *  p2              temporary pointer
1532  *
1533  *      global variables:
1534  *              none
1535  *
1536  *      functions called:
1537  *              char *  strrchr()       c_library
1538  *
1539  *      side effects:
1540  *              none
1541  */
1542 
1543 int
fndidx(str)1544 fndidx(str)
1545 char *str;
1546 {
1547         char *p1, *p2;
1548 
1549         /*
1550          * Skip Path Delimiters
1551          */
1552         p1 = str;
1553         if ((p2 = strrchr(p1,  ':')) != NULL) { p1 = p2 + 1; }
1554         if ((p2 = strrchr(p1,  '/')) != NULL) { p1 = p2 + 1; }
1555         if ((p2 = strrchr(p1, '\\')) != NULL) { p1 = p2 + 1; }
1556 
1557         return((int) (p1 - str));
1558 }
1559 
1560 /*)Function     int     fndext(str)
1561  *
1562  *              char *  str             file specification string
1563  *
1564  *      The function fndext() scans the file specification string
1565  *      to find the file.ext separater.
1566  *
1567  *      fndext() returns the index to FSEPX or the end of the string.
1568  *
1569  *      local variables:
1570  *              char *  p1              temporary pointer
1571  *              char *  p2              temporary pointer
1572  *
1573  *      global variables:
1574  *              none
1575  *
1576  *      functions called:
1577  *              char *  strrchr()       c_library
1578  *
1579  *      side effects:
1580  *              none
1581  */
1582 
1583 int
fndext(str)1584 fndext(str)
1585 char * str;
1586 {
1587         char *p1, *p2;
1588 
1589         /*
1590          * Find the file separator
1591          */
1592         p1 = str + strlen(str);
1593         if ((p2 = strrchr(str,  FSEPX)) != NULL) { p1 = p2; }
1594 
1595         return((int) (p1 - str));
1596 }
1597 
1598 /* sdld specific */
1599 /*)Function     VOID    iramsav()
1600  *
1601  *      The function iramsav() stores the size of the chip's internal RAM.
1602  *      This is used after linking to check that variable assignment to this
1603  *      dataspace didn't overflow into adjoining segments.      Variables in the
1604  *      DSEG, OSEG, and ISEG are assigned to this dataspace.
1605  *
1606  *      local variables:
1607  *              none
1608  *
1609  *      global variables:
1610  *              char    *ip             pointer into the REL file
1611  *                                      text line in ib[]
1612  *              unsigned int            size of chip's internal
1613  *              iram_size               RAM segment
1614  *
1615  *       functions called:
1616  *              int     getnb()         lklex.c
1617  *              VOID    unget()         lklex.c
1618  *              a_uint  expr()          lkeval.c
1619  *
1620  *      side effects:
1621  *              The iram_size may be modified.
1622  */
1623 
1624 VOID
iramsav()1625 iramsav()
1626 {
1627   unget(getnb());
1628   if (ip && *ip)
1629         iram_size = expr(0);    /* evaluate size expression */
1630   else
1631         iram_size = 128;                /* Default is 128 (0x80) bytes */
1632   if ((iram_size<=0) || (iram_size>256))
1633         iram_size = 128;                /* Default is 128 (0x80) bytes */
1634 }
1635 
1636 /*Similar to iramsav but for xram memory*/
1637 VOID
xramsav()1638 xramsav()
1639 {
1640   unget(getnb());
1641   if (ip && *ip)
1642         xram_size = expr(0);    /* evaluate size expression */
1643   else
1644         xram_size = rflag?0x1000000:0x10000;
1645 }
1646 
1647 /*Similar to iramsav but for code memory*/
1648 VOID
codesav()1649 codesav()
1650 {
1651   unget(getnb());
1652   if (ip && *ip)
1653         code_size = expr(0);    /* evaluate size expression */
1654   else
1655         code_size = rflag?0x1000000:0x10000;
1656 }
1657 
1658 
1659 /*)Function     VOID    iramcheck()
1660  *
1661  *      The function iramcheck() is used at the end of linking to check that
1662  *      the internal RAM area wasn't overflowed by too many variable
1663  *      assignments.  Variables in the DSEG, ISEG, and OSEG are assigned to
1664  *      the chip's internal RAM.
1665  *
1666  *      local variables:
1667  *              none
1668  *
1669  *      global variables:
1670  *              unsigned int            size of chip's internal
1671  *              iram_size               RAM segment
1672  *              struct area             linked list of memory
1673  *              *areap                  areas
1674  *
1675  *       functions called:
1676  *
1677  *      side effects:
1678  */
1679 
1680 VOID
iramcheck()1681 iramcheck()
1682 {
1683   register unsigned int last_addr;
1684   register struct area *ap;
1685 
1686   for (ap = areap; ap; ap=ap->a_ap) {
1687         if ((ap->a_size != 0) &&
1688                 (!strcmp(ap->a_id, "DSEG") ||
1689                  !strcmp(ap->a_id, "OSEG") ||
1690                  !strcmp(ap->a_id, "ISEG")
1691                 )
1692            )
1693         {
1694           last_addr = ap->a_addr + ap->a_size - 1;
1695           if (last_addr >= iram_size)
1696                 fprintf(stderr,
1697                   "\nWARNING! Segment %s extends past the end\n"
1698                   "         of internal RAM.  Check map file.\n",
1699                   ap->a_id);
1700         }
1701   }
1702 }
1703 /* end sdld specific */
1704 
1705 char *usetxt[] = {
1706         "Usage: [-Options] [-Option with arg] file",
1707         "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
1708         "Startup:",
1709         "  -p   Echo commands to stdout (default)",
1710         "  -n   No echo of commands to stdout",
1711         "Alternates to Command Line Input:",
1712         "  -c                   ASlink >> prompt input",
1713         "  -f   file[.lk]       Command File input",
1714         "Libraries:",
1715         "  -k   Library path specification, one per -k",
1716         "  -l   Library file specification, one per -l",
1717         "Relocation:",
1718         "  -b   area base address = expression",
1719         "  -g   global symbol = expression",
1720         "Map format:",
1721         "  -m   Map output generated as (out)file[.map]",
1722         "  -w   Wide listing format for map file",
1723         "  -x   Hexadecimal (default)",
1724         "  -d   Decimal",
1725         "  -q   Octal",
1726         "Output:",
1727         "  -i   Intel Hex as (out)file[.ihx]",
1728         "  -s   Motorola S Record as (out)file[.s19]",
1729 //      "  -t   Tandy CoCo Disk BASIC binary as (out)file[.bi-]",
1730 #if NOICE
1731         "  -j   NoICE Debug output as (out)file[.noi]",
1732 #endif
1733 #if SDCDB
1734         "  -y   SDCDB Debug output as (out)file[.cdb]",
1735 #endif
1736 //      "  -o   Linked file/library object output enable (default)",
1737 //      "  -v   Linked file/library object output disable",
1738         "List:",
1739         "  -u   Update listing file(s) with link data as file(s)[.rst]",
1740         "Case Sensitivity:",
1741         "  -z   Disable Case Sensitivity for Symbols",
1742         "End:",
1743         "  -e   or null line terminates input",
1744         "",
1745         0
1746 };
1747 
1748 char *usetxt_8051[] = {
1749         "Usage: [-Options] [-Option with arg] file",
1750         "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
1751         "Startup:",
1752         "  -p   Echo commands to stdout (default)",
1753         "  -n   No echo of commands to stdout",
1754         "Alternates to Command Line Input:",
1755         "  -c                   ASlink >> prompt input",
1756         "  -f   file[.lk]       Command File input",
1757         "Libraries:",
1758         "  -k   Library path specification, one per -k",
1759         "  -l   Library file specification, one per -l",
1760         "Relocation:",
1761         "  -b   area base address = expression",
1762         "  -g   global symbol = expression",
1763         "Map format:",
1764         "  -m   Map output generated as (out)file[.map]",
1765         "  -w   Wide listing format for map file",
1766         "  -x   Hexadecimal (default)",
1767         "  -d   Decimal",
1768         "  -q   Octal",
1769         "Output:",
1770         "  -i   Intel Hex as (out)file[.ihx]",
1771         "  -s   Motorola S Record as (out)file[.s19]",
1772 #if NOICE
1773         "  -j   NoICE Debug output as (out)file[.noi]",
1774 #endif
1775 #if SDCDB
1776         "  -y   SDCDB Debug output as (out)file[.cdb]",
1777 #endif
1778         "List:",
1779         "  -u   Update listing file(s) with link data as file(s)[.rst]",
1780         "Case Sensitivity:",
1781         "  -z   Disable Case Sensitivity for Symbols",
1782         "Miscellaneous:\n"
1783         "  -I   [iram-size] Check for internal RAM overflow",
1784         "  -X   [xram-size] Check for external RAM overflow",
1785         "  -C   [code-size] Check for code overflow",
1786         "  -M   Generate memory usage summary file[.mem]",
1787         "  -Y   Pack internal ram",
1788         "  -S   [stack-size] Allocate space for stack",
1789         "End:",
1790         "  -e   or null line terminates input",
1791         "",
1792         0
1793 };
1794 
1795 char *usetxt_6808[] = {
1796         "Usage: [-Options] [-Option with arg] file",
1797         "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
1798         "Startup:",
1799         "  -p   Echo commands to stdout (default)",
1800         "  -n   No echo of commands to stdout",
1801         "Alternates to Command Line Input:",
1802         "  -c                   ASlink >> prompt input",
1803         "  -f   file[.lk]       Command File input",
1804         "Libraries:",
1805         "  -k   Library path specification, one per -k",
1806         "  -l   Library file specification, one per -l",
1807         "Relocation:",
1808         "  -b   area base address = expression",
1809         "  -g   global symbol = expression",
1810         "Map format:",
1811         "  -m   Map output generated as (out)file[.map]",
1812         "  -w   Wide listing format for map file",
1813         "  -x   Hexadecimal (default)",
1814         "  -d   Decimal",
1815         "  -q   Octal",
1816         "Output:",
1817         "  -i   Intel Hex as (out)file[.ihx]",
1818         "  -s   Motorola S Record as (out)file[.s19]",
1819         "  -E   ELF executable as file[.elf]",
1820 #if NOICE
1821         "  -j   NoICE Debug output as (out)file[.noi]",
1822 #endif
1823 #if SDCDB
1824         "  -y   SDCDB Debug output as (out)file[.cdb]",
1825 #endif
1826         "List:",
1827         "  -u   Update listing file(s) with link data as file(s)[.rst]",
1828         "Case Sensitivity:",
1829         "  -z   Disable Case Sensitivity for Symbols",
1830         "Miscellaneous:\n"
1831         "  -I   [iram-size] Check for internal RAM overflow",
1832         "  -X   [xram-size] Check for external RAM overflow",
1833         "  -C   [code-size] Check for code overflow",
1834         "  -M   Generate memory usage summary file[.mem]",
1835         "End:",
1836         "  -e   or null line terminates input",
1837         "",
1838         0
1839 };
1840 
1841 char *usetxt_z80_gb[] = {
1842         "Usage: [-Options] [-Option with arg] file",
1843         "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
1844         "Startup:",
1845         "  -p   Echo commands to stdout (default)",
1846         "  -n   No echo of commands to stdout",
1847         "Alternates to Command Line Input:",
1848         "  -c                   ASlink >> prompt input",
1849         "  -f   file[.lk]       Command File input",
1850         "Libraries:",
1851         "  -k   Library path specification, one per -k",
1852         "  -l   Library file specification, one per -l",
1853         "Relocation:",
1854         "  -b   area base address = expression",
1855         "  -g   global symbol = expression",
1856         "Map format:",
1857         "  -m   Map output generated as (out)file[.map]",
1858         "  -w   Wide listing format for map file",
1859         "  -x   Hexadecimal (default)",
1860         "  -d   Decimal",
1861         "  -q   Octal",
1862         "Output:",
1863         "  -i   Intel Hex as (out)file[.ihx]",
1864         "  -s   Motorola S Record as (out)file[.s19]",
1865 #if SDCDB
1866         "  -y   SDCDB Debug output as (out)file[.cdb]",
1867 #endif
1868         "List:",
1869         "  -u   Update listing file(s) with link data as file(s)[.rst]",
1870         "Case Sensitivity:",
1871         "  -z   Disable Case Sensitivity for Symbols",
1872         "End:",
1873         "  -e   or null line terminates input",
1874         "",
1875         0
1876 };
1877 
1878 /*)Function     VOID    usage(n)
1879  *
1880  *              int     n               exit code
1881  *
1882  *      The function usage() outputs to the stderr device the
1883  *      linker name and version and a list of valid linker options.
1884  *
1885  *      local variables:
1886  *              char ** dp              pointer to an array of
1887  *                                      text string pointers.
1888  *
1889  *      global variables:
1890  *              FILE *  stderr          c_library
1891  *
1892  *      functions called:
1893  *              int     fprintf()       c_library
1894  *
1895  *      side effects:
1896  *              none
1897  */
1898 
1899 VOID
usage(int n)1900 usage(int n)
1901 {
1902         char    **dp;
1903 
1904         /* sdld specific */
1905         fprintf(stderr, "\n%s Linker %s\n\n", is_sdld() ? "sdld" : "ASxxxx", VERSION);
1906         for (dp = TARGET_IS_8051 ? usetxt_8051 : (TARGET_IS_6808 ? usetxt_6808 : ((TARGET_IS_Z80 || TARGET_IS_GB) ? usetxt_z80_gb : usetxt)); *dp; dp++)
1907                 fprintf(stderr, "%s\n", *dp);
1908         /* end sdld specific */
1909         lkexit(n);
1910 }
1911 
1912 /*)Function     VOID    copyfile()
1913  *
1914  *              FILE    *dest           destination file
1915  *              FILE    *src            source file
1916  *
1917  *              function will copy source file to destination file
1918  *
1919  *
1920  *      functions called:
1921  *              int     fgetc()                 c_library
1922  *              int     fputc()                 c_library
1923  *
1924  *      side effects:
1925  *              none
1926  */
1927 VOID
copyfile(FILE * dest,FILE * src)1928 copyfile (FILE *dest, FILE *src)
1929 {
1930         int ch;
1931 
1932         while ((ch = fgetc(src)) != EOF) {
1933                 fputc(ch,dest);
1934         }
1935 }
1936