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 void Timer(int action, char * message)
27 static double start, end, total=0.0;
28 static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
30 if(action==0) start=clock()*secs_per_tick;
33 end=clock() * secs_per_tick;
34 printf("%s \t%f seconds.\n", message, (end-start));
39 printf("Total time: \t%f seconds.\n", total);
45 /* yuck - but including unistd.h causes problems on Cygwin by redefining
48 extern int unlink(const char *);
52 * The module lkmain.c contains the functions which
53 * (1) input the linker options, parameters, and specifications
54 * (2) perform a two pass link
55 * (3) produce the appropriate linked data output and/or
56 * link map file and/or relocated listing files.
58 * lkmain.c contains the following functions:
59 * FILE * afile(fn,ft,wf)
64 * VOID main(argc,argv)
71 * lkmain.c contains the following local variables:
72 * char * usetext[] array of pointers to the
73 * command option tect lines
77 /*JCF: Creates some of the default areas so they are allocated in the right order.*/
82 "H 7 areas 0 global symbols",
83 "A _CODE size 0 flags 0", /*Each .rel has one, so...*/
84 "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/
85 "A REG_BANK_1 size 0 flags 4",
86 "A REG_BANK_2 size 0 flags 4",
87 "A REG_BANK_3 size 0 flags 4",
88 "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/
89 "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/
95 "H B areas 0 global symbols",
96 "A _CODE size 0 flags 0", /*Each .rel has one, so...*/
97 "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/
98 "A REG_BANK_1 size 0 flags 4",
99 "A REG_BANK_2 size 0 flags 4",
100 "A REG_BANK_3 size 0 flags 4",
101 "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/
102 "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/
103 "A DSEG size 0 flags 0",
104 "A OSEG size 0 flags 4",
105 "A ISEG size 0 flags 0",
106 "A SSEG size 0 flags 4",
111 if(packflag_and_stacksize)
113 for (j=0; rel2[j][0]!=0; j++)
121 for (j=0; rel[j][0]!=0; j++)
128 /*Set the start address of the default areas:*/
129 for(ap=areap; ap; ap=ap->a_ap)
131 /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr=0x00; ap->a_type=1; }
132 else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr=0x08; ap->a_type=1; }
133 else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; }
134 else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; }
135 else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; }
136 else if (!strcmp(ap->a_id, "SSEG"))
138 if(packflag_and_stacksize>1) ap->a_axp->a_size=packflag_and_stacksize;
143 /*)Function VOID main(argc,argv)
145 * int argc number of command line arguments + 1
146 * char * argv[] array of pointers to the command line
149 * The function main() evaluates the command line arguments to
150 * determine if the linker parameters are to input through 'stdin'
151 * or read from a command file. The functiond getline() and parse()
152 * are to input and evaluate the linker parameters. The linking process
153 * proceeds by making the first pass through each .rel file in the order
154 * presented to the linker. At the end of the first pass the setbase(),
155 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
156 * the base address terms, link all areas, define global variables,
157 * and look for undefined symbols. Following these routines a linker
158 * map file may be produced and the linker output files may be opened.
159 * The second pass through the .rel files will output the linked data
160 * in one of the four supported formats.
163 * char * p pointer to an argument string
164 * int c character from argument string
169 * lfile *cfp The pointer *cfp points to the
170 * current lfile structure
171 * char ctype[] array of character types, one per
173 * lfile *filep The pointer *filep points to the
174 * beginning of a linked list of
176 * head *hp Pointer to the current
178 * char ib[NINPUT] .rel file text line
179 * char *ip pointer into the .rel file
180 * lfile *linkp pointer to first lfile structure
181 * containing an input .rel file
183 * int lkerr error flag
184 * int mflag Map output flag
185 * int oflag Output file type flag
186 * FILE *ofp Output file handle
188 * FILE *ofph Output file handle
189 * for high byte format
190 * FILE *ofpl Output file handle
191 * for low byte format
192 * int pass linker pass number
193 * int pflag print linker command file flag
194 * int radix current number conversion radix
195 * FILE *sfp The file handle sfp points to the
196 * currently open file
197 * lfile *startp asmlnk startup file structure
198 * FILE * stdin c_library
199 * FILE * stdout c_library
202 * FILE * afile() lkmain.c
203 * int fclose() c_library
204 * int fprintf() c_library
205 * int getline() lklex.c
206 * VOID library() lklibr.c
207 * VOID link_main() lkmain.c
208 * VOID lkexit() lkmain.c
209 * VOID lnkarea() lkarea.c
210 * VOID map() lkmain.c
212 * int parse() lkmain.c
213 * VOID reloc() lkreloc.c
214 * VOID search() lklibr.c
215 * VOID setbas() lkmain.c
216 * VOID setgbl() lkmain.c
217 * VOID symdef() lksym.c
218 * VOID usage() lkmain.c
221 * Completion of main() completes the linking process
222 * and may produce a map file (.map) and/or a linked
223 * data files (.ihx or .s19) and/or one or more
224 * relocated listing files (.rst).
238 startp = (struct lfile *) new (sizeof (struct lfile));
241 for (i=1; i<argc; ++i) {
244 while (ctype[c = *(++p)] & LETTER) {
249 startp->f_type = F_STD;
254 startp->f_type = F_LNK;
272 if (startp->f_type == F_LNK) {
277 if (startp->f_type == 0)
279 if (startp->f_type == F_LNK && startp->f_idp == NULL)
289 if (pflag && sfp != stdin)
290 fprintf(stdout, "%s\n", ip);
291 if (*ip == '\0' || parse())
306 //dfp = afile("temp", "cdb", 1);
307 SaveLinkedFilePath(linkp->f_idp); //Must be the first one...
308 dfp = afile(linkp->f_idp,"cdb",1); //JCF: Nov 30, 2002
313 for (pass=0; pass<2; ++pass) {
320 Areas51(); /*JCF: Create the default 8051 areas in the right order*/
325 /* pass any "magic comments" to NoICE output */
326 if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
327 fprintf( jfp, "%s\n", &ip[2] );
333 * Search libraries for global symbols
337 * Set area base addresses.
341 * Link all area addresses.
343 if(!packflag_and_stacksize)
348 * Process global definitions.
352 * Check for undefined globals.
356 /* Open NoICE output file if requested */
358 jfp = afile(linkp->f_idp, "NOI", 1);
365 * Output Link Map if requested,
366 * or if NoICE output requested (since NoICE
367 * file is generated in part by map() processing)
372 if (sflag) /*JCF: memory usage summary output*/
374 if(!packflag_and_stacksize)
376 if(summary(areap)) lkexit(1);
380 if(summary2(areap)) lkexit(1);
384 if ((iram_size) && (!packflag_and_stacksize))
391 ofp = afile(linkp->f_idp, "ihx", 1);
395 /* include NoICE command to load hex file */
396 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
400 ofp = afile(linkp->f_idp, "S19", 1);
404 /* include NoICE command to load hex file */
405 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
409 * Link in library files
419 Timer(1, "Linker execution time");
426 /*)Function VOID lkexit(i)
430 * The function lkexit() explicitly closes all open
431 * files and then terminates the program.
437 * FILE * mfp file handle for .map
438 * FILE * ofp file handle for .ihx/.s19
439 * FILE * rfp file hanlde for .rst
440 * FILE * sfp file handle for .rel
441 * FILE * tfp file handle for .lst
444 * int fclose() c_library
445 * VOID exit() c_library
448 * All files closed. Program terminates.
455 if (mfp != NULL) fclose(mfp);
456 if (jfp != NULL) fclose(jfp);
457 if (ofp != NULL) fclose(ofp);
458 if (rfp != NULL) fclose(rfp);
459 if (sfp != NULL) fclose(sfp);
460 if (tfp != NULL) fclose(tfp);
461 if (dfp != NULL) fclose(dfp);
463 FILE *xfp = afile(linkp->f_idp,"cdb",1);
464 dfp = freopen("temp.cdb","r",dfp);
473 /*)Function link_main()
475 * The function link_main() evaluates the directives for each line of
476 * text read from the .rel file(s). The valid directives processed
478 * X, D, Q, H, M, A, S, T, R, and P.
481 * int c first non blank character of a line
484 * head *headp The pointer to the first
485 * head structure of a linked list
486 * head *hp Pointer to the current
488 * int pass linker pass number
489 * int radix current number conversion radix
492 * char endline() lklex.c
493 * VOID module() lkhead.c
494 * VOID newarea() lkarea.c
495 * VOID newhead() lkhead.c
496 * sym * newsym() lksym.c
497 * VOID reloc() lkreloc.c
500 * Head, area, and symbol structures are created and
501 * the radix is set as the .rel file(s) are read.
509 if ((c=endline()) == 0) { return; }
512 case 'O': /*For some important sdcc options*/
515 if(strlen(sdccopt)==0)
517 strcpy(sdccopt, &ip[1]);
518 strcpy(sdccopt_module, curr_module);
522 if(strcmp(sdccopt, &ip[1])!=0)
525 "?ASlink-Warning-Conflicting sdcc options:\n"
526 " \"%s\" in module \"%s\" and\n"
527 " \"%s\" in module \"%s\".\n",
528 sdccopt, sdccopt_module, &ip[1], curr_module);
565 strcpy(curr_module, &ip[1]);
573 if (sdp.s_area == NULL) {
575 sdp.s_areax = areap->a_axp;
596 if (c == 'X' || c == 'D' || c == 'Q') {
597 if ((c = get()) == 'H') {
607 /*)Function VOID map()
609 * The function map() opens the output map file and calls the various
611 * (1) output the variables in each area,
612 * (2) list the files processed with module names,
613 * (3) list the libraries file processed,
614 * (4) list base address definitions,
615 * (5) list global variable definitions, and
616 * (6) list any undefined variables.
620 * head * hdp pointer to head structure
621 * lbfile *lbfh pointer to library file structure
624 * area *ap Pointer to the current
626 * area *areap The pointer to the first
627 * area structure of a linked list
628 * base *basep The pointer to the first
630 * base *bsp Pointer to the current
632 * lfile *filep The pointer *filep points to the
633 * beginning of a linked list of
635 * globl *globlp The pointer to the first
637 * globl *gsp Pointer to the current
639 * head *headp The pointer to the first
640 * head structure of a linked list
641 * lbfile *lbfhead The pointer to the first
642 * lbfile structure of a linked list
643 * lfile *linkp pointer to first lfile structure
644 * containing an input REL file
646 * int lop current line number on page
647 * FILE *mfp Map output file handle
648 * int page current page number
651 * FILE * afile() lkmain.c
652 * int fprintf() c_library
653 * VOID lkexit() lkmain.c
654 * VOID lstarea() lklist.c
655 * VOID newpag() lklist.c
656 * VOID symdef() lksym.c
659 * The map file is created.
666 register struct head *hdp;
667 register struct lbfile *lbfh;
672 mfp = afile(linkp->f_idp, "map", 1);
678 * Output Map Area Lists
691 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
695 fprintf(mfp, "%-16s", filep->f_idp);
697 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
699 fprintf(mfp, ", %8.8s", hdp->m_id);
702 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
704 fprintf(mfp, " [ %8.8s", hdp->m_id);
713 filep = filep->f_flp;
716 * List Linked Libraries
718 if (lbfhead != NULL) {
720 "\nLibraries Linked [ object file ]\n\n");
721 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
722 fprintf(mfp, "%-32s [ %16.16s ]\n",
723 lbfh->libspc, lbfh->relfil);
728 * List Base Address Definitions
732 fprintf(mfp, "\nUser Base Address Definitions\n\n");
735 fprintf(mfp, "%s\n", bsp->b_strp);
740 * List Global Definitions
744 fprintf(mfp, "\nUser Global Definitions\n\n");
747 fprintf(mfp, "%s\n", gsp->g_strp);
751 fprintf(mfp, "\n\f");
755 /*)Function int parse()
757 * The function parse() evaluates all command line or file input
758 * linker directives and updates the appropriate variables.
761 * int c character value
762 * char fid[] file id string
765 * char ctype[] array of character types, one per
767 * lfile *lfp pointer to current lfile structure
768 * being processed by parse()
769 * lfile *linkp pointer to first lfile structure
770 * containing an input REL file
772 * int mflag Map output flag
773 * int oflag Output file type flag
774 * int pflag print linker command file flag
775 * FILE * stderr c_library
776 * int uflag Relocated listing flag
777 * int xflag Map file radix type flag
780 * VOID addlib() lklibr.c
781 * VOID addpath() lklibr.c
782 * VOID bassav() lkmain.c
783 * int fprintf() c_library
784 * VOID gblsav() lkmain.c
785 * VOID getfid() lklex.c
786 * char getnb() lklex.c
787 * VOID lkexit() lkmain.c
788 * char * strcpy() c_library
789 * int strlen() c_library
792 * Various linker flags are updated and the linked
793 * structure lfile is created.
802 while ((c = getnb()) != 0) {
804 while (ctype[c=get()] & LETTER) {
822 case 'y': /*JCF: memory usage summary output*/
828 /*The stack segment default size is 16 bytes. Use -Yxx for xx bytes*/
829 packflag_and_stacksize=(ip && *ip)?expr(0):16;
914 fprintf(stderr, "Invalid option\n");
919 if (ctype[c] & ILL) {
920 fprintf(stderr, "Invalid input");
924 linkp = (struct lfile *)
925 new (sizeof (struct lfile));
928 lfp->f_flp = (struct lfile *)
929 new (sizeof (struct lfile));
933 lfp->f_idp = (char *) new (strlen(fid)+1);
934 strcpy(lfp->f_idp, fid);
941 /*)Function VOID bassav()
943 * The function bassav() creates a linked structure containing
944 * the base address strings input to the linker.
950 * base *basep The pointer to the first
952 * base *bsp Pointer to the current
954 * char *ip pointer into the REL file
958 * char getnb() lklex.c
959 * VOID * new() lksym.c
960 * int strlen() c_library
961 * char * strcpy() c_library
962 * VOID unget() lklex.c
965 * The basep structure is created.
972 basep = (struct base *)
973 new (sizeof (struct base));
976 bsp->b_base = (struct base *)
977 new (sizeof (struct base));
981 bsp->b_strp = (char *) new (strlen(ip)+1);
982 strcpy(bsp->b_strp, ip);
985 /*)Function VOID setbas()
987 * The function setbas() scans the base address lines in hte
988 * basep structure, evaluates the arguments, and sets beginning
989 * address of the specified areas.
992 * int v expression value
993 * char id[] base id string
996 * area *ap Pointer to the current
998 * area *areap The pointer to the first
999 * area structure of a linked list
1000 * base *basep The pointer to the first
1002 * base *bsp Pointer to the current
1004 * char *ip pointer into the REL file
1006 * int lkerr error flag
1009 * Addr_T expr() lkeval.c
1010 * int fprintf() c_library
1011 * VOID getid() lklex.c
1012 * char getnb() lklex.c
1013 * int symeq() lksym.c
1016 * The base address of an area is set.
1029 if (getnb() == '=') {
1031 for (ap = areap; ap != NULL; ap = ap->a_ap) {
1032 if (symeq(id, ap->a_id))
1037 "ASlink-Warning-No definition of area %s\n", id);
1041 ap->a_type = 1; /* JLH: value set */
1044 fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1051 /*)Function VOID gblsav()
1053 * The function gblsav() creates a linked structure containing
1054 * the global variable strings input to the linker.
1060 * globl *globlp The pointer to the first
1062 * globl *gsp Pointer to the current
1064 * char *ip pointer into the REL file
1066 * int lkerr error flag
1069 * char getnb() lklex.c
1070 * VOID * new() lksym.c
1071 * int strlen() c_library
1072 * char * strcpy() c_library
1073 * VOID unget() lklex.c
1076 * The globlp structure is created.
1082 if (globlp == NULL) {
1083 globlp = (struct globl *)
1084 new (sizeof (struct globl));
1087 gsp->g_globl = (struct globl *)
1088 new (sizeof (struct globl));
1092 gsp->g_strp = (char *) new (strlen(ip)+1);
1093 strcpy(gsp->g_strp, ip);
1096 /*)Function VOID setgbl()
1098 * The function setgbl() scans the global variable lines in hte
1099 * globlp structure, evaluates the arguments, and sets a variable
1103 * int v expression value
1104 * char id[] base id string
1105 * sym * sp pointer to a symbol structure
1108 * char *ip pointer into the REL file
1110 * globl *globlp The pointer to the first
1112 * globl *gsp Pointer to the current
1114 * FILE * stderr c_library
1115 * int lkerr error flag
1118 * Addr_T expr() lkeval.c
1119 * int fprintf() c_library
1120 * VOID getid() lklex.c
1121 * char getnb() lklex.c
1122 * sym * lkpsym() lksym.c
1125 * The value of a variable is set.
1132 register struct sym *sp;
1139 if (getnb() == '=') {
1144 "No definition of symbol %s\n", id);
1147 if (sp->s_flag & S_DEF) {
1149 "Redefinition of symbol %s\n", id);
1154 sp->s_type |= S_DEF;
1157 fprintf(stderr, "No '=' in global expression");
1164 /*)Function FILE * afile(fn,, ft, wf)
1166 * char * fn file specification string
1167 * char * ft file type string
1168 * int wf read(0)/write(1) flag
1170 * The function afile() opens a file for reading or writing.
1171 * (1) If the file type specification string ft
1172 * is not NULL then a file specification is
1173 * constructed with the file path\name in fn
1174 * and the extension in ft.
1175 * (2) If the file type specification string ft
1176 * is NULL then the file specification is
1177 * constructed from fn. If fn does not have
1178 * a file type then the default .rel file
1179 * type is appended to the file specification.
1181 * afile() returns a file handle for the opened file or aborts
1182 * the assembler on an open error.
1185 * char fb[] constructed file specification string
1186 * FILE * fp filehandle for opened file
1189 * int lkerr error flag
1192 * FILE * fopen() c_library
1193 * int fprintf() c_library
1196 * File is opened for read or write.
1206 char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1209 /*Look backward the name path and get rid of the extension, if any*/
1211 for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>=0); i--);
1212 if( (fn[i]=='.') && strcmp(ft, "lnk") )
1222 /*Add the extension*/
1224 strcat(fb, strlen(ft)?ft:"rel");
1226 fp = fopen(fb, omode);
1229 if (strcmp(ft,"adb"))/*Do not complaint for optional adb files*/
1231 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1238 /*)Function VOID iramsav()
1240 * The function iramsav() stores the size of the chip's internal RAM.
1241 * This is used after linking to check that variable assignment to this
1242 * dataspace didn't overflow into adjoining segments. Variables in the
1243 * DSEG, OSEG, and ISEG are assigned to this dataspace.
1249 * char *ip pointer into the REL file
1251 * unsigned int size of chip's internal
1252 * iram_size RAM segment
1255 * char getnb() lklex.c
1256 * VOID unget() lklex.c
1257 * Addr_T expr() lkeval.c
1260 * The iram_size may be modified.
1268 //iram_size = atoi(ip);
1269 iram_size = expr(0); /* evaluate size expression */
1271 iram_size = 128; /* Default is 128 (0x80) bytes */
1274 /*Similar to iramsav but for xram memory*/
1280 xram_size = expr(0); /* evaluate size expression */
1282 xram_size = rflag?0x1000000:0x10000;
1285 /*Similar to iramsav but for code memory*/
1291 code_size = expr(0); /* evaluate size expression */
1293 code_size = rflag?0x1000000:0x10000;
1297 /*)Function VOID iramcheck()
1299 * The function iramcheck() is used at the end of linking to check that
1300 * the internal RAM area wasn't overflowed by too many variable
1301 * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to
1302 * the chip's internal RAM.
1308 * unsigned int size of chip's internal
1309 * iram_size RAM segment
1310 * struct area linked list of memory
1321 register unsigned int last_addr;
1322 register struct area *ap;
1324 for (ap = areap; ap; ap=ap->a_ap) {
1325 if ((ap->a_size != 0) &&
1326 (!strcmp(ap->a_id, "DSEG") ||
1327 !strcmp(ap->a_id, "OSEG") ||
1328 !strcmp(ap->a_id, "ISEG")
1332 last_addr = ap->a_addr + ap->a_size - 1;
1333 if (last_addr >= iram_size)
1335 "\nWARNING! Segment %s extends past the end\n"
1336 " of internal RAM. Check map file.\n",
1344 " -c Command line input",
1345 " -f file[LNK] File input",
1346 " -p Prompt and echo of file[LNK] to stdout (default)",
1347 " -n No echo of file[LNK] to stdout",
1348 /* "Usage: [-Options] file [file ...]", */
1350 " -k Library path specification, one per -k",
1351 " -l Library file specification, one per -l",
1353 " -b area base address = expression",
1354 " -g global symbol = expression",
1356 " -m Map output generated as file[MAP]",
1357 " -x Hexadecimal (default), -d Decimal, -q Octal",
1359 " -i Intel Hex as file[IHX]",
1360 " -s Motorola S19 as file[S19]",
1361 " -j Produce NoICE debug as file[NOI]",
1362 " -z Produce SDCdb debug as file[cdb]",
1364 " -u Update listing file(s) with link data as file(s)[.RST]",
1366 " -a [iram-size] Check for internal RAM overflow",
1367 " -v [xram-size] Check for external RAM overflow",
1368 " -w [code-size] Check for code overflow",
1370 " -e or null line terminates input",
1374 /*)Function VOID usage()
1376 * The function usage() outputs to the stderr device the
1377 * assembler name and version and a list of valid assembler options.
1380 * char ** dp pointer to an array of
1381 * text string pointers.
1384 * FILE * stderr c_library
1387 * int fprintf() c_library
1398 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1399 for (dp = usetxt; *dp; dp++)
1400 fprintf(stderr, "%s\n", *dp);
1404 /*)Function VOID copyfile()
1406 * FILE *dest destination file
1407 * FILE *src source file
1409 * function will copy source file to destination file
1413 * int fgetc() c_library
1414 * int fputc() c_library
1419 VOID copyfile (dest,src)
1423 while ((ch = fgetc(src)) != EOF) {