4 * (C) Copyright 1989-1995
12 * - add jflag and jfp to control NoICE output file genration
14 * - use a_type == 0 as "virgin area" flag: set == 1 if -b
25 * The module lkmain.c contains the functions which
26 * (1) input the linker options, parameters, and specifications
27 * (2) perform a two pass link
28 * (3) produce the appropriate linked data output and/or
29 * link map file and/or relocated listing files.
31 * lkmain.c contains the following functions:
32 * FILE * afile(fn,ft,wf)
37 * VOID main(argc,argv)
44 * lkmain.c contains the following local variables:
45 * char * usetext[] array of pointers to the
46 * command option tect lines
50 /*)Function VOID main(argc,argv)
52 * int argc number of command line arguments + 1
53 * char * argv[] array of pointers to the command line
56 * The function main() evaluates the command line arguments to
57 * determine if the linker parameters are to input through 'stdin'
58 * or read from a command file. The functiond getline() and parse()
59 * are to input and evaluate the linker parameters. The linking process
60 * proceeds by making the first pass through each .rel file in the order
61 * presented to the linker. At the end of the first pass the setbase(),
62 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
63 * the base address terms, link all areas, define global variables,
64 * and look for undefined symbols. Following these routines a linker
65 * map file may be produced and the linker output files may be opened.
66 * The second pass through the .rel files will output the linked data
67 * in one of the four supported formats.
70 * char * p pointer to an argument string
71 * int c character from argument string
76 * lfile *cfp The pointer *cfp points to the
77 * current lfile structure
78 * char ctype[] array of character types, one per
80 * lfile *filep The pointer *filep points to the
81 * beginning of a linked list of
83 * head *hp Pointer to the current
85 * char ib[NINPUT] .rel file text line
86 * char *ip pointer into the .rel file
87 * lfile *linkp pointer to first lfile structure
88 * containing an input .rel file
90 * int lkerr error flag
91 * int mflag Map output flag
92 * int oflag Output file type flag
93 * FILE *ofp Output file handle
95 * FILE *ofph Output file handle
96 * for high byte format
97 * FILE *ofpl Output file handle
99 * int pass linker pass number
100 * int pflag print linker command file flag
101 * int radix current number conversion radix
102 * FILE *sfp The file handle sfp points to the
103 * currently open file
104 * lfile *startp asmlnk startup file structure
105 * FILE * stdin c_library
106 * FILE * stdout c_library
109 * FILE * afile() lkmain.c
110 * int fclose() c_library
111 * int fprintf() c_library
112 * int getline() lklex.c
113 * VOID library() lklibr.c
114 * VOID link() lkmain.c
115 * VOID lkexit() lkmain.c
116 * VOID lnkarea() lkarea.c
117 * VOID map() lkmain.c
119 * int parse() lkmain.c
120 * VOID reloc() lkreloc.c
121 * VOID search() lklibr.c
122 * VOID setbas() lkmain.c
123 * VOID setgbl() lkmain.c
124 * VOID symdef() lksym.c
125 * VOID usage() lkmain.c
128 * Completion of main() completes the linking process
129 * and may produce a map file (.map) and/or a linked
130 * data files (.ihx or .s19) and/or one or more
131 * relocated listing files (.rst).
141 fprintf(stdout, "\n");
143 startp = (struct lfile *) new (sizeof (struct lfile));
146 for (i=1; i<argc; ++i) {
149 while (ctype[c = *(++p)] & LETTER) {
154 startp->f_type = F_STD;
159 startp->f_type = F_LNK;
177 if (startp->f_type == F_LNK) {
182 if (startp->f_type == 0)
184 if (startp->f_type == F_LNK && startp->f_idp == NULL)
194 if (pflag && sfp != stdin)
195 fprintf(stdout, "%s\n", ip);
196 if (*ip == '\0' || parse())
211 dfp = afile("temp", "cdb", 1);
216 for (pass=0; pass<2; ++pass) {
226 /* pass any "magic comments" to NoICE output */
227 if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
228 fprintf( jfp, "%s\n", &ip[2] );
234 * Search libraries for global symbols
238 * Set area base addresses.
242 * Link all area addresses.
246 * Process global definitions.
250 * Check for undefined globals.
254 /* Open NoICE output file if requested */
256 jfp = afile(linkp->f_idp, "NOI", 1);
263 * Output Link Map if requested,
264 * or if NoICE output requested (since NoICE
265 * file is generated in part by map() processing)
277 ofp = afile(linkp->f_idp, "ihx", 1);
281 /* include NoICE command to load hex file */
282 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
286 ofp = afile(linkp->f_idp, "S19", 1);
290 /* include NoICE command to load hex file */
291 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
295 * Link in library files
305 /*)Function VOID lkexit(i)
309 * The function lkexit() explicitly closes all open
310 * files and then terminates the program.
316 * FILE * mfp file handle for .map
317 * FILE * ofp file handle for .ihx/.s19
318 * FILE * rfp file hanlde for .rst
319 * FILE * sfp file handle for .rel
320 * FILE * tfp file handle for .lst
323 * int fclose() c_library
324 * VOID exit() c_library
327 * All files closed. Program terminates.
334 if (mfp != NULL) fclose(mfp);
335 if (jfp != NULL) fclose(jfp);
336 if (ofp != NULL) fclose(ofp);
337 if (rfp != NULL) fclose(rfp);
338 if (sfp != NULL) fclose(sfp);
339 if (tfp != NULL) fclose(tfp);
341 FILE *xfp = afile(linkp->f_idp,"cdb",1);
342 dfp = freopen("temp.cdb","r",dfp);
353 * The function link() evaluates the directives for each line of
354 * text read from the .rel file(s). The valid directives processed
356 * X, D, Q, H, M, A, S, T, R, and P.
359 * int c first non blank character of a line
362 * head *headp The pointer to the first
363 * head structure of a linked list
364 * head *hp Pointer to the current
366 * int pass linker pass number
367 * int radix current number conversion radix
370 * char endline() lklex.c
371 * VOID module() lkhead.c
372 * VOID newarea() lkarea.c
373 * VOID newhead() lkhead.c
374 * sym * newsym() lksym.c
375 * VOID reloc() lkreloc.c
378 * Head, area, and symbol structures are created and
379 * the radix is set as the .rel file(s) are read.
387 if ((c=endline()) == 0) { return; }
415 lastExtendedAddress = -1;
426 if (sdp.s_area == NULL) {
428 sdp.s_areax = areap->a_axp;
449 if (c == 'X' || c == 'D' || c == 'Q') {
450 if ((c = get()) == 'H') {
460 /*)Function VOID map()
462 * The function map() opens the output map file and calls the various
464 * (1) output the variables in each area,
465 * (2) list the files processed with module names,
466 * (3) list the libraries file processed,
467 * (4) list base address definitions,
468 * (5) list global variable definitions, and
469 * (6) list any undefined variables.
473 * head * hdp pointer to head structure
474 * lbfile *lbfh pointer to library file structure
477 * area *ap Pointer to the current
479 * area *areap The pointer to the first
480 * area structure of a linked list
481 * base *basep The pointer to the first
483 * base *bsp Pointer to the current
485 * lfile *filep The pointer *filep points to the
486 * beginning of a linked list of
488 * globl *globlp The pointer to the first
490 * globl *gsp Pointer to the current
492 * head *headp The pointer to the first
493 * head structure of a linked list
494 * lbfile *lbfhead The pointer to the first
495 * lbfile structure of a linked list
496 * lfile *linkp pointer to first lfile structure
497 * containing an input REL file
499 * int lop current line number on page
500 * FILE *mfp Map output file handle
501 * int page current page number
504 * FILE * afile() lkmain.c
505 * int fprintf() c_library
506 * VOID lkexit() lkmain.c
507 * VOID lstarea() lklist.c
508 * VOID newpag() lklist.c
509 * VOID symdef() lksym.c
512 * The map file is created.
519 register struct head *hdp;
520 register struct lbfile *lbfh;
525 mfp = afile(linkp->f_idp, "map", 1);
531 * Output Map Area Lists
544 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
548 fprintf(mfp, "%-16s", filep->f_idp);
550 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
552 fprintf(mfp, ", %8.8s", hdp->m_id);
555 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
557 fprintf(mfp, " [ %8.8s", hdp->m_id);
566 filep = filep->f_flp;
569 * List Linked Libraries
571 if (lbfhead != NULL) {
573 "\nLibraries Linked [ object file ]\n\n");
574 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
575 fprintf(mfp, "%-32s [ %16.16s ]\n",
576 lbfh->libspc, lbfh->relfil);
581 * List Base Address Definitions
585 fprintf(mfp, "\nUser Base Address Definitions\n\n");
588 fprintf(mfp, "%s\n", bsp->b_strp);
593 * List Global Definitions
597 fprintf(mfp, "\nUser Global Definitions\n\n");
600 fprintf(mfp, "%s\n", gsp->g_strp);
604 fprintf(mfp, "\n\f");
608 /*)Function int parse()
610 * The function parse() evaluates all command line or file input
611 * linker directives and updates the appropriate variables.
614 * int c character value
615 * char fid[] file id string
618 * char ctype[] array of character types, one per
620 * lfile *lfp pointer to current lfile structure
621 * being processed by parse()
622 * lfile *linkp pointer to first lfile structure
623 * containing an input REL file
625 * int mflag Map output flag
626 * int oflag Output file type flag
627 * int pflag print linker command file flag
628 * FILE * stderr c_library
629 * int uflag Relocated listing flag
630 * int xflag Map file radix type flag
633 * VOID addlib() lklibr.c
634 * VOID addpath() lklibr.c
635 * VOID bassav() lkmain.c
636 * int fprintf() c_library
637 * VOID gblsav() lkmain.c
638 * VOID getfid() lklex.c
639 * char getnb() lklex.c
640 * VOID lkexit() lkmain.c
641 * char * strcpy() c_library
642 * int strlen() c_library
645 * Various linker flags are updated and the linked
646 * structure lfile is created.
655 while ((c = getnb()) != 0) {
657 while (ctype[c=get()] & LETTER) {
747 fprintf(stderr, "Invalid option\n");
752 if (ctype[c] & ILL) {
753 fprintf(stderr, "Invalid input");
757 linkp = (struct lfile *)
758 new (sizeof (struct lfile));
761 lfp->f_flp = (struct lfile *)
762 new (sizeof (struct lfile));
766 lfp->f_idp = (char *) new (strlen(fid)+1);
767 strcpy(lfp->f_idp, fid);
774 /*)Function VOID bassav()
776 * The function bassav() creates a linked structure containing
777 * the base address strings input to the linker.
783 * base *basep The pointer to the first
785 * base *bsp Pointer to the current
787 * char *ip pointer into the REL file
791 * char getnb() lklex.c
792 * VOID * new() lksym.c
793 * int strlen() c_library
794 * char * strcpy() c_library
795 * VOID unget() lklex.c
798 * The basep structure is created.
805 basep = (struct base *)
806 new (sizeof (struct base));
809 bsp->b_base = (struct base *)
810 new (sizeof (struct base));
814 bsp->b_strp = (char *) new (strlen(ip)+1);
815 strcpy(bsp->b_strp, ip);
818 /*)Function VOID setbas()
820 * The function setbas() scans the base address lines in hte
821 * basep structure, evaluates the arguments, and sets beginning
822 * address of the specified areas.
825 * int v expression value
826 * char id[] base id string
829 * area *ap Pointer to the current
831 * area *areap The pointer to the first
832 * area structure of a linked list
833 * base *basep The pointer to the first
835 * base *bsp Pointer to the current
837 * char *ip pointer into the REL file
839 * int lkerr error flag
842 * addr_t expr() lkeval.c
843 * int fprintf() c_library
844 * VOID getid() lklex.c
845 * char getnb() lklex.c
846 * int symeq() lksym.c
849 * The base address of an area is set.
862 if (getnb() == '=') {
864 for (ap = areap; ap != NULL; ap = ap->a_ap) {
865 if (symeq(id, ap->a_id))
870 "No definition of area %s\n", id);
874 ap->a_type = 1; /* JLH: value set */
877 fprintf(stderr, "No '=' in base expression");
884 /*)Function VOID gblsav()
886 * The function gblsav() creates a linked structure containing
887 * the global variable strings input to the linker.
893 * globl *globlp The pointer to the first
895 * globl *gsp Pointer to the current
897 * char *ip pointer into the REL file
899 * int lkerr error flag
902 * char getnb() lklex.c
903 * VOID * new() lksym.c
904 * int strlen() c_library
905 * char * strcpy() c_library
906 * VOID unget() lklex.c
909 * The globlp structure is created.
915 if (globlp == NULL) {
916 globlp = (struct globl *)
917 new (sizeof (struct globl));
920 gsp->g_globl = (struct globl *)
921 new (sizeof (struct globl));
925 gsp->g_strp = (char *) new (strlen(ip)+1);
926 strcpy(gsp->g_strp, ip);
929 /*)Function VOID setgbl()
931 * The function setgbl() scans the global variable lines in hte
932 * globlp structure, evaluates the arguments, and sets a variable
936 * int v expression value
937 * char id[] base id string
938 * sym * sp pointer to a symbol structure
941 * char *ip pointer into the REL file
943 * globl *globlp The pointer to the first
945 * globl *gsp Pointer to the current
947 * FILE * stderr c_library
948 * int lkerr error flag
951 * addr_t expr() lkeval.c
952 * int fprintf() c_library
953 * VOID getid() lklex.c
954 * char getnb() lklex.c
955 * sym * lkpsym() lksym.c
958 * The value of a variable is set.
965 register struct sym *sp;
972 if (getnb() == '=') {
977 "No definition of symbol %s\n", id);
980 if (sp->s_flag & S_DEF) {
982 "Redefinition of symbol %s\n", id);
990 fprintf(stderr, "No '=' in global expression");
997 /*)Function FILE * afile(fn,, ft, wf)
999 * char * fn file specification string
1000 * char * ft file type string
1001 * int wf read(0)/write(1) flag
1003 * The function afile() opens a file for reading or writing.
1004 * (1) If the file type specification string ft
1005 * is not NULL then a file specification is
1006 * constructed with the file path\name in fn
1007 * and the extension in ft.
1008 * (2) If the file type specification string ft
1009 * is NULL then the file specification is
1010 * constructed from fn. If fn does not have
1011 * a file type then the default .rel file
1012 * type is appended to the file specification.
1014 * afile() returns a file handle for the opened file or aborts
1015 * the assembler on an open error.
1018 * int c character value
1019 * char fb[] constructed file specification string
1020 * FILE * fp filehandle for opened file
1021 * char * p1 pointer to filespec string fn
1022 * char * p2 pointer to filespec string fb
1023 * char * p3 pointer to filetype string ft
1026 * int lkerr error flag
1029 * FILE * fopen() c_library
1030 * int fprintf() c_library
1033 * File is opened for read or write.
1041 register char *p1, *p2, *p3;
1045 char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1050 while ((c = *p1++) != 0 && c != FSEPX) {
1051 if (p2 < &fb[FILSPC-4])
1062 while ((c = *p3++) != 0) {
1063 if (p2 < &fb[FILSPC-1])
1067 if ((fp = fopen(fb, omode)) == NULL) {
1068 if (strcmp(ft,"cdb")) {
1069 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1076 /*)Function VOID iramsav()
1078 * The function iramsav() stores the size of the chip's internal RAM.
1079 * This is used after linking to check that variable assignment to this
1080 * dataspace didn't overflow into adjoining segments. Variables in the
1081 * DSEG, OSEG, and ISEG are assigned to this dataspace.
1087 * char *ip pointer into the REL file
1089 * unsigned int size of chip's internal
1090 * iram_size RAM segment
1093 * char getnb() lklex.c
1094 * VOID unget() lklex.c
1095 * addr_t expr() lkeval.c
1098 * The iram_size may be modified.
1106 //iram_size = atoi(ip);
1107 iram_size = expr(0); /* evaluate size expression */
1109 iram_size = 128; /* Default is 128 (0x80) bytes */
1112 /*)Function VOID iramcheck()
1114 * The function iramcheck() is used at the end of linking to check that
1115 * the internal RAM area wasn't overflowed by too many variable
1116 * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to
1117 * the chip's internal RAM.
1123 * unsigned int size of chip's internal
1124 * iram_size RAM segment
1125 * struct area linked list of memory
1136 register unsigned int last_addr;
1137 register struct area *ap;
1139 for (ap = areap; ap; ap=ap->a_ap) {
1140 if ((ap->a_size != 0) &&
1141 (!strcmp(ap->a_id, "DSEG") ||
1142 !strcmp(ap->a_id, "OSEG") ||
1143 !strcmp(ap->a_id, "ISEG")
1147 last_addr = ap->a_addr + ap->a_size - 1;
1148 if (last_addr >= iram_size)
1150 "\nWARNING! Segment %s extends past the end\n"
1151 " of internal RAM. Check map file.\n",
1159 " -c Command line input",
1160 " -f file[LNK] File input",
1161 " -p Prompt and echo of file[LNK] to stdout (default)",
1162 " -n No echo of file[LNK] to stdout",
1163 /* "Usage: [-Options] file [file ...]", */
1165 " -k Library path specification, one per -k",
1166 " -l Library file specification, one per -l",
1168 " -b area base address = expression",
1169 " -g global symbol = expression",
1171 " -m Map output generated as file[MAP]",
1172 " -x Hexadecimal (default), -d Decimal, -q Octal",
1174 " -i Intel Hex as file[IHX]",
1175 " -s Motorola S19 as file[S19]",
1176 " -j Produce NoICE debug as file[NOI]",
1177 " -z Produce SDCdb debug as file[cdb]",
1179 " -u Update listing file(s) with link data as file(s)[.RST]",
1181 " -a [iram-size] Check for internal RAM overflow",
1183 " -e or null line terminates input",
1187 /*)Function VOID usage()
1189 * The function usage() outputs to the stderr device the
1190 * assembler name and version and a list of valid assembler options.
1193 * char ** dp pointer to an array of
1194 * text string pointers.
1197 * FILE * stderr c_library
1200 * int fprintf() c_library
1211 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1212 for (dp = usetxt; *dp; dp++)
1213 fprintf(stderr, "%s\n", *dp);
1217 /*)Function VOID copyfile()
1219 * FILE *dest destination file
1220 * FILE *src source file
1222 * function will copy source file to destination file
1226 * int fgetc() c_library
1227 * int fputc() c_library
1232 VOID copyfile (dest,src)
1236 while ((ch = fgetc(src)) != EOF) {