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
22 /* yuck - but including unistd.h causes problems on Cygwin by redefining
25 extern int unlink(const char *);
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.
35 * lkmain.c contains the following functions:
36 * FILE * afile(fn,ft,wf)
41 * VOID main(argc,argv)
48 * lkmain.c contains the following local variables:
49 * char * usetext[] array of pointers to the
50 * command option tect lines
54 /*JCF: Creates some of the default areas so they are allocated in the right order.*/
59 "H 7 areas 0 global symbols",
60 "A _CODE size 0 flags 0", /*Each .rel has one, so...*/
61 "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/
62 "A REG_BANK_1 size 0 flags 4",
63 "A REG_BANK_2 size 0 flags 4",
64 "A REG_BANK_3 size 0 flags 4",
65 "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/
66 "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/
71 for (j=0; rel[j][0]!=0; j++)
77 /*Set the start address of the default areas:*/
78 for(ap=areap; ap; ap=ap->a_ap)
80 /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr=0x00; ap->a_type=1; }
81 else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr=0x08; ap->a_type=1; }
82 else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; }
83 else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; }
84 else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; }
88 /*)Function VOID main(argc,argv)
90 * int argc number of command line arguments + 1
91 * char * argv[] array of pointers to the command line
94 * The function main() evaluates the command line arguments to
95 * determine if the linker parameters are to input through 'stdin'
96 * or read from a command file. The functiond getline() and parse()
97 * are to input and evaluate the linker parameters. The linking process
98 * proceeds by making the first pass through each .rel file in the order
99 * presented to the linker. At the end of the first pass the setbase(),
100 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
101 * the base address terms, link all areas, define global variables,
102 * and look for undefined symbols. Following these routines a linker
103 * map file may be produced and the linker output files may be opened.
104 * The second pass through the .rel files will output the linked data
105 * in one of the four supported formats.
108 * char * p pointer to an argument string
109 * int c character from argument string
114 * lfile *cfp The pointer *cfp points to the
115 * current lfile structure
116 * char ctype[] array of character types, one per
118 * lfile *filep The pointer *filep points to the
119 * beginning of a linked list of
121 * head *hp Pointer to the current
123 * char ib[NINPUT] .rel file text line
124 * char *ip pointer into the .rel file
125 * lfile *linkp pointer to first lfile structure
126 * containing an input .rel file
128 * int lkerr error flag
129 * int mflag Map output flag
130 * int oflag Output file type flag
131 * FILE *ofp Output file handle
133 * FILE *ofph Output file handle
134 * for high byte format
135 * FILE *ofpl Output file handle
136 * for low byte format
137 * int pass linker pass number
138 * int pflag print linker command file flag
139 * int radix current number conversion radix
140 * FILE *sfp The file handle sfp points to the
141 * currently open file
142 * lfile *startp asmlnk startup file structure
143 * FILE * stdin c_library
144 * FILE * stdout c_library
147 * FILE * afile() lkmain.c
148 * int fclose() c_library
149 * int fprintf() c_library
150 * int getline() lklex.c
151 * VOID library() lklibr.c
152 * VOID link_main() lkmain.c
153 * VOID lkexit() lkmain.c
154 * VOID lnkarea() lkarea.c
155 * VOID map() lkmain.c
157 * int parse() lkmain.c
158 * VOID reloc() lkreloc.c
159 * VOID search() lklibr.c
160 * VOID setbas() lkmain.c
161 * VOID setgbl() lkmain.c
162 * VOID symdef() lksym.c
163 * VOID usage() lkmain.c
166 * Completion of main() completes the linking process
167 * and may produce a map file (.map) and/or a linked
168 * data files (.ihx or .s19) and/or one or more
169 * relocated listing files (.rst).
179 startp = (struct lfile *) new (sizeof (struct lfile));
182 for (i=1; i<argc; ++i) {
185 while (ctype[c = *(++p)] & LETTER) {
190 startp->f_type = F_STD;
195 startp->f_type = F_LNK;
213 if (startp->f_type == F_LNK) {
218 if (startp->f_type == 0)
220 if (startp->f_type == F_LNK && startp->f_idp == NULL)
230 if (pflag && sfp != stdin)
231 fprintf(stdout, "%s\n", ip);
232 if (*ip == '\0' || parse())
247 //dfp = afile("temp", "cdb", 1);
248 SaveLinkedFilePath(linkp->f_idp); //Must be the first one...
249 dfp = afile(linkp->f_idp,"cdb",1); //JCF: Nov 30, 2002
254 for (pass=0; pass<2; ++pass) {
261 Areas51(); /*JCF: Create the default 8051 areas in the right order*/
266 /* pass any "magic comments" to NoICE output */
267 if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
268 fprintf( jfp, "%s\n", &ip[2] );
274 * Search libraries for global symbols
278 * Set area base addresses.
282 * Link all area addresses.
286 * Process global definitions.
290 * Check for undefined globals.
294 /* Open NoICE output file if requested */
296 jfp = afile(linkp->f_idp, "NOI", 1);
303 * Output Link Map if requested,
304 * or if NoICE output requested (since NoICE
305 * file is generated in part by map() processing)
310 if (sflag) /*JCF: memory usage summary output*/
311 if(summary(areap))lkexit(1);
320 ofp = afile(linkp->f_idp, "ihx", 1);
324 /* include NoICE command to load hex file */
325 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
329 ofp = afile(linkp->f_idp, "S19", 1);
333 /* include NoICE command to load hex file */
334 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
338 * Link in library files
351 /*)Function VOID lkexit(i)
355 * The function lkexit() explicitly closes all open
356 * files and then terminates the program.
362 * FILE * mfp file handle for .map
363 * FILE * ofp file handle for .ihx/.s19
364 * FILE * rfp file hanlde for .rst
365 * FILE * sfp file handle for .rel
366 * FILE * tfp file handle for .lst
369 * int fclose() c_library
370 * VOID exit() c_library
373 * All files closed. Program terminates.
380 if (mfp != NULL) fclose(mfp);
381 if (jfp != NULL) fclose(jfp);
382 if (ofp != NULL) fclose(ofp);
383 if (rfp != NULL) fclose(rfp);
384 if (sfp != NULL) fclose(sfp);
385 if (tfp != NULL) fclose(tfp);
386 if (dfp != NULL) fclose(dfp);
388 FILE *xfp = afile(linkp->f_idp,"cdb",1);
389 dfp = freopen("temp.cdb","r",dfp);
398 /*)Function link_main()
400 * The function link_main() evaluates the directives for each line of
401 * text read from the .rel file(s). The valid directives processed
403 * X, D, Q, H, M, A, S, T, R, and P.
406 * int c first non blank character of a line
409 * head *headp The pointer to the first
410 * head structure of a linked list
411 * head *hp Pointer to the current
413 * int pass linker pass number
414 * int radix current number conversion radix
417 * char endline() lklex.c
418 * VOID module() lkhead.c
419 * VOID newarea() lkarea.c
420 * VOID newhead() lkhead.c
421 * sym * newsym() lksym.c
422 * VOID reloc() lkreloc.c
425 * Head, area, and symbol structures are created and
426 * the radix is set as the .rel file(s) are read.
434 if ((c=endline()) == 0) { return; }
472 if (sdp.s_area == NULL) {
474 sdp.s_areax = areap->a_axp;
495 if (c == 'X' || c == 'D' || c == 'Q') {
496 if ((c = get()) == 'H') {
506 /*)Function VOID map()
508 * The function map() opens the output map file and calls the various
510 * (1) output the variables in each area,
511 * (2) list the files processed with module names,
512 * (3) list the libraries file processed,
513 * (4) list base address definitions,
514 * (5) list global variable definitions, and
515 * (6) list any undefined variables.
519 * head * hdp pointer to head structure
520 * lbfile *lbfh pointer to library file structure
523 * area *ap Pointer to the current
525 * area *areap The pointer to the first
526 * area structure of a linked list
527 * base *basep The pointer to the first
529 * base *bsp Pointer to the current
531 * lfile *filep The pointer *filep points to the
532 * beginning of a linked list of
534 * globl *globlp The pointer to the first
536 * globl *gsp Pointer to the current
538 * head *headp The pointer to the first
539 * head structure of a linked list
540 * lbfile *lbfhead The pointer to the first
541 * lbfile structure of a linked list
542 * lfile *linkp pointer to first lfile structure
543 * containing an input REL file
545 * int lop current line number on page
546 * FILE *mfp Map output file handle
547 * int page current page number
550 * FILE * afile() lkmain.c
551 * int fprintf() c_library
552 * VOID lkexit() lkmain.c
553 * VOID lstarea() lklist.c
554 * VOID newpag() lklist.c
555 * VOID symdef() lksym.c
558 * The map file is created.
565 register struct head *hdp;
566 register struct lbfile *lbfh;
571 mfp = afile(linkp->f_idp, "map", 1);
577 * Output Map Area Lists
590 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
594 fprintf(mfp, "%-16s", filep->f_idp);
596 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
598 fprintf(mfp, ", %8.8s", hdp->m_id);
601 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
603 fprintf(mfp, " [ %8.8s", hdp->m_id);
612 filep = filep->f_flp;
615 * List Linked Libraries
617 if (lbfhead != NULL) {
619 "\nLibraries Linked [ object file ]\n\n");
620 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
621 fprintf(mfp, "%-32s [ %16.16s ]\n",
622 lbfh->libspc, lbfh->relfil);
627 * List Base Address Definitions
631 fprintf(mfp, "\nUser Base Address Definitions\n\n");
634 fprintf(mfp, "%s\n", bsp->b_strp);
639 * List Global Definitions
643 fprintf(mfp, "\nUser Global Definitions\n\n");
646 fprintf(mfp, "%s\n", gsp->g_strp);
650 fprintf(mfp, "\n\f");
654 /*)Function int parse()
656 * The function parse() evaluates all command line or file input
657 * linker directives and updates the appropriate variables.
660 * int c character value
661 * char fid[] file id string
664 * char ctype[] array of character types, one per
666 * lfile *lfp pointer to current lfile structure
667 * being processed by parse()
668 * lfile *linkp pointer to first lfile structure
669 * containing an input REL file
671 * int mflag Map output flag
672 * int oflag Output file type flag
673 * int pflag print linker command file flag
674 * FILE * stderr c_library
675 * int uflag Relocated listing flag
676 * int xflag Map file radix type flag
679 * VOID addlib() lklibr.c
680 * VOID addpath() lklibr.c
681 * VOID bassav() lkmain.c
682 * int fprintf() c_library
683 * VOID gblsav() lkmain.c
684 * VOID getfid() lklex.c
685 * char getnb() lklex.c
686 * VOID lkexit() lkmain.c
687 * char * strcpy() c_library
688 * int strlen() c_library
691 * Various linker flags are updated and the linked
692 * structure lfile is created.
701 while ((c = getnb()) != 0) {
703 while (ctype[c=get()] & LETTER) {
721 case 'y': /*JCF: memory usage summary output*/
808 fprintf(stderr, "Invalid option\n");
813 if (ctype[c] & ILL) {
814 fprintf(stderr, "Invalid input");
818 linkp = (struct lfile *)
819 new (sizeof (struct lfile));
822 lfp->f_flp = (struct lfile *)
823 new (sizeof (struct lfile));
827 lfp->f_idp = (char *) new (strlen(fid)+1);
828 strcpy(lfp->f_idp, fid);
835 /*)Function VOID bassav()
837 * The function bassav() creates a linked structure containing
838 * the base address strings input to the linker.
844 * base *basep The pointer to the first
846 * base *bsp Pointer to the current
848 * char *ip pointer into the REL file
852 * char getnb() lklex.c
853 * VOID * new() lksym.c
854 * int strlen() c_library
855 * char * strcpy() c_library
856 * VOID unget() lklex.c
859 * The basep structure is created.
866 basep = (struct base *)
867 new (sizeof (struct base));
870 bsp->b_base = (struct base *)
871 new (sizeof (struct base));
875 bsp->b_strp = (char *) new (strlen(ip)+1);
876 strcpy(bsp->b_strp, ip);
879 /*)Function VOID setbas()
881 * The function setbas() scans the base address lines in hte
882 * basep structure, evaluates the arguments, and sets beginning
883 * address of the specified areas.
886 * int v expression value
887 * char id[] base id string
890 * area *ap Pointer to the current
892 * area *areap The pointer to the first
893 * area structure of a linked list
894 * base *basep The pointer to the first
896 * base *bsp Pointer to the current
898 * char *ip pointer into the REL file
900 * int lkerr error flag
903 * Addr_T expr() lkeval.c
904 * int fprintf() c_library
905 * VOID getid() lklex.c
906 * char getnb() lklex.c
907 * int symeq() lksym.c
910 * The base address of an area is set.
923 if (getnb() == '=') {
925 for (ap = areap; ap != NULL; ap = ap->a_ap) {
926 if (symeq(id, ap->a_id))
931 "ASlink-Warning-No definition of area %s\n", id);
935 ap->a_type = 1; /* JLH: value set */
938 fprintf(stderr, "ASlink-Warning-No '=' in base expression");
945 /*)Function VOID gblsav()
947 * The function gblsav() creates a linked structure containing
948 * the global variable strings input to the linker.
954 * globl *globlp The pointer to the first
956 * globl *gsp Pointer to the current
958 * char *ip pointer into the REL file
960 * int lkerr error flag
963 * char getnb() lklex.c
964 * VOID * new() lksym.c
965 * int strlen() c_library
966 * char * strcpy() c_library
967 * VOID unget() lklex.c
970 * The globlp structure is created.
976 if (globlp == NULL) {
977 globlp = (struct globl *)
978 new (sizeof (struct globl));
981 gsp->g_globl = (struct globl *)
982 new (sizeof (struct globl));
986 gsp->g_strp = (char *) new (strlen(ip)+1);
987 strcpy(gsp->g_strp, ip);
990 /*)Function VOID setgbl()
992 * The function setgbl() scans the global variable lines in hte
993 * globlp structure, evaluates the arguments, and sets a variable
997 * int v expression value
998 * char id[] base id string
999 * sym * sp pointer to a symbol structure
1002 * char *ip pointer into the REL file
1004 * globl *globlp The pointer to the first
1006 * globl *gsp Pointer to the current
1008 * FILE * stderr c_library
1009 * int lkerr error flag
1012 * Addr_T expr() lkeval.c
1013 * int fprintf() c_library
1014 * VOID getid() lklex.c
1015 * char getnb() lklex.c
1016 * sym * lkpsym() lksym.c
1019 * The value of a variable is set.
1026 register struct sym *sp;
1033 if (getnb() == '=') {
1038 "No definition of symbol %s\n", id);
1041 if (sp->s_flag & S_DEF) {
1043 "Redefinition of symbol %s\n", id);
1048 sp->s_type |= S_DEF;
1051 fprintf(stderr, "No '=' in global expression");
1058 /*)Function FILE * afile(fn,, ft, wf)
1060 * char * fn file specification string
1061 * char * ft file type string
1062 * int wf read(0)/write(1) flag
1064 * The function afile() opens a file for reading or writing.
1065 * (1) If the file type specification string ft
1066 * is not NULL then a file specification is
1067 * constructed with the file path\name in fn
1068 * and the extension in ft.
1069 * (2) If the file type specification string ft
1070 * is NULL then the file specification is
1071 * constructed from fn. If fn does not have
1072 * a file type then the default .rel file
1073 * type is appended to the file specification.
1075 * afile() returns a file handle for the opened file or aborts
1076 * the assembler on an open error.
1079 * int c character value
1080 * char fb[] constructed file specification string
1081 * FILE * fp filehandle for opened file
1082 * char * p1 pointer to filespec string fn
1083 * char * p2 pointer to filespec string fb
1084 * char * p3 pointer to filetype string ft
1087 * int lkerr error flag
1090 * FILE * fopen() c_library
1091 * int fprintf() c_library
1094 * File is opened for read or write.
1102 register char *p1, *p2, *p3;
1106 char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1111 while ((c = *p1++) != 0 && c != FSEPX) {
1112 if (p2 < &fb[PATH_MAX-4])
1123 while ((c = *p3++) != 0) {
1124 if (p2 < &fb[PATH_MAX-1])
1128 if ((fp = fopen(fb, omode)) == NULL) {
1129 if (strcmp(ft,"adb")) {
1130 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1137 /*)Function VOID iramsav()
1139 * The function iramsav() stores the size of the chip's internal RAM.
1140 * This is used after linking to check that variable assignment to this
1141 * dataspace didn't overflow into adjoining segments. Variables in the
1142 * DSEG, OSEG, and ISEG are assigned to this dataspace.
1148 * char *ip pointer into the REL file
1150 * unsigned int size of chip's internal
1151 * iram_size RAM segment
1154 * char getnb() lklex.c
1155 * VOID unget() lklex.c
1156 * Addr_T expr() lkeval.c
1159 * The iram_size may be modified.
1167 //iram_size = atoi(ip);
1168 iram_size = expr(0); /* evaluate size expression */
1170 iram_size = 128; /* Default is 128 (0x80) bytes */
1173 /*Similar to iramsav but for xram memory*/
1179 xram_size = expr(0); /* evaluate size expression */
1181 xram_size = rflag?0x1000000:0x10000;
1184 /*Similar to iramsav but for code memory*/
1190 code_size = expr(0); /* evaluate size expression */
1192 code_size = rflag?0x1000000:0x10000;
1196 /*)Function VOID iramcheck()
1198 * The function iramcheck() is used at the end of linking to check that
1199 * the internal RAM area wasn't overflowed by too many variable
1200 * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to
1201 * the chip's internal RAM.
1207 * unsigned int size of chip's internal
1208 * iram_size RAM segment
1209 * struct area linked list of memory
1220 register unsigned int last_addr;
1221 register struct area *ap;
1223 for (ap = areap; ap; ap=ap->a_ap) {
1224 if ((ap->a_size != 0) &&
1225 (!strcmp(ap->a_id, "DSEG") ||
1226 !strcmp(ap->a_id, "OSEG") ||
1227 !strcmp(ap->a_id, "ISEG")
1231 last_addr = ap->a_addr + ap->a_size - 1;
1232 if (last_addr >= iram_size)
1234 "\nWARNING! Segment %s extends past the end\n"
1235 " of internal RAM. Check map file.\n",
1243 " -c Command line input",
1244 " -f file[LNK] File input",
1245 " -p Prompt and echo of file[LNK] to stdout (default)",
1246 " -n No echo of file[LNK] to stdout",
1247 /* "Usage: [-Options] file [file ...]", */
1249 " -k Library path specification, one per -k",
1250 " -l Library file specification, one per -l",
1252 " -b area base address = expression",
1253 " -g global symbol = expression",
1255 " -m Map output generated as file[MAP]",
1256 " -x Hexadecimal (default), -d Decimal, -q Octal",
1258 " -i Intel Hex as file[IHX]",
1259 " -s Motorola S19 as file[S19]",
1260 " -j Produce NoICE debug as file[NOI]",
1261 " -z Produce SDCdb debug as file[cdb]",
1263 " -u Update listing file(s) with link data as file(s)[.RST]",
1265 " -a [iram-size] Check for internal RAM overflow",
1266 " -v [xram-size] Check for external RAM overflow",
1267 " -w [code-size] Check for code overflow",
1269 " -e or null line terminates input",
1273 /*)Function VOID usage()
1275 * The function usage() outputs to the stderr device the
1276 * assembler name and version and a list of valid assembler options.
1279 * char ** dp pointer to an array of
1280 * text string pointers.
1283 * FILE * stderr c_library
1286 * int fprintf() c_library
1297 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1298 for (dp = usetxt; *dp; dp++)
1299 fprintf(stderr, "%s\n", *dp);
1303 /*)Function VOID copyfile()
1305 * FILE *dest destination file
1306 * FILE *src source file
1308 * function will copy source file to destination file
1312 * int fgetc() c_library
1313 * int fputc() c_library
1318 VOID copyfile (dest,src)
1322 while ((ch = fgetc(src)) != EOF) {