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
26 /* yuck - but including unistd.h causes problems on Cygwin by redefining
29 extern int unlink(const char *);
33 * The module lkmain.c contains the functions which
34 * (1) input the linker options, parameters, and specifications
35 * (2) perform a two pass link
36 * (3) produce the appropriate linked data output and/or
37 * link map file and/or relocated listing files.
39 * lkmain.c contains the following functions:
40 * FILE * afile(fn,ft,wf)
45 * VOID main(argc,argv)
52 * lkmain.c contains the following local variables:
53 * char * usetext[] array of pointers to the
54 * command option tect lines
58 /*)Function VOID main(argc,argv)
60 * int argc number of command line arguments + 1
61 * char * argv[] array of pointers to the command line
64 * The function main() evaluates the command line arguments to
65 * determine if the linker parameters are to input through 'stdin'
66 * or read from a command file. The functiond getline() and parse()
67 * are to input and evaluate the linker parameters. The linking process
68 * proceeds by making the first pass through each .rel file in the order
69 * presented to the linker. At the end of the first pass the setbase(),
70 * lnkarea(), setgbl(), and symdef() functions are called to evaluate
71 * the base address terms, link all areas, define global variables,
72 * and look for undefined symbols. Following these routines a linker
73 * map file may be produced and the linker output files may be opened.
74 * The second pass through the .rel files will output the linked data
75 * in one of the four supported formats.
78 * char * p pointer to an argument string
79 * int c character from argument string
84 * lfile *cfp The pointer *cfp points to the
85 * current lfile structure
86 * char ctype[] array of character types, one per
88 * lfile *filep The pointer *filep points to the
89 * beginning of a linked list of
91 * head *hp Pointer to the current
93 * char ib[NINPUT] .rel file text line
94 * char *ip pointer into the .rel file
95 * lfile *linkp pointer to first lfile structure
96 * containing an input .rel file
98 * int lkerr error flag
99 * int mflag Map output flag
100 * int oflag Output file type flag
101 * FILE *ofp Output file handle
103 * FILE *ofph Output file handle
104 * for high byte format
105 * FILE *ofpl Output file handle
106 * for low byte format
107 * int pass linker pass number
108 * int pflag print linker command file flag
109 * int radix current number conversion radix
110 * FILE *sfp The file handle sfp points to the
111 * currently open file
112 * lfile *startp asmlnk startup file structure
113 * FILE * stdin c_library
114 * FILE * stdout c_library
117 * FILE * afile() lkmain.c
118 * int fclose() c_library
119 * int fprintf() c_library
120 * int getline() lklex.c
121 * VOID library() lklibr.c
122 * VOID link_main() lkmain.c
123 * VOID lkexit() lkmain.c
124 * VOID lnkarea() lkarea.c
125 * VOID map() lkmain.c
127 * int parse() lkmain.c
128 * VOID reloc() lkreloc.c
129 * VOID search() lklibr.c
130 * VOID setbas() lkmain.c
131 * VOID setgbl() lkmain.c
132 * VOID symdef() lksym.c
133 * VOID usage() lkmain.c
136 * Completion of main() completes the linking process
137 * and may produce a map file (.map) and/or a linked
138 * data files (.ihx or .s19) and/or one or more
139 * relocated listing files (.rst).
149 fprintf(stdout, "\n");
151 startp = (struct lfile *) new (sizeof (struct lfile));
154 for (i=1; i<argc; ++i) {
157 while (ctype[c = *(++p)] & LETTER) {
162 startp->f_type = F_STD;
167 startp->f_type = F_LNK;
185 if (startp->f_type == F_LNK) {
190 if (startp->f_type == 0)
192 if (startp->f_type == F_LNK && startp->f_idp == NULL)
202 if (pflag && sfp != stdin)
203 fprintf(stdout, "%s\n", ip);
204 if (*ip == '\0' || parse())
219 dfp = afile("temp", "cdb", 1);
224 for (pass=0; pass<2; ++pass) {
234 /* pass any "magic comments" to NoICE output */
235 if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
236 fprintf( jfp, "%s\n", &ip[2] );
242 * Search libraries for global symbols
246 * Set area base addresses.
250 * Link all area addresses.
254 * Process global definitions.
258 * Check for undefined globals.
262 /* Open NoICE output file if requested */
264 jfp = afile(linkp->f_idp, "NOI", 1);
271 * Output Link Map if requested,
272 * or if NoICE output requested (since NoICE
273 * file is generated in part by map() processing)
285 ofp = afile(linkp->f_idp, "ihx", 1);
289 /* include NoICE command to load hex file */
290 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
294 ofp = afile(linkp->f_idp, "S19", 1);
298 /* include NoICE command to load hex file */
299 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
303 * Link in library files
313 /*)Function VOID lkexit(i)
317 * The function lkexit() explicitly closes all open
318 * files and then terminates the program.
324 * FILE * mfp file handle for .map
325 * FILE * ofp file handle for .ihx/.s19
326 * FILE * rfp file hanlde for .rst
327 * FILE * sfp file handle for .rel
328 * FILE * tfp file handle for .lst
331 * int fclose() c_library
332 * VOID exit() c_library
335 * All files closed. Program terminates.
342 if (mfp != NULL) fclose(mfp);
343 if (jfp != NULL) fclose(jfp);
344 if (ofp != NULL) fclose(ofp);
345 if (rfp != NULL) fclose(rfp);
346 if (sfp != NULL) fclose(sfp);
347 if (tfp != NULL) fclose(tfp);
349 FILE *xfp = afile(linkp->f_idp,"cdb",1);
350 dfp = freopen("temp.cdb","r",dfp);
359 /*)Function link_main()
361 * The function link_main() evaluates the directives for each line of
362 * text read from the .rel file(s). The valid directives processed
364 * X, D, Q, H, M, A, S, T, R, and P.
367 * int c first non blank character of a line
370 * head *headp The pointer to the first
371 * head structure of a linked list
372 * head *hp Pointer to the current
374 * int pass linker pass number
375 * int radix current number conversion radix
378 * char endline() lklex.c
379 * VOID module() lkhead.c
380 * VOID newarea() lkarea.c
381 * VOID newhead() lkhead.c
382 * sym * newsym() lksym.c
383 * VOID reloc() lkreloc.c
386 * Head, area, and symbol structures are created and
387 * the radix is set as the .rel file(s) are read.
395 if ((c=endline()) == 0) { return; }
423 lastExtendedAddress = -1;
434 if (sdp.s_area == NULL) {
436 sdp.s_areax = areap->a_axp;
457 if (c == 'X' || c == 'D' || c == 'Q') {
458 if ((c = get()) == 'H') {
468 /*)Function VOID map()
470 * The function map() opens the output map file and calls the various
472 * (1) output the variables in each area,
473 * (2) list the files processed with module names,
474 * (3) list the libraries file processed,
475 * (4) list base address definitions,
476 * (5) list global variable definitions, and
477 * (6) list any undefined variables.
481 * head * hdp pointer to head structure
482 * lbfile *lbfh pointer to library file structure
485 * area *ap Pointer to the current
487 * area *areap The pointer to the first
488 * area structure of a linked list
489 * base *basep The pointer to the first
491 * base *bsp Pointer to the current
493 * lfile *filep The pointer *filep points to the
494 * beginning of a linked list of
496 * globl *globlp The pointer to the first
498 * globl *gsp Pointer to the current
500 * head *headp The pointer to the first
501 * head structure of a linked list
502 * lbfile *lbfhead The pointer to the first
503 * lbfile structure of a linked list
504 * lfile *linkp pointer to first lfile structure
505 * containing an input REL file
507 * int lop current line number on page
508 * FILE *mfp Map output file handle
509 * int page current page number
512 * FILE * afile() lkmain.c
513 * int fprintf() c_library
514 * VOID lkexit() lkmain.c
515 * VOID lstarea() lklist.c
516 * VOID newpag() lklist.c
517 * VOID symdef() lksym.c
520 * The map file is created.
527 register struct head *hdp;
528 register struct lbfile *lbfh;
533 mfp = afile(linkp->f_idp, "map", 1);
539 * Output Map Area Lists
552 fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
556 fprintf(mfp, "%-16s", filep->f_idp);
558 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
560 fprintf(mfp, ", %8.8s", hdp->m_id);
563 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
565 fprintf(mfp, " [ %8.8s", hdp->m_id);
574 filep = filep->f_flp;
577 * List Linked Libraries
579 if (lbfhead != NULL) {
581 "\nLibraries Linked [ object file ]\n\n");
582 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
583 fprintf(mfp, "%-32s [ %16.16s ]\n",
584 lbfh->libspc, lbfh->relfil);
589 * List Base Address Definitions
593 fprintf(mfp, "\nUser Base Address Definitions\n\n");
596 fprintf(mfp, "%s\n", bsp->b_strp);
601 * List Global Definitions
605 fprintf(mfp, "\nUser Global Definitions\n\n");
608 fprintf(mfp, "%s\n", gsp->g_strp);
612 fprintf(mfp, "\n\f");
616 /*)Function int parse()
618 * The function parse() evaluates all command line or file input
619 * linker directives and updates the appropriate variables.
622 * int c character value
623 * char fid[] file id string
626 * char ctype[] array of character types, one per
628 * lfile *lfp pointer to current lfile structure
629 * being processed by parse()
630 * lfile *linkp pointer to first lfile structure
631 * containing an input REL file
633 * int mflag Map output flag
634 * int oflag Output file type flag
635 * int pflag print linker command file flag
636 * FILE * stderr c_library
637 * int uflag Relocated listing flag
638 * int xflag Map file radix type flag
641 * VOID addlib() lklibr.c
642 * VOID addpath() lklibr.c
643 * VOID bassav() lkmain.c
644 * int fprintf() c_library
645 * VOID gblsav() lkmain.c
646 * VOID getfid() lklex.c
647 * char getnb() lklex.c
648 * VOID lkexit() lkmain.c
649 * char * strcpy() c_library
650 * int strlen() c_library
653 * Various linker flags are updated and the linked
654 * structure lfile is created.
663 while ((c = getnb()) != 0) {
665 while (ctype[c=get()] & LETTER) {
755 fprintf(stderr, "Invalid option\n");
760 if (ctype[c] & ILL) {
761 fprintf(stderr, "Invalid input");
765 linkp = (struct lfile *)
766 new (sizeof (struct lfile));
769 lfp->f_flp = (struct lfile *)
770 new (sizeof (struct lfile));
774 lfp->f_idp = (char *) new (strlen(fid)+1);
775 strcpy(lfp->f_idp, fid);
782 /*)Function VOID bassav()
784 * The function bassav() creates a linked structure containing
785 * the base address strings input to the linker.
791 * base *basep The pointer to the first
793 * base *bsp Pointer to the current
795 * char *ip pointer into the REL file
799 * char getnb() lklex.c
800 * VOID * new() lksym.c
801 * int strlen() c_library
802 * char * strcpy() c_library
803 * VOID unget() lklex.c
806 * The basep structure is created.
813 basep = (struct base *)
814 new (sizeof (struct base));
817 bsp->b_base = (struct base *)
818 new (sizeof (struct base));
822 bsp->b_strp = (char *) new (strlen(ip)+1);
823 strcpy(bsp->b_strp, ip);
826 /*)Function VOID setbas()
828 * The function setbas() scans the base address lines in hte
829 * basep structure, evaluates the arguments, and sets beginning
830 * address of the specified areas.
833 * int v expression value
834 * char id[] base id string
837 * area *ap Pointer to the current
839 * area *areap The pointer to the first
840 * area structure of a linked list
841 * base *basep The pointer to the first
843 * base *bsp Pointer to the current
845 * char *ip pointer into the REL file
847 * int lkerr error flag
850 * Addr_T expr() lkeval.c
851 * int fprintf() c_library
852 * VOID getid() lklex.c
853 * char getnb() lklex.c
854 * int symeq() lksym.c
857 * The base address of an area is set.
870 if (getnb() == '=') {
872 for (ap = areap; ap != NULL; ap = ap->a_ap) {
873 if (symeq(id, ap->a_id))
878 "No definition of area %s\n", id);
882 ap->a_type = 1; /* JLH: value set */
885 fprintf(stderr, "No '=' in base expression");
892 /*)Function VOID gblsav()
894 * The function gblsav() creates a linked structure containing
895 * the global variable strings input to the linker.
901 * globl *globlp The pointer to the first
903 * globl *gsp Pointer to the current
905 * char *ip pointer into the REL file
907 * int lkerr error flag
910 * char getnb() lklex.c
911 * VOID * new() lksym.c
912 * int strlen() c_library
913 * char * strcpy() c_library
914 * VOID unget() lklex.c
917 * The globlp structure is created.
923 if (globlp == NULL) {
924 globlp = (struct globl *)
925 new (sizeof (struct globl));
928 gsp->g_globl = (struct globl *)
929 new (sizeof (struct globl));
933 gsp->g_strp = (char *) new (strlen(ip)+1);
934 strcpy(gsp->g_strp, ip);
937 /*)Function VOID setgbl()
939 * The function setgbl() scans the global variable lines in hte
940 * globlp structure, evaluates the arguments, and sets a variable
944 * int v expression value
945 * char id[] base id string
946 * sym * sp pointer to a symbol structure
949 * char *ip pointer into the REL file
951 * globl *globlp The pointer to the first
953 * globl *gsp Pointer to the current
955 * FILE * stderr c_library
956 * int lkerr error flag
959 * Addr_T expr() lkeval.c
960 * int fprintf() c_library
961 * VOID getid() lklex.c
962 * char getnb() lklex.c
963 * sym * lkpsym() lksym.c
966 * The value of a variable is set.
973 register struct sym *sp;
980 if (getnb() == '=') {
985 "No definition of symbol %s\n", id);
988 if (sp->s_flag & S_DEF) {
990 "Redefinition of symbol %s\n", id);
998 fprintf(stderr, "No '=' in global expression");
1005 /*)Function FILE * afile(fn,, ft, wf)
1007 * char * fn file specification string
1008 * char * ft file type string
1009 * int wf read(0)/write(1) flag
1011 * The function afile() opens a file for reading or writing.
1012 * (1) If the file type specification string ft
1013 * is not NULL then a file specification is
1014 * constructed with the file path\name in fn
1015 * and the extension in ft.
1016 * (2) If the file type specification string ft
1017 * is NULL then the file specification is
1018 * constructed from fn. If fn does not have
1019 * a file type then the default .rel file
1020 * type is appended to the file specification.
1022 * afile() returns a file handle for the opened file or aborts
1023 * the assembler on an open error.
1026 * int c character value
1027 * char fb[] constructed file specification string
1028 * FILE * fp filehandle for opened file
1029 * char * p1 pointer to filespec string fn
1030 * char * p2 pointer to filespec string fb
1031 * char * p3 pointer to filetype string ft
1034 * int lkerr error flag
1037 * FILE * fopen() c_library
1038 * int fprintf() c_library
1041 * File is opened for read or write.
1049 register char *p1, *p2, *p3;
1053 char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1058 while ((c = *p1++) != 0 && c != FSEPX) {
1059 if (p2 < &fb[FILSPC-4])
1070 while ((c = *p3++) != 0) {
1071 if (p2 < &fb[FILSPC-1])
1075 if ((fp = fopen(fb, omode)) == NULL) {
1076 if (strcmp(ft,"cdb")) {
1077 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1084 /*)Function VOID iramsav()
1086 * The function iramsav() stores the size of the chip's internal RAM.
1087 * This is used after linking to check that variable assignment to this
1088 * dataspace didn't overflow into adjoining segments. Variables in the
1089 * DSEG, OSEG, and ISEG are assigned to this dataspace.
1095 * char *ip pointer into the REL file
1097 * unsigned int size of chip's internal
1098 * iram_size RAM segment
1101 * char getnb() lklex.c
1102 * VOID unget() lklex.c
1103 * Addr_T expr() lkeval.c
1106 * The iram_size may be modified.
1114 //iram_size = atoi(ip);
1115 iram_size = expr(0); /* evaluate size expression */
1117 iram_size = 128; /* Default is 128 (0x80) bytes */
1120 /*)Function VOID iramcheck()
1122 * The function iramcheck() is used at the end of linking to check that
1123 * the internal RAM area wasn't overflowed by too many variable
1124 * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to
1125 * the chip's internal RAM.
1131 * unsigned int size of chip's internal
1132 * iram_size RAM segment
1133 * struct area linked list of memory
1144 register unsigned int last_addr;
1145 register struct area *ap;
1147 for (ap = areap; ap; ap=ap->a_ap) {
1148 if ((ap->a_size != 0) &&
1149 (!strcmp(ap->a_id, "DSEG") ||
1150 !strcmp(ap->a_id, "OSEG") ||
1151 !strcmp(ap->a_id, "ISEG")
1155 last_addr = ap->a_addr + ap->a_size - 1;
1156 if (last_addr >= iram_size)
1158 "\nWARNING! Segment %s extends past the end\n"
1159 " of internal RAM. Check map file.\n",
1167 " -c Command line input",
1168 " -f file[LNK] File input",
1169 " -p Prompt and echo of file[LNK] to stdout (default)",
1170 " -n No echo of file[LNK] to stdout",
1171 /* "Usage: [-Options] file [file ...]", */
1173 " -k Library path specification, one per -k",
1174 " -l Library file specification, one per -l",
1176 " -b area base address = expression",
1177 " -g global symbol = expression",
1179 " -m Map output generated as file[MAP]",
1180 " -x Hexadecimal (default), -d Decimal, -q Octal",
1182 " -i Intel Hex as file[IHX]",
1183 " -s Motorola S19 as file[S19]",
1184 " -j Produce NoICE debug as file[NOI]",
1185 " -z Produce SDCdb debug as file[cdb]",
1187 " -u Update listing file(s) with link data as file(s)[.RST]",
1189 " -a [iram-size] Check for internal RAM overflow",
1191 " -e or null line terminates input",
1195 /*)Function VOID usage()
1197 * The function usage() outputs to the stderr device the
1198 * assembler name and version and a list of valid assembler options.
1201 * char ** dp pointer to an array of
1202 * text string pointers.
1205 * FILE * stderr c_library
1208 * int fprintf() c_library
1219 fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1220 for (dp = usetxt; *dp; dp++)
1221 fprintf(stderr, "%s\n", *dp);
1225 /*)Function VOID copyfile()
1227 * FILE *dest destination file
1228 * FILE *src source file
1230 * function will copy source file to destination file
1234 * int fgetc() c_library
1235 * int fputc() c_library
1240 VOID copyfile (dest,src)
1244 while ((ch = fgetc(src)) != EOF) {