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);
47 * The module lkmain.c contains the functions which
48 * (1) input the linker options, parameters, and specifications
49 * (2) perform a two pass link
50 * (3) produce the appropriate linked data output and/or
51 * link map file and/or relocated listing files.
53 * lkmain.c contains the following functions:
54 * FILE * afile(fn,ft,wf)
59 * VOID main(argc,argv)
66 * lkmain.c contains the following local variables:
67 * char * usetext[] array of pointers to the
68 * command option tect lines
72 /*JCF: Creates some of the default areas so they are allocated in the right order.*/
77 "H 7 areas 0 global symbols",
78 "A _CODE size 0 flags 0", /*Each .rel has one, so...*/
79 "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/
80 "A REG_BANK_1 size 0 flags 4",
81 "A REG_BANK_2 size 0 flags 4",
82 "A REG_BANK_3 size 0 flags 4",
83 "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/
84 "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/
89 for (j=0; rel[j][0]!=0; j++)
95 /*Set the start address of the default areas:*/
96 for(ap=areap; ap; ap=ap->a_ap)
98 /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr=0x00; ap->a_type=1; }
99 else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr=0x08; ap->a_type=1; }
100 else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; }
101 else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; }
102 else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; }
106 /*)Function VOID main(argc,argv)
108 * int argc number of command line arguments + 1
109 * char * argv[] array of pointers to the command line
112 * The function main() evaluates the command line arguments to
113 * determine if the linker parameters are to input through 'stdin'
114 * or read from a command file. The functions lk_getline() and parse()
115 * are to input and evaluate the linker parameters. The linking process
116 * proceeds by making the first pass through each .rel file in the order
117 * presented to the linker. At the end of the first pass the setbase(),
118 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
119 * the base address terms, link all areas, define global variables,
120 * and look for undefined symbols. Following these routines a linker
121 * map file may be produced and the linker output files may be opened.
122 * The second pass through the .rel files will output the linked data
123 * in one of the four supported formats.
126 * char * p pointer to an argument string
127 * int c character from argument string
132 * lfile *cfp The pointer *cfp points to the
133 * current lfile structure
134 * char ctype[] array of character types, one per
136 * lfile *filep The pointer *filep points to the
137 * beginning of a linked list of
139 * head *hp Pointer to the current
141 * char ib[NINPUT] .rel file text line
142 * char *ip pointer into the .rel file
143 * lfile *linkp pointer to first lfile structure
144 * containing an input .rel file
146 * int lkerr error flag
147 * int mflag Map output flag
148 * int oflag Output file type flag
149 * FILE *ofp Output file handle
151 * FILE *ofph Output file handle
152 * for high byte format
153 * FILE *ofpl Output file handle
154 * for low byte format
155 * int pass linker pass number
156 * int pflag print linker command file flag
157 * int radix current number conversion radix
158 * FILE *sfp The file handle sfp points to the
159 * currently open file
160 * lfile *startp asmlnk startup file structure
161 * FILE * stdin c_library
162 * FILE * stdout c_library
165 * FILE * afile() lkmain.c
166 * int fclose() c_library
167 * int fprintf() c_library
168 * int lk_getline() lklex.c
169 * VOID library() lklibr.c
170 * VOID link_main() lkmain.c
171 * VOID lkexit() lkmain.c
172 * VOID lnkarea() lkarea.c
173 * VOID map() lkmain.c
175 * int parse() lkmain.c
176 * VOID reloc() lkreloc.c
177 * VOID search() lklibr.c
178 * VOID setbas() lkmain.c
179 * VOID setgbl() lkmain.c
180 * VOID symdef() lksym.c
181 * VOID usage() lkmain.c
184 * Completion of main() completes the linking process
185 * and may produce a map file (.map) and/or a linked
186 * data files (.ihx or .s19) and/or one or more
187 * relocated listing files (.rst).
191 main(int argc, char *argv[])
200 startp = (struct lfile *) new (sizeof (struct lfile));
203 for (i=1; i<argc; ++i) {
206 while (ctype[c = *(++p)] & LETTER) {
211 startp->f_type = F_STD;
216 startp->f_type = F_LNK;
234 if (startp->f_type == F_LNK) {
239 if (startp->f_type == 0)
241 if (startp->f_type == F_LNK && startp->f_idp == NULL)
249 if (lk_getline() == 0)
251 if (pflag && sfp != stdin)
252 fprintf(stdout, "%s\n", ip);
253 if (*ip == '\0' || parse())
268 //dfp = afile("temp", "cdb", 1);
269 SaveLinkedFilePath(linkp->f_idp); //Must be the first one...
270 dfp = afile(linkp->f_idp,"cdb",1); //JCF: Nov 30, 2002
275 for (pass=0; pass<2; ++pass) {
282 Areas51(); /*JCF: Create the default 8051 areas in the right order*/
284 while (lk_getline()) {
287 /* pass any "magic comments" to NoICE output */
288 if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
289 fprintf( jfp, "%s\n", &ip[2] );
295 * Search libraries for global symbols
299 * Set area base addresses.
303 * Link all area addresses.
307 * Process global definitions.
311 * Check for undefined globals.
315 /* Open NoICE output file if requested */
317 jfp = afile(linkp->f_idp, "NOI", 1);
324 * Output Link Map if requested,
325 * or if NoICE output requested (since NoICE
326 * file is generated in part by map() processing)
331 if (sflag) /*JCF: memory usage summary output*/
332 if(summary(areap))lkexit(1);
341 ofp = afile(linkp->f_idp, "ihx", 1);
345 /* include NoICE command to load hex file */
346 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
350 ofp = afile(linkp->f_idp, "S19", 1);
354 /* include NoICE command to load hex file */
355 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
358 ofp = afile(linkp->f_idp, "elf", 4);
365 * Link in library files
375 Timer(1, "Linker execution time");
382 /*)Function VOID lkexit(i)
386 * The function lkexit() explicitly closes all open
387 * files and then terminates the program.
393 * FILE * mfp file handle for .map
394 * FILE * ofp file handle for .ihx/.s19
395 * FILE * rfp file hanlde for .rst
396 * FILE * sfp file handle for .rel
397 * FILE * tfp file handle for .lst
400 * int fclose() c_library
401 * VOID exit() c_library
404 * All files closed. Program terminates.
410 if (mfp != NULL) fclose(mfp);
411 if (jfp != NULL) fclose(jfp);
412 if (ofp != NULL) fclose(ofp);
413 if (rfp != NULL) fclose(rfp);
414 if (sfp != NULL) fclose(sfp);
415 if (tfp != NULL) fclose(tfp);
416 if (dfp != NULL) fclose(dfp);
418 FILE *xfp = afile(linkp->f_idp,"cdb",1);
419 dfp = freopen("temp.cdb","r",dfp);
428 /*)Function link_main()
430 * The function link_main() evaluates the directives for each line of
431 * text read from the .rel file(s). The valid directives processed
433 * X, D, Q, H, M, A, S, T, R, and P.
436 * int c first non blank character of a line
439 * head *headp The pointer to the first
440 * head structure of a linked list
441 * head *hp Pointer to the current
443 * int pass linker pass number
444 * int radix current number conversion radix
447 * char endline() lklex.c
448 * VOID module() lkhead.c
449 * VOID newarea() lkarea.c
450 * VOID newhead() lkhead.c
451 * sym * newsym() lksym.c
452 * VOID reloc() lkreloc.c
455 * Head, area, and symbol structures are created and
456 * the radix is set as the .rel file(s) are read.
464 if ((c=endline()) == 0) { return; }
467 case 'O': /*For some important sdcc options*/
470 if(strlen(sdccopt)==0)
472 strcpy(sdccopt, &ip[1]);
473 strcpy(sdccopt_module, curr_module);
477 if(strcmp(sdccopt, &ip[1])!=0)
480 "?ASlink-Warning-Conflicting sdcc options:\n"
481 " \"%s\" in module \"%s\" and\n"
482 " \"%s\" in module \"%s\".\n",
483 sdccopt, sdccopt_module, &ip[1], curr_module);
520 strcpy(curr_module, &ip[1]);
528 if (sdp.s_area == NULL) {
530 sdp.s_areax = areap->a_axp;
551 if (c == 'X' || c == 'D' || c == 'Q') {
552 if ((c = get()) == 'H') {
562 /*)Function VOID map()
564 * The function map() opens the output map file and calls the various
566 * (1) output the variables in each area,
567 * (2) list the files processed with module names,
568 * (3) list the libraries file processed,
569 * (4) list base address definitions,
570 * (5) list global variable definitions, and
571 * (6) list any undefined variables.
575 * head * hdp pointer to head structure
576 * lbfile *lbfh pointer to library file structure
579 * area *ap Pointer to the current
581 * area *areap The pointer to the first
582 * area structure of a linked list
583 * base *basep The pointer to the first
585 * base *bsp Pointer to the current
587 * lfile *filep The pointer *filep points to the
588 * beginning of a linked list of
590 * globl *globlp The pointer to the first
592 * globl *gsp Pointer to the current
594 * head *headp The pointer to the first
595 * head structure of a linked list
596 * lbfile *lbfhead The pointer to the first
597 * lbfile structure of a linked list
598 * lfile *linkp pointer to first lfile structure
599 * containing an input REL file
601 * int lop current line number on page
602 * FILE *mfp Map output file handle
603 * int page current page number
606 * FILE * afile() lkmain.c
607 * int fprintf() c_library
608 * VOID lkexit() lkmain.c
609 * VOID lstarea() lklist.c
610 * VOID newpag() lklist.c
611 * VOID symdef() lksym.c
614 * The map file is created.
621 register struct head *hdp;
622 register struct lbfile *lbfh;
627 mfp = afile(linkp->f_idp, "map", 1);
633 * Output Map Area Lists
646 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
650 fprintf(mfp, "%-16s", filep->f_idp);
652 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
654 fprintf(mfp, ", %8.8s", hdp->m_id);
657 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
659 fprintf(mfp, " [ %8.8s", hdp->m_id);
668 filep = filep->f_flp;
671 * List Linked Libraries
673 if (lbfhead != NULL) {
675 "\nLibraries Linked [ object file ]\n\n");
676 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
677 fprintf(mfp, "%-32s [ %16.16s ]\n",
678 lbfh->libspc, lbfh->relfil);
683 * List Base Address Definitions
687 fprintf(mfp, "\nUser Base Address Definitions\n\n");
690 fprintf(mfp, "%s\n", bsp->b_strp);
695 * List Global Definitions
699 fprintf(mfp, "\nUser Global Definitions\n\n");
702 fprintf(mfp, "%s\n", gsp->g_strp);
706 fprintf(mfp, "\n\f");
710 /*)Function int parse()
712 * The function parse() evaluates all command line or file input
713 * linker directives and updates the appropriate variables.
716 * int c character value
717 * char fid[] file id string
720 * char ctype[] array of character types, one per
722 * lfile *lfp pointer to current lfile structure
723 * being processed by parse()
724 * lfile *linkp pointer to first lfile structure
725 * containing an input REL file
727 * int mflag Map output flag
728 * int oflag Output file type flag
729 * int pflag print linker command file flag
730 * FILE * stderr c_library
731 * int uflag Relocated listing flag
732 * int xflag Map file radix type flag
735 * VOID addlib() lklibr.c
736 * VOID addpath() lklibr.c
737 * VOID bassav() lkmain.c
738 * int fprintf() c_library
739 * VOID gblsav() lkmain.c
740 * VOID getfid() lklex.c
741 * char getnb() lklex.c
742 * VOID lkexit() lkmain.c
743 * char * strcpy() c_library
744 * int strlen() c_library
747 * Various linker flags are updated and the linked
748 * structure lfile is created.
757 while ((c = getnb()) != 0) {
761 while (ctype[c=get()] & LETTER) {
784 case 'y': /*JCF: memory usage summary output*/
871 fprintf(stderr, "Invalid option\n");
878 if (ctype[c] & ILL) {
879 fprintf(stderr, "Invalid input");
883 linkp = (struct lfile *)
884 new (sizeof (struct lfile));
887 lfp->f_flp = (struct lfile *)
888 new (sizeof (struct lfile));
892 lfp->f_idp = (char *) new (strlen(fid)+1);
893 strcpy(lfp->f_idp, fid);
900 /*)Function VOID bassav()
902 * The function bassav() creates a linked structure containing
903 * the base address strings input to the linker.
909 * base *basep The pointer to the first
911 * base *bsp Pointer to the current
913 * char *ip pointer into the REL file
917 * char getnb() lklex.c
918 * VOID * new() lksym.c
919 * int strlen() c_library
920 * char * strcpy() c_library
921 * VOID unget() lklex.c
924 * The basep structure is created.
931 basep = (struct base *)
932 new (sizeof (struct base));
935 bsp->b_base = (struct base *)
936 new (sizeof (struct base));
940 bsp->b_strp = (char *) new (strlen(ip)+1);
941 strcpy(bsp->b_strp, ip);
944 /*)Function VOID setbas()
946 * The function setbas() scans the base address lines in the
947 * basep structure, evaluates the arguments, and sets beginning
948 * address of the specified areas.
951 * int v expression value
952 * char id[] base id string
955 * area *ap Pointer to the current
957 * area *areap The pointer to the first
958 * area structure of a linked list
959 * base *basep The pointer to the first
961 * base *bsp Pointer to the current
963 * char *ip pointer into the REL file
965 * int lkerr error flag
968 * Addr_T expr() lkeval.c
969 * int fprintf() c_library
970 * VOID getid() lklex.c
971 * char getnb() lklex.c
972 * int symeq() lksym.c
975 * The base address of an area is set.
988 if (getnb() == '=') {
990 for (ap = areap; ap != NULL; ap = ap->a_ap) {
991 if (symeq(id, ap->a_id))
996 "ASlink-Warning-No definition of area %s\n", id);
1000 ap->a_type = 1; /* JLH: value set */
1003 fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1010 /*)Function VOID gblsav()
1012 * The function gblsav() creates a linked structure containing
1013 * the global variable strings input to the linker.
1019 * globl *globlp The pointer to the first
1021 * globl *gsp Pointer to the current
1023 * char *ip pointer into the REL file
1025 * int lkerr error flag
1028 * char getnb() lklex.c
1029 * VOID * new() lksym.c
1030 * int strlen() c_library
1031 * char * strcpy() c_library
1032 * VOID unget() lklex.c
1035 * The globlp structure is created.
1041 if (globlp == NULL) {
1042 globlp = (struct globl *)
1043 new (sizeof (struct globl));
1046 gsp->g_globl = (struct globl *)
1047 new (sizeof (struct globl));
1051 gsp->g_strp = (char *) new (strlen(ip)+1);
1052 strcpy(gsp->g_strp, ip);
1055 /*)Function VOID setgbl()
1057 * The function setgbl() scans the global variable lines in the
1058 * globlp structure, evaluates the arguments, and sets a variable
1062 * int v expression value
1063 * char id[] base id string
1064 * sym * sp pointer to a symbol structure
1067 * char *ip pointer into the REL file
1069 * globl *globlp The pointer to the first
1071 * globl *gsp Pointer to the current
1073 * FILE * stderr c_library
1074 * int lkerr error flag
1077 * Addr_T expr() lkeval.c
1078 * int fprintf() c_library
1079 * VOID getid() lklex.c
1080 * char getnb() lklex.c
1081 * sym * lkpsym() lksym.c
1084 * The value of a variable is set.
1091 register struct sym *sp;
1098 if (getnb() == '=') {
1103 "No definition of symbol %s\n", id);
1106 if (sp->s_flag & S_DEF) {
1108 "Redefinition of symbol %s\n", id);
1113 sp->s_type |= S_DEF;
1116 fprintf(stderr, "No '=' in global expression");
1123 /*)Function FILE * afile(fn,, ft, wf)
1125 * char * fn file specification string
1126 * char * ft file type string
1127 * int wf read(0)/write(1) flag
1129 * The function afile() opens a file for reading or writing.
1130 * (1) If the file type specification string ft
1131 * is not NULL then a file specification is
1132 * constructed with the file path\name in fn
1133 * and the extension in ft.
1134 * (2) If the file type specification string ft
1135 * is NULL then the file specification is
1136 * constructed from fn. If fn does not have
1137 * a file type then the default .rel file
1138 * type is appended to the file specification.
1140 * afile() returns a file handle for the opened file or aborts
1141 * the assembler on an open error.
1144 * char fb[] constructed file specification string
1145 * FILE * fp filehandle for opened file
1148 * int lkerr error flag
1151 * FILE * fopen() c_library
1152 * int fprintf() c_library
1155 * File is opened for read or write.
1159 afile(char *fn, char *ft, int wf)
1167 case 0: omode = "r"; break;
1168 case 1: omode = "w"; break;
1169 case 2: omode = "a"; break;
1170 case 3: omode = "rb"; break;
1171 case 4: omode = "wb"; break;
1172 case 5: omode = "ab"; break;
1173 default: omode = "r"; break;
1176 /*Look backward the name path and get rid of the extension, if any*/
1178 for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>0); i--);
1179 if( (fn[i]=='.') && strcmp(ft, "lnk") )
1189 /*Add the extension*/
1193 strcat(fb, strlen(ft)?ft:"rel");
1196 fp = fopen(fb, omode);
1199 if (strcmp(ft,"adb"))/*Do not complaint for optional adb files*/
1201 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1208 /*)Function VOID iramsav()
1210 * The function iramsav() stores the size of the chip's internal RAM.
1211 * This is used after linking to check that variable assignment to this
1212 * dataspace didn't overflow into adjoining segments. Variables in the
1213 * DSEG, OSEG, and ISEG are assigned to this dataspace.
1219 * char *ip pointer into the REL file
1221 * unsigned int size of chip's internal
1222 * iram_size RAM segment
1225 * char getnb() lklex.c
1226 * VOID unget() lklex.c
1227 * Addr_T expr() lkeval.c
1230 * The iram_size may be modified.
1238 iram_size = expr(0); /* evaluate size expression */
1240 iram_size = 128; /* Default is 128 (0x80) bytes */
1243 /*Similar to iramsav but for xram memory*/
1249 xram_size = expr(0); /* evaluate size expression */
1251 xram_size = rflag?0x1000000:0x10000;
1254 /*Similar to iramsav but for code memory*/
1260 code_size = expr(0); /* evaluate size expression */
1262 code_size = rflag?0x1000000:0x10000;
1266 /*)Function VOID iramcheck()
1268 * The function iramcheck() is used at the end of linking to check that
1269 * the internal RAM area wasn't overflowed by too many variable
1270 * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to
1271 * the chip's internal RAM.
1277 * unsigned int size of chip's internal
1278 * iram_size RAM segment
1279 * struct area linked list of memory
1290 register unsigned int last_addr;
1291 register struct area *ap;
1293 for (ap = areap; ap; ap=ap->a_ap) {
1294 if ((ap->a_size != 0) &&
1295 (!strcmp(ap->a_id, "DSEG") ||
1296 !strcmp(ap->a_id, "OSEG") ||
1297 !strcmp(ap->a_id, "ISEG")
1301 last_addr = ap->a_addr + ap->a_size - 1;
1302 if (last_addr >= iram_size)
1304 "\nWARNING! Segment %s extends past the end\n"
1305 " of internal RAM. Check map file.\n",
1313 " -c Command line input",
1314 " -f file[LNK] File input",
1315 " -p Prompt and echo of file[LNK] to stdout (default)",
1316 " -n No echo of file[LNK] to stdout",
1317 /* "Usage: [-Options] file [file ...]", */
1319 " -k Library path specification, one per -k",
1320 " -l Library file specification, one per -l",
1322 " -b area base address = expression",
1323 " -g global symbol = expression",
1325 " -m Map output generated as file[MAP]",
1326 " -x Hexadecimal (default), -d Decimal, -q Octal",
1328 " -i Intel Hex as file[IHX]",
1329 " -s Motorola S19 as file[S19]",
1330 " -t ELF executable as file[elf]",
1331 " -j Produce NoICE debug as file[NOI]",
1332 " -z Produce SDCdb debug as file[cdb]",
1334 " -u Update listing file(s) with link data as file(s)[.RST]",
1336 " -a [iram-size] Check for internal RAM overflow",
1337 " -v [xram-size] Check for external RAM overflow",
1338 " -w [code-size] Check for code overflow",
1340 " -e or null line terminates input",
1344 /*)Function VOID usage()
1346 * The function usage() outputs to the stderr device the
1347 * assembler name and version and a list of valid assembler options.
1350 * char ** dp pointer to an array of
1351 * text string pointers.
1354 * FILE * stderr c_library
1357 * int fprintf() c_library
1368 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1369 for (dp = usetxt; *dp; dp++)
1370 fprintf(stderr, "%s\n", *dp);
1374 /*)Function VOID copyfile()
1376 * FILE *dest destination file
1377 * FILE *src source file
1379 * function will copy source file to destination file
1383 * int fgetc() c_library
1384 * int fputc() c_library
1389 VOID copyfile (dest,src)
1394 while ((ch = fgetc(src)) != EOF) {