4 * (C) Copyright 1989-1995
13 * Extensions: P. Felber
21 #ifndef SDK_VERSION_STRING
22 #define SDK_VERSION_STRING "3.0.0"
25 #define TARGET_STRING "gbz80"
31 void Timer(int action, char * message)
33 static double start, end, total=0.0;
34 static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
36 if(action==0) start=clock()*secs_per_tick;
39 end=clock() * secs_per_tick;
40 printf("%s \t%f seconds.\n", message, (end-start));
45 printf("Total time: \t%f seconds.\n", total);
53 * The module lkmain.c contains the functions which
54 * (1) input the linker options, parameters, and specifications
55 * (2) perform a two pass link
56 * (3) produce the appropriate linked data output and/or
57 * link map file and/or relocated listing files.
59 * lkmain.c contains the following functions:
60 * FILE * afile(fn,ft,wf)
65 * VOID main(argc,argv)
72 * lkmain.c contains the following local variables:
73 * char * usetext[] array of pointers to the
74 * command option tect lines
78 /*)Function VOID main(argc,argv)
80 * int argc number of command line arguments + 1
81 * char * argv[] array of pointers to the command line
84 * The function main() evaluates the command line arguments to
85 * determine if the linker parameters are to input through 'stdin'
86 * or read from a command file. The functions lk_getline() and parse()
87 * are to input and evaluate the linker parameters. The linking process
88 * proceeds by making the first pass through each .rel file in the order
89 * presented to the linker. At the end of the first pass the setbase(),
90 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
91 * the base address terms, link all areas, define global variables,
92 * and look for undefined symbols. Following these routines a linker
93 * map file may be produced and the linker output files may be opened.
94 * The second pass through the .rel files will output the linked data
95 * in one of the four supported formats.
98 * char * p pointer to an argument string
99 * int c character from argument string
104 * lfile *cfp The pointer *cfp points to the
105 * current lfile structure
106 * char ctype[] array of character types, one per
108 * lfile *filep The pointer *filep points to the
109 * beginning of a linked list of
111 * head *hp Pointer to the current
113 * char ib[NINPUT] .rel file text line
114 * char *ip pointer into the .rel file
115 * lfile *linkp pointer to first lfile structure
116 * containing an input .rel file
118 * int lkerr error flag
119 * int mflag Map output flag
120 * int oflag Output file type flag
121 * FILE *ofp Output file handle
123 * FILE *ofph Output file handle
124 * for high byte format
125 * FILE *ofpl Output file handle
126 * for low byte format
127 * int pass linker pass number
128 * int pflag print linker command file flag
129 * int radix current number conversion radix
130 * FILE *sfp The file handle sfp points to the
131 * currently open file
132 * lfile *startp asmlnk startup file structure
133 * FILE * stdin c_library
134 * FILE * stdout c_library
137 * FILE * afile() lkmain.c
138 * int fclose() c_library
139 * int fprintf() c_library
140 * int lk_getline() lklex.c
141 * VOID library() lklibr.c
142 * VOID link_main() lkmain.c
143 * VOID lkexit() lkmain.c
144 * VOID lnkarea() lkarea.c
145 * VOID map() lkmain.c
147 * int parse() lkmain.c
148 * VOID reloc() lkreloc.c
149 * VOID search() lklibr.c
150 * VOID setbas() lkmain.c
151 * VOID setgbl() lkmain.c
152 * VOID symdef() lksym.c
153 * VOID usage() lkmain.c
156 * Completion of main() completes the linking process
157 * and may produce a map file (.map) and/or a linked
158 * data files (.ihx or .s19) and/or one or more
159 * relocated listing files (.rst).
166 char *default_basep[] = {
172 char *default_globlp[] = {
173 /* DMA transfer must start at multiples of 0x100 */
176 ".refresh_OAM=0xFF80",
185 main(int argc, char *argv[])
200 for(i = 0; default_basep[i] != NULL; i++) {
202 basep = (struct base *)new(sizeof(struct base));
205 bsp->b_base = (struct base *)new(sizeof(struct base));
208 bsp->b_strp = default_basep[i];
210 for(i = 0; default_globlp[i] != NULL; i++) {
212 globlp = (struct globl *)new(sizeof(struct globl));
215 gsp->g_globl = (struct globl *)new(sizeof(struct globl));
218 gsp->g_strp = default_globlp[i];
222 fprintf(stdout, "\n");
225 startp = (struct lfile *) new (sizeof (struct lfile));
228 for (i=1; i<argc; ++i) {
231 while (ctype[c = *(++p)] & LETTER) {
236 startp->f_type = F_STD;
241 startp->f_type = F_LNK;
261 startp->f_type = F_CMD;
262 startp->f_idp = (char *)&argv[i+1];
268 if (startp->f_type == F_LNK) {
273 if (startp->f_type == F_INV)
275 if (startp->f_type == F_LNK && startp->f_idp == NULL)
278 if (startp->f_type == F_CMD && startp->f_idp == NULL)
287 if (lk_getline() == 0)
289 if (pflag && sfp != stdin)
290 fprintf(stdout, "%s\n", ip);
291 if (*ip == '\0' || parse())
303 if (linkp->f_flp == NULL)
308 for(i = 1; i < nb_rom_banks; i++) {
309 bsp->b_base = (struct base *)new(sizeof(struct base));
311 bsp->b_strp = (char *)malloc(18);
312 sprintf(bsp->b_strp, "_CODE_%d=0x4000", i);
314 for(i = 0; i < nb_ram_banks; i++) {
315 bsp->b_base = (struct base *)new(sizeof(struct base));
317 bsp->b_strp = (char *)malloc(18);
318 sprintf(bsp->b_strp, "_DATA_%d=0xA000", i);
323 for (pass=0; pass<2; ++pass) {
327 filep = linkp->f_flp;
334 while (lk_getline()) {
340 * Search libraries for global symbols
344 * Set area base addresses.
348 * Link all area addresses.
352 * Process global definitions.
356 * Check for undefined globals.
364 * Output Link Map if requested.
373 ofp = afile(linkp->f_idp, "ihx", 1);
375 ofp = afile(linkp->f_idp, "IHX", 1);
383 ofp = afile(linkp->f_idp, "s19", 1);
385 ofp = afile(linkp->f_idp, "S19", 1);
394 ofp = afile(linkp->f_idp, "", 1);
403 * Link in library files
410 Timer(1, "Linker execution time");
415 /* Never get here. */
419 /*)Function VOID lkexit(i)
423 * The function lkexit() explicitly closes all open
424 * files and then terminates the program.
430 * FILE * mfp file handle for .map
431 * FILE * ofp file handle for .ihx/.s19
432 * FILE * rfp file hanlde for .rst
433 * FILE * sfp file handle for .rel
434 * FILE * tfp file handle for .lst
437 * int fclose() c_library
438 * VOID exit() c_library
441 * All files closed. Program terminates.
447 if (mfp != NULL) fclose(mfp);
448 if (ofp != NULL) fclose(ofp);
449 if (rfp != NULL) fclose(rfp);
450 if (sfp != NULL) fclose(sfp);
451 if (tfp != NULL) fclose(tfp);
455 /*)Function link_main()
457 * The function link_main() evaluates the directives for each line of
458 * text read from the .rel file(s). The valid directives processed
460 * X, D, Q, H, M, A, S, T, R, and P.
463 * int c first non blank character of a line
466 * head *headp The pointer to the first
467 * head structure of a linked list
468 * head *hp Pointer to the current
470 * int pass linker pass number
471 * int radix current number conversion radix
474 * char endline() lklex.c
475 * VOID module() lkhead.c
476 * VOID newarea() lkarea.c
477 * VOID newhead() lkhead.c
478 * sym * newsym() lksym.c
479 * VOID reloc() lkreloc.c
482 * Head, area, and symbol structures are created and
483 * the radix is set as the .rel file(s) are read.
491 if ((c=endline()) == 0) { return; }
494 case 'O': /*For some important sdcc options*/
497 if(strlen(sdccopt)==0)
499 strcpy(sdccopt, &ip[1]);
500 strcpy(sdccopt_module, curr_module);
504 if(strcmp(sdccopt, &ip[1])!=0)
507 "?ASlink-Warning-Conflicting sdcc options:\n"
508 " \"%s\" in module \"%s\" and\n"
509 " \"%s\" in module \"%s\".\n",
510 sdccopt, sdccopt_module, &ip[1], curr_module);
547 strcpy(curr_module, &ip[1]);
555 if (sdp.s_area == NULL) {
557 sdp.s_areax = areap->a_axp;
578 if (c == 'X' || c == 'D' || c == 'Q') {
579 if ((c = get()) == 'H') {
588 /*)Function VOID map()
590 * The function map() opens the output map file and calls the various
592 * (1) output the variables in each area,
593 * (2) list the files processed with module names,
594 * (3) list the libraries file processed,
595 * (4) list base address definitions,
596 * (5) list global variable definitions, and
597 * (6) list any undefined variables.
601 * head * hdp pointer to head structure
602 * lbfile *lbfh pointer to library file structure
605 * area *ap Pointer to the current
607 * area *areap The pointer to the first
608 * area structure of a linked list
609 * base *basep The pointer to the first
611 * base *bsp Pointer to the current
613 * lfile *filep The pointer *filep points to the
614 * beginning of a linked list of
616 * globl *globlp The pointer to the first
618 * globl *gsp Pointer to the current
620 * head *headp The pointer to the first
621 * head structure of a linked list
622 * lbfile *lbfhead The pointer to the first
623 * lbfile structure of a linked list
624 * lfile *linkp pointer to first lfile structure
625 * containing an input REL file
627 * int lop current line number on page
628 * FILE *mfp Map output file handle
629 * int page current page number
632 * FILE * afile() lkmain.c
633 * int fprintf() c_library
634 * VOID lkexit() lkmain.c
635 * VOID lstarea() lklist.c
636 * VOID newpag() lklist.c
637 * VOID symdef() lksym.c
640 * The map file is created.
648 register struct head *hdp;
649 register struct lbfile *lbfh;
655 mfp = afile(linkp->f_idp, "map", 1);
657 mfp = afile(linkp->f_idp, "MAP", 1);
664 * Output Map Area Lists
677 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
680 filep = linkp->f_flp;
685 fprintf(mfp, "%-16s", filep->f_idp);
687 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
689 fprintf(mfp, ", %8.8s", hdp->m_id);
692 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
694 fprintf(mfp, " [ %8.8s", hdp->m_id);
703 filep = filep->f_flp;
706 * List Linked Libraries
708 if (lbfhead != NULL) {
710 "\nLibraries Linked [ object file ]\n\n");
711 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
712 fprintf(mfp, "%-32s [ %16.16s ]\n",
713 lbfh->libspc, lbfh->relfil);
718 * List Base Address Definitions
722 fprintf(mfp, "\nUser Base Address Definitions\n\n");
725 fprintf(mfp, "%s\n", bsp->b_strp);
730 * List Global Definitions
734 fprintf(mfp, "\nUser Global Definitions\n\n");
737 fprintf(mfp, "%s\n", gsp->g_strp);
741 fprintf(mfp, "\n\f");
747 register struct head *hdp;
748 register struct lbfile *lbfh;
754 mfp = afile(linkp->f_idp, "map", 1);
756 mfp = afile(linkp->f_idp, "MAP", 1);
763 *Output Map Area Lists
777 filep = linkp->f_flp;
782 fprintf( mfp, "MODULES\n");
785 fprintf(mfp, "\tFILE %s\n", filep->f_idp);
786 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
787 if (strlen(hdp->m_id)>0)
788 fprintf(mfp, "\t\tNAME %s\n", hdp->m_id);
791 filep = filep->f_flp;
794 * List Linked Libraries
796 if (lbfhead != NULL) {
797 fprintf(mfp, "LIBRARIES\n");
798 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
799 fprintf(mfp, "\tLIBRARY %s\n"
801 lbfh->libspc, lbfh->relfil);
805 * List Base Address Definitions
808 fprintf(mfp, "USERBASEDEF\n");
811 fprintf(mfp, "\t%s\n", bsp->b_strp);
816 * List Global Definitions
819 fprintf(mfp, "USERGLOBALDEF\n");
822 fprintf(mfp, "\t%s\n", gsp->g_strp);
838 VOID lstareatosym(struct area *xp);
845 mfp = afile(linkp->f_idp, "sym", 1);
849 fprintf( mfp, "; no$gmb format .sym file\n"
850 "; Generated automagically by ASxxxx linker %s (SDK " SDK_VERSION_STRING ")\n"
853 * Output sym Area Lists
869 /*)Function int parse()
871 * The function parse() evaluates all command line or file input
872 * linker directives and updates the appropriate variables.
875 * int c character value
876 * char fid[] file id string
879 * char ctype[] array of character types, one per
881 * lfile *lfp pointer to current lfile structure
882 * being processed by parse()
883 * lfile *linkp pointer to first lfile structure
884 * containing an input REL file
886 * int mflag Map output flag
887 * int oflag Output file type flag
888 * int pflag print linker command file flag
889 * FILE * stderr c_library
890 * int uflag Relocated listing flag
891 * int xflag Map file radix type flag
894 * VOID addlib() lklibr.c
895 * VOID addpath() lklibr.c
896 * VOID bassav() lkmain.c
897 * int fprintf() c_library
898 * VOID gblsav() lkmain.c
899 * VOID getfid() lklex.c
900 * char getnb() lklex.c
901 * VOID lkexit() lkmain.c
902 * char * strcpy() c_library
903 * int strlen() c_library
906 * Various linker flags are updated and the linked
907 * structure lfile is created.
916 while ((c = getnb()) != 0) {
920 while (ctype[c=get()] & LETTER) {
936 if(c == 'O' || c == 'o')
937 nb_rom_banks = expr(0);
938 else if(c == 'A' || c == 'a')
939 nb_ram_banks = expr(0);
940 else if(c == 'T' || c == 't')
942 else if(c == 'N' || c == 'n') {
944 if(getnb() != '=' || getnb() != '"') {
945 fprintf(stderr, "Syntax error in -YN=\"name\" flag\n");
948 while((c = get()) != '"' && i < 16) {
956 } else if(c == 'P' || c == 'p') {
959 patches = (patch *)malloc(sizeof(patch));
961 patches->addr = expr(0);
963 fprintf(stderr, "Syntax error in -YHaddr=val flag\n");
966 patches->value = expr(0);
968 fprintf(stderr, "Invalid option\n");
1044 fprintf(stderr, "Invalid option\n");
1050 } else if (ctype[c] & ILL) {
1051 fprintf(stderr, "Invalid input");
1054 if (linkp == NULL) {
1055 linkp = (struct lfile *)
1056 new (sizeof (struct lfile));
1059 lfp->f_flp = (struct lfile *)
1060 new (sizeof (struct lfile));
1064 lfp->f_idp = (char *) new (strlen(fid)+1);
1065 strcpy(lfp->f_idp, fid);
1066 lfp->f_type = F_REL;
1072 /*)Function VOID bassav()
1074 * The function bassav() creates a linked structure containing
1075 * the base address strings input to the linker.
1081 * base *basep The pointer to the first
1083 * base *bsp Pointer to the current
1085 * char *ip pointer into the REL file
1089 * char getnb() lklex.c
1090 * VOID * new() lksym.c
1091 * int strlen() c_library
1092 * char * strcpy() c_library
1093 * VOID unget() lklex.c
1096 * The basep structure is created.
1102 if (basep == NULL) {
1103 basep = (struct base *)
1104 new (sizeof (struct base));
1107 bsp->b_base = (struct base *)
1108 new (sizeof (struct base));
1112 bsp->b_strp = (char *) new (strlen(ip)+1);
1113 strcpy(bsp->b_strp, ip);
1116 /*)Function VOID setbas()
1118 * The function setbas() scans the base address lines in the
1119 * basep structure, evaluates the arguments, and sets beginning
1120 * address of the specified areas.
1123 * int v expression value
1124 * char id[] base id string
1127 * area *ap Pointer to the current
1129 * area *areap The pointer to the first
1130 * area structure of a linked list
1131 * base *basep The pointer to the first
1133 * base *bsp Pointer to the current
1135 * char *ip pointer into the REL file
1137 * int lkerr error flag
1140 * Addr_T expr() lkeval.c
1141 * int fprintf() c_library
1142 * VOID getid() lklex.c
1143 * char getnb() lklex.c
1144 * int symeq() lksym.c
1147 * The base address of an area is set.
1160 if (getnb() == '=') {
1162 for (ap = areap; ap != NULL; ap = ap->a_ap) {
1163 if (symeq(id, ap->a_id))
1169 "ASlink-Warning-No definition of area %s\n", id);
1176 fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1183 /*)Function VOID gblsav()
1185 * The function gblsav() creates a linked structure containing
1186 * the global variable strings input to the linker.
1192 * globl *globlp The pointer to the first
1194 * globl *gsp Pointer to the current
1196 * char *ip pointer into the REL file
1198 * int lkerr error flag
1201 * char getnb() lklex.c
1202 * VOID * new() lksym.c
1203 * int strlen() c_library
1204 * char * strcpy() c_library
1205 * VOID unget() lklex.c
1208 * The globlp structure is created.
1214 if (globlp == NULL) {
1215 globlp = (struct globl *)
1216 new (sizeof (struct globl));
1219 gsp->g_globl = (struct globl *)
1220 new (sizeof (struct globl));
1224 gsp->g_strp = (char *) new (strlen(ip)+1);
1225 strcpy(gsp->g_strp, ip);
1228 /*)Function VOID setgbl()
1230 * The function setgbl() scans the global variable lines in the
1231 * globlp structure, evaluates the arguments, and sets a variable
1235 * int v expression value
1236 * char id[] base id string
1237 * sym * sp pointer to a symbol structure
1240 * char *ip pointer into the REL file
1242 * globl *globlp The pointer to the first
1244 * globl *gsp Pointer to the current
1246 * FILE * stderr c_library
1247 * int lkerr error flag
1250 * Addr_T expr() lkeval.c
1251 * int fprintf() c_library
1252 * VOID getid() lklex.c
1253 * char getnb() lklex.c
1254 * sym * lkpsym() lksym.c
1257 * The value of a variable is set.
1264 register struct sym *sp;
1271 if (getnb() == '=') {
1277 "No definition of symbol %s\n", id);
1282 if (sp->s_flag & S_DEF) {
1284 "Redefinition of symbol %s\n", id);
1290 sp->s_type |= S_DEF;
1293 fprintf(stderr, "No '=' in global expression");
1300 /*)Function FILE * afile(fn,, ft, wf)
1302 * char * fn file specification string
1303 * char * ft file type string
1304 * int wf read(0)/write(1) flag
1306 * The function afile() opens a file for reading or writing.
1307 * (1) If the file type specification string ft
1308 * is not NULL then a file specification is
1309 * constructed with the file path\name in fn
1310 * and the extension in ft.
1311 * (2) If the file type specification string ft
1312 * is NULL then the file specification is
1313 * constructed from fn. If fn does not have
1314 * a file type then the default .rel file
1315 * type is appended to the file specification.
1317 * afile() returns a file handle for the opened file or aborts
1318 * the assembler on an open error.
1321 * int c character value
1322 * char fb[] constructed file specification string
1323 * FILE * fp filehandle for opened file
1324 * char * p1 pointer to filespec string fn
1325 * char * p2 pointer to filespec string fb
1326 * char * p3 pointer to filetype string ft
1329 * int lkerr error flag
1332 * FILE * fopen() c_library
1333 * int fprintf() c_library
1336 * File is opened for read or write.
1340 afile(char *fn, char *ft, int wf)
1343 register char *p1, *p2, *p3;
1355 while ((c = *p1++) != 0 && c != FSEPX) {
1356 if (p2 < &fb[PATH_MAX-4])
1371 while ((c = *p3++) != 0) {
1372 if (p2 < &fb[FILSPC-1])
1377 /*Look backward the name path and get rid of the extension, if any*/
1379 for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>0); i--);
1380 if( (fn[i]=='.') && *ft && strcmp(ft, "lnk") )
1390 /*Add the extension*/
1395 strcat(fb, strlen(ft)?ft:"rel");
1397 strcat(fb, strlen(ft)?ft:"REL");
1403 if ((fp = fopen(fb, wf?(binary?"wb":"w"):(binary?"rb":"r"))) == NULL) {
1405 if ((fp = fopen(fb, wf?"w":"r")) == NULL) {
1407 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1415 "Distributed with SDK " SDK_VERSION_STRING ", built on " __DATE__ " " __TIME__,
1416 "Compile options: SDK Target " TARGET_STRING
1423 " -c Command line input",
1424 " -f file[LNK] File input",
1425 " -p Prompt and echo of file[LNK] to stdout (default)",
1426 " -n No echo of file[LNK] to stdout",
1428 "Usage: [-Options] outfile file [file ...]",
1430 "Usage: [-Options] file [file ...]",
1433 " -k Library path specification, one per -k",
1434 " -l Library file specification, one per -l",
1436 " -b area base address = expression",
1437 " -g global symbol = expression",
1439 " -yo Number of rom banks (default: 2)",
1440 " -ya Number of ram banks (default: 0)",
1441 " -yt MBC type (default: no MBC)",
1442 " -yn Name of program (default: name of output file)",
1443 " -yp# Patch one byte in the output GB file (# is: addr=byte)",
1444 #endif /* GAMEBOY */
1446 " -m Map output generated as file[MAP]",
1448 " -j no$gmb symbol file generated as file[SYM]",
1450 " -x Hexadecimal (default), -d Decimal, -q Octal",
1452 " -i Intel Hex as file[IHX]",
1453 " -s Motorola S19 as file[S19]",
1456 " -z Gamegear image as file[GG]",
1458 " -z Gameboy image as file[GB]",
1459 #endif /* GAMEGEAR */
1462 " -u Update listing file(s) with link data as file(s)[.RST]",
1464 " -e or null line terminates input",
1469 /*)Function VOID usage()
1471 * The function usage() outputs to the stderr device the
1472 * assembler name and version and a list of valid assembler options.
1475 * char ** dp pointer to an array of
1476 * text string pointers.
1479 * FILE * stderr c_library
1482 * int fprintf() c_library
1493 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1494 for (dp = usetxt; *dp; dp++)
1495 fprintf(stderr, "%s\n", *dp);
1499 /*)Function VOID copyfile()
1501 * FILE *dest destination file
1502 * FILE *src source file
1504 * function will copy source file to destination file
1508 * int fgetc() c_library
1509 * int fputc() c_library
1514 VOID copyfile (dest,src)
1519 while ((ch = fgetc(src)) != EOF) {