3 Copyright (C) 1989-1995 Alan R. Baldwin
4 721 Berkeley St., Kent, Ohio 44240
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 * Extensions: P. Felber
28 #ifndef SDK_VERSION_STRING
29 #define SDK_VERSION_STRING "3.0.0"
32 #define TARGET_STRING "gbz80"
38 void Timer(int action, char * message)
40 static double start, end, total=0.0;
41 static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
43 if(action==0) start=clock()*secs_per_tick;
46 end=clock() * secs_per_tick;
47 printf("%s \t%f seconds.\n", message, (end-start));
52 printf("Total time: \t%f seconds.\n", total);
60 * The module lkmain.c contains the functions which
61 * (1) input the linker options, parameters, and specifications
62 * (2) perform a two pass link
63 * (3) produce the appropriate linked data output and/or
64 * link map file and/or relocated listing files.
66 * lkmain.c contains the following functions:
67 * FILE * afile(fn,ft,wf)
72 * VOID main(argc,argv)
79 * lkmain.c contains the following local variables:
80 * char * usetext[] array of pointers to the
81 * command option tect lines
85 /*)Function VOID main(argc,argv)
87 * int argc number of command line arguments + 1
88 * char * argv[] array of pointers to the command line
91 * The function main() evaluates the command line arguments to
92 * determine if the linker parameters are to input through 'stdin'
93 * or read from a command file. The functions lk_getline() and parse()
94 * are to input and evaluate the linker parameters. The linking process
95 * proceeds by making the first pass through each .rel file in the order
96 * presented to the linker. At the end of the first pass the setbase(),
97 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
98 * the base address terms, link all areas, define global variables,
99 * and look for undefined symbols. Following these routines a linker
100 * map file may be produced and the linker output files may be opened.
101 * The second pass through the .rel files will output the linked data
102 * in one of the four supported formats.
105 * char * p pointer to an argument string
106 * int c character from argument string
111 * lfile *cfp The pointer *cfp points to the
112 * current lfile structure
113 * char ctype[] array of character types, one per
115 * lfile *filep The pointer *filep points to the
116 * beginning of a linked list of
118 * head *hp Pointer to the current
120 * char ib[NINPUT] .rel file text line
121 * char *ip pointer into the .rel file
122 * lfile *linkp pointer to first lfile structure
123 * containing an input .rel file
125 * int lkerr error flag
126 * int mflag Map output flag
127 * int oflag Output file type flag
128 * FILE *ofp Output file handle
130 * FILE *ofph Output file handle
131 * for high byte format
132 * FILE *ofpl Output file handle
133 * for low byte format
134 * int pass linker pass number
135 * int pflag print linker command file flag
136 * int radix current number conversion radix
137 * FILE *sfp The file handle sfp points to the
138 * currently open file
139 * lfile *startp asmlnk startup file structure
140 * FILE * stdin c_library
141 * FILE * stdout c_library
144 * FILE * afile() lkmain.c
145 * int fclose() c_library
146 * int fprintf() c_library
147 * int lk_getline() lklex.c
148 * VOID library() lklibr.c
149 * VOID link_main() lkmain.c
150 * VOID lkexit() lkmain.c
151 * VOID lnkarea() lkarea.c
152 * VOID map() lkmain.c
154 * int parse() lkmain.c
155 * VOID reloc() lkreloc.c
156 * VOID search() lklibr.c
157 * VOID setbas() lkmain.c
158 * VOID setgbl() lkmain.c
159 * VOID symdef() lksym.c
160 * VOID usage() lkmain.c
163 * Completion of main() completes the linking process
164 * and may produce a map file (.map) and/or a linked
165 * data files (.ihx or .s19) and/or one or more
166 * relocated listing files (.rst).
173 char *default_basep[] = {
179 char *default_globlp[] = {
180 /* DMA transfer must start at multiples of 0x100 */
183 ".refresh_OAM=0xFF80",
192 main(int argc, char *argv[])
207 for(i = 0; default_basep[i] != NULL; i++) {
209 basep = (struct base *)new(sizeof(struct base));
212 bsp->b_base = (struct base *)new(sizeof(struct base));
215 bsp->b_strp = default_basep[i];
217 for(i = 0; default_globlp[i] != NULL; i++) {
219 globlp = (struct globl *)new(sizeof(struct globl));
222 gsp->g_globl = (struct globl *)new(sizeof(struct globl));
225 gsp->g_strp = default_globlp[i];
229 fprintf(stdout, "\n");
232 startp = (struct lfile *) new (sizeof (struct lfile));
235 for (i=1; i<argc; ++i) {
238 while (ctype[c = *(++p)] & LETTER) {
243 startp->f_type = F_STD;
248 startp->f_type = F_LNK;
268 startp->f_type = F_CMD;
269 startp->f_idp = (char *)&argv[i+1];
275 if (startp->f_type == F_LNK) {
280 if (startp->f_type == F_INV)
282 if (startp->f_type == F_LNK && startp->f_idp == NULL)
285 if (startp->f_type == F_CMD && startp->f_idp == NULL)
294 if (lk_getline() == 0)
296 if (pflag && sfp != stdin)
297 fprintf(stdout, "%s\n", ip);
298 if (*ip == '\0' || parse())
310 if (linkp->f_flp == NULL)
315 for(i = 1; i < nb_rom_banks; i++) {
316 bsp->b_base = (struct base *)new(sizeof(struct base));
318 bsp->b_strp = (char *)malloc(18);
319 sprintf(bsp->b_strp, "_CODE_%d=0x4000", i);
321 for(i = 0; i < nb_ram_banks; i++) {
322 bsp->b_base = (struct base *)new(sizeof(struct base));
324 bsp->b_strp = (char *)malloc(18);
325 sprintf(bsp->b_strp, "_DATA_%d=0xA000", i);
332 SaveLinkedFilePath(linkp->f_idp); //Must be the first one...
333 dfp = afile(linkp->f_idp,"cdb",1);
338 for (pass=0; pass<2; ++pass) {
342 filep = linkp->f_flp;
349 while (lk_getline()) {
355 * Search libraries for global symbols
359 * Set area base addresses.
363 * Link all area addresses.
367 * Process global definitions.
371 * Check for undefined globals.
379 * Output Link Map if requested.
388 ofp = afile(linkp->f_idp, "ihx", 1);
390 ofp = afile(linkp->f_idp, "IHX", 1);
398 ofp = afile(linkp->f_idp, "s19", 1);
400 ofp = afile(linkp->f_idp, "S19", 1);
409 ofp = afile(linkp->f_idp, "", 1);
418 * Link in library files
425 Timer(1, "Linker execution time");
430 /* Never get here. */
434 /*)Function VOID lkexit(i)
438 * The function lkexit() explicitly closes all open
439 * files and then terminates the program.
445 * FILE * mfp file handle for .map
446 * FILE * ofp file handle for .ihx/.s19
447 * FILE * rfp file hanlde for .rst
448 * FILE * sfp file handle for .rel
449 * FILE * tfp file handle for .lst
452 * int fclose() c_library
453 * VOID exit() c_library
456 * All files closed. Program terminates.
462 if (mfp != NULL) fclose(mfp);
463 if (ofp != NULL) fclose(ofp);
464 if (rfp != NULL) fclose(rfp);
465 if (sfp != NULL) fclose(sfp);
466 if (tfp != NULL) fclose(tfp);
467 if (dfp != NULL) fclose(dfp);
471 /*)Function link_main()
473 * The function link_main() evaluates the directives for each line of
474 * text read from the .rel file(s). The valid directives processed
476 * X, D, Q, H, M, A, S, T, R, and P.
479 * int c first non blank character of a line
482 * head *headp The pointer to the first
483 * head structure of a linked list
484 * head *hp Pointer to the current
486 * int pass linker pass number
487 * int radix current number conversion radix
490 * char endline() lklex.c
491 * VOID module() lkhead.c
492 * VOID newarea() lkarea.c
493 * VOID newhead() lkhead.c
494 * sym * newsym() lksym.c
495 * VOID reloc() lkreloc.c
498 * Head, area, and symbol structures are created and
499 * the radix is set as the .rel file(s) are read.
507 if ((c=endline()) == 0) { return; }
510 case 'O': /*For some important sdcc options*/
513 if(strlen(sdccopt)==0)
515 strcpy(sdccopt, &ip[1]);
516 strcpy(sdccopt_module, curr_module);
520 if(strcmp(sdccopt, &ip[1])!=0)
523 "?ASlink-Warning-Conflicting sdcc options:\n"
524 " \"%s\" in module \"%s\" and\n"
525 " \"%s\" in module \"%s\".\n",
526 sdccopt, sdccopt_module, &ip[1], curr_module);
563 strcpy(curr_module, &ip[1]);
571 if (sdp.s_area == NULL) {
573 sdp.s_areax = areap->a_axp;
594 if (c == 'X' || c == 'D' || c == 'Q') {
595 if ((c = get()) == 'H') {
604 /*)Function VOID map()
606 * The function map() opens the output map file and calls the various
608 * (1) output the variables in each area,
609 * (2) list the files processed with module names,
610 * (3) list the libraries file processed,
611 * (4) list base address definitions,
612 * (5) list global variable definitions, and
613 * (6) list any undefined variables.
617 * head * hdp pointer to head structure
618 * lbfile *lbfh pointer to library file structure
621 * area *ap Pointer to the current
623 * area *areap The pointer to the first
624 * area structure of a linked list
625 * base *basep The pointer to the first
627 * base *bsp Pointer to the current
629 * lfile *filep The pointer *filep points to the
630 * beginning of a linked list of
632 * globl *globlp The pointer to the first
634 * globl *gsp Pointer to the current
636 * head *headp The pointer to the first
637 * head structure of a linked list
638 * lbfile *lbfhead The pointer to the first
639 * lbfile structure of a linked list
640 * lfile *linkp pointer to first lfile structure
641 * containing an input REL file
643 * int lop current line number on page
644 * FILE *mfp Map output file handle
645 * int page current page number
648 * FILE * afile() lkmain.c
649 * int fprintf() c_library
650 * VOID lkexit() lkmain.c
651 * VOID lstarea() lklist.c
652 * VOID newpag() lklist.c
653 * VOID symdef() lksym.c
656 * The map file is created.
664 register struct head *hdp;
665 register struct lbfile *lbfh;
671 mfp = afile(linkp->f_idp, "map", 1);
673 mfp = afile(linkp->f_idp, "MAP", 1);
680 * Output Map Area Lists
693 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
696 filep = linkp->f_flp;
701 fprintf(mfp, "%-16s", filep->f_idp);
703 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
705 fprintf(mfp, ", %8.8s", hdp->m_id);
708 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
710 fprintf(mfp, " [ %8.8s", hdp->m_id);
719 filep = filep->f_flp;
722 * List Linked Libraries
724 if (lbfhead != NULL) {
726 "\nLibraries Linked [ object file ]\n\n");
727 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
728 fprintf(mfp, "%-32s [ %16.16s ]\n",
729 lbfh->libspc, lbfh->relfil);
734 * List Base Address Definitions
738 fprintf(mfp, "\nUser Base Address Definitions\n\n");
741 fprintf(mfp, "%s\n", bsp->b_strp);
746 * List Global Definitions
750 fprintf(mfp, "\nUser Global Definitions\n\n");
753 fprintf(mfp, "%s\n", gsp->g_strp);
757 fprintf(mfp, "\n\f");
763 register struct head *hdp;
764 register struct lbfile *lbfh;
770 mfp = afile(linkp->f_idp, "map", 1);
772 mfp = afile(linkp->f_idp, "MAP", 1);
779 *Output Map Area Lists
793 filep = linkp->f_flp;
798 fprintf( mfp, "MODULES\n");
801 fprintf(mfp, "\tFILE %s\n", filep->f_idp);
802 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
803 if (strlen(hdp->m_id)>0)
804 fprintf(mfp, "\t\tNAME %s\n", hdp->m_id);
807 filep = filep->f_flp;
810 * List Linked Libraries
812 if (lbfhead != NULL) {
813 fprintf(mfp, "LIBRARIES\n");
814 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
815 fprintf(mfp, "\tLIBRARY %s\n"
817 lbfh->libspc, lbfh->relfil);
821 * List Base Address Definitions
824 fprintf(mfp, "USERBASEDEF\n");
827 fprintf(mfp, "\t%s\n", bsp->b_strp);
832 * List Global Definitions
835 fprintf(mfp, "USERGLOBALDEF\n");
838 fprintf(mfp, "\t%s\n", gsp->g_strp);
854 VOID lstareatosym(struct area *xp);
861 mfp = afile(linkp->f_idp, "sym", 1);
865 fprintf( mfp, "; no$gmb format .sym file\n"
866 "; Generated automagically by ASxxxx linker %s (SDK " SDK_VERSION_STRING ")\n"
869 * Output sym Area Lists
885 /*)Function int parse()
887 * The function parse() evaluates all command line or file input
888 * linker directives and updates the appropriate variables.
891 * int c character value
892 * char fid[] file id string
895 * char ctype[] array of character types, one per
897 * lfile *lfp pointer to current lfile structure
898 * being processed by parse()
899 * lfile *linkp pointer to first lfile structure
900 * containing an input REL file
902 * int mflag Map output flag
903 * int oflag Output file type flag
904 * int pflag print linker command file flag
905 * FILE * stderr c_library
906 * int uflag Relocated listing flag
907 * int xflag Map file radix type flag
910 * VOID addlib() lklibr.c
911 * VOID addpath() lklibr.c
912 * VOID bassav() lkmain.c
913 * int fprintf() c_library
914 * VOID gblsav() lkmain.c
915 * VOID getfid() lklex.c
916 * char getnb() lklex.c
917 * VOID lkexit() lkmain.c
918 * char * strcpy() c_library
919 * int strlen() c_library
922 * Various linker flags are updated and the linked
923 * structure lfile is created.
932 while ((c = getnb()) != 0) {
936 while (ctype[c=get()] & LETTER) {
952 if(c == 'O' || c == 'o')
953 nb_rom_banks = expr(0);
954 else if(c == 'A' || c == 'a')
955 nb_ram_banks = expr(0);
956 else if(c == 'T' || c == 't')
958 else if(c == 'N' || c == 'n') {
960 if(getnb() != '=' || getnb() != '"') {
961 fprintf(stderr, "Syntax error in -YN=\"name\" flag\n");
964 while((c = get()) != '"' && i < 16) {
972 } else if(c == 'P' || c == 'p') {
975 patches = (patch *)malloc(sizeof(patch));
977 patches->addr = expr(0);
979 fprintf(stderr, "Syntax error in -YHaddr=val flag\n");
982 patches->value = expr(0);
984 fprintf(stderr, "Invalid option\n");
1063 fprintf(stderr, "Invalid option\n");
1069 } else if (ctype[c] & ILL) {
1070 fprintf(stderr, "Invalid input");
1073 if (linkp == NULL) {
1074 linkp = (struct lfile *)
1075 new (sizeof (struct lfile));
1078 lfp->f_flp = (struct lfile *)
1079 new (sizeof (struct lfile));
1083 lfp->f_idp = (char *) new (strlen(fid)+1);
1084 strcpy(lfp->f_idp, fid);
1085 lfp->f_type = F_REL;
1091 /*)Function VOID bassav()
1093 * The function bassav() creates a linked structure containing
1094 * the base address strings input to the linker.
1100 * base *basep The pointer to the first
1102 * base *bsp Pointer to the current
1104 * char *ip pointer into the REL file
1108 * char getnb() lklex.c
1109 * VOID * new() lksym.c
1110 * int strlen() c_library
1111 * char * strcpy() c_library
1112 * VOID unget() lklex.c
1115 * The basep structure is created.
1121 if (basep == NULL) {
1122 basep = (struct base *)
1123 new (sizeof (struct base));
1126 bsp->b_base = (struct base *)
1127 new (sizeof (struct base));
1131 bsp->b_strp = (char *) new (strlen(ip)+1);
1132 strcpy(bsp->b_strp, ip);
1135 /*)Function VOID setbas()
1137 * The function setbas() scans the base address lines in the
1138 * basep structure, evaluates the arguments, and sets beginning
1139 * address of the specified areas.
1142 * int v expression value
1143 * char id[] base id string
1146 * area *ap Pointer to the current
1148 * area *areap The pointer to the first
1149 * area structure of a linked list
1150 * base *basep The pointer to the first
1152 * base *bsp Pointer to the current
1154 * char *ip pointer into the REL file
1156 * int lkerr error flag
1159 * Addr_T expr() lkeval.c
1160 * int fprintf() c_library
1161 * VOID getid() lklex.c
1162 * char getnb() lklex.c
1163 * int symeq() lksym.c
1166 * The base address of an area is set.
1179 if (getnb() == '=') {
1181 for (ap = areap; ap != NULL; ap = ap->a_ap) {
1182 if (symeq(id, ap->a_id))
1188 "ASlink-Warning-No definition of area %s\n", id);
1195 fprintf(stderr, "ASlink-Warning-No '=' in base expression");
1202 /*)Function VOID gblsav()
1204 * The function gblsav() creates a linked structure containing
1205 * the global variable strings input to the linker.
1211 * globl *globlp The pointer to the first
1213 * globl *gsp Pointer to the current
1215 * char *ip pointer into the REL file
1217 * int lkerr error flag
1220 * char getnb() lklex.c
1221 * VOID * new() lksym.c
1222 * int strlen() c_library
1223 * char * strcpy() c_library
1224 * VOID unget() lklex.c
1227 * The globlp structure is created.
1233 if (globlp == NULL) {
1234 globlp = (struct globl *)
1235 new (sizeof (struct globl));
1238 gsp->g_globl = (struct globl *)
1239 new (sizeof (struct globl));
1243 gsp->g_strp = (char *) new (strlen(ip)+1);
1244 strcpy(gsp->g_strp, ip);
1247 /*)Function VOID setgbl()
1249 * The function setgbl() scans the global variable lines in the
1250 * globlp structure, evaluates the arguments, and sets a variable
1254 * int v expression value
1255 * char id[] base id string
1256 * sym * sp pointer to a symbol structure
1259 * char *ip pointer into the REL file
1261 * globl *globlp The pointer to the first
1263 * globl *gsp Pointer to the current
1265 * FILE * stderr c_library
1266 * int lkerr error flag
1269 * Addr_T expr() lkeval.c
1270 * int fprintf() c_library
1271 * VOID getid() lklex.c
1272 * char getnb() lklex.c
1273 * sym * lkpsym() lksym.c
1276 * The value of a variable is set.
1283 register struct sym *sp;
1290 if (getnb() == '=') {
1296 "No definition of symbol %s\n", id);
1301 if (sp->s_flag & S_DEF) {
1303 "Redefinition of symbol %s\n", id);
1309 sp->s_type |= S_DEF;
1312 fprintf(stderr, "No '=' in global expression");
1319 /*)Function FILE * afile(fn,, ft, wf)
1321 * char * fn file specification string
1322 * char * ft file type string
1323 * int wf read(0)/write(1) flag
1325 * The function afile() opens a file for reading or writing.
1326 * (1) If the file type specification string ft
1327 * is not NULL then a file specification is
1328 * constructed with the file path\name in fn
1329 * and the extension in ft.
1330 * (2) If the file type specification string ft
1331 * is NULL then the file specification is
1332 * constructed from fn. If fn does not have
1333 * a file type then the default .rel file
1334 * type is appended to the file specification.
1336 * afile() returns a file handle for the opened file or aborts
1337 * the assembler on an open error.
1340 * int c character value
1341 * char fb[] constructed file specification string
1342 * FILE * fp filehandle for opened file
1343 * char * p1 pointer to filespec string fn
1344 * char * p2 pointer to filespec string fb
1345 * char * p3 pointer to filetype string ft
1348 * int lkerr error flag
1351 * FILE * fopen() c_library
1352 * int fprintf() c_library
1355 * File is opened for read or write.
1359 afile(char *fn, char *ft, int wf)
1362 register char *p1, *p2, *p3;
1374 while ((c = *p1++) != 0 && c != FSEPX) {
1375 if (p2 < &fb[PATH_MAX-4])
1390 while ((c = *p3++) != 0) {
1391 if (p2 < &fb[FILSPC-1])
1396 /*Look backward the name path and get rid of the extension, if any*/
1398 for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>0); i--);
1399 if( (fn[i]=='.') && *ft && strcmp(ft, "lnk") )
1409 /*Add the extension*/
1414 strcat(fb, strlen(ft)?ft:"rel");
1416 strcat(fb, strlen(ft)?ft:"REL");
1422 if ((fp = fopen(fb, wf?(binary?"wb":"w"):(binary?"rb":"r"))) == NULL) {
1424 if ((fp = fopen(fb, wf?"w":"r")) == NULL) {
1426 if (strcmp(ft,"adb"))/*Do not complaint for optional adb files*/
1428 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1437 "Distributed with SDK " SDK_VERSION_STRING ", built on " __DATE__ " " __TIME__,
1438 "Compile options: SDK Target " TARGET_STRING
1445 " -c Command line input",
1446 " -f file[LNK] File input",
1447 " -p Prompt and echo of file[LNK] to stdout (default)",
1448 " -n No echo of file[LNK] to stdout",
1451 "Usage: [-Options] outfile file [file ...]",
1453 "Usage: [-Options] file [file ...]",
1457 " -k Library path specification, one per -k",
1458 " -l Library file specification, one per -l",
1460 " -b area base address = expression",
1461 " -g global symbol = expression",
1463 " -yo Number of rom banks (default: 2)",
1464 " -ya Number of ram banks (default: 0)",
1465 " -yt MBC type (default: no MBC)",
1466 " -yn Name of program (default: name of output file)",
1467 " -yp# Patch one byte in the output GB file (# is: addr=byte)",
1468 #endif /* GAMEBOY */
1470 " -m Map output generated as file[MAP]",
1472 " -j no$gmb symbol file generated as file[SYM]",
1474 " -x Hexadecimal (default), -d Decimal, -q Octal",
1476 " -i Intel Hex as file[IHX]",
1477 " -s Motorola S19 as file[S19]",
1479 " -z Produce SDCdb debug as file[cdb]",
1483 " -Z Gamegear image as file[GG]",
1485 " -Z Gameboy image as file[GB]",
1486 #endif /* GAMEGEAR */
1489 " -u Update listing file(s) with link data as file(s)[.RST]",
1491 " -e or null line terminates input",
1496 /*)Function VOID usage()
1498 * The function usage() outputs to the stderr device the
1499 * assembler name and version and a list of valid assembler options.
1502 * char ** dp pointer to an array of
1503 * text string pointers.
1506 * FILE * stderr c_library
1509 * int fprintf() c_library
1520 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1521 for (dp = usetxt; *dp; dp++)
1522 fprintf(stderr, "%s\n", *dp);
1526 /*)Function VOID copyfile()
1528 * FILE *dest destination file
1529 * FILE *src source file
1531 * function will copy source file to destination file
1535 * int fgetc() c_library
1536 * int fputc() c_library
1541 VOID copyfile (dest,src)
1546 while ((ch = fgetc(src)) != EOF) {