/* lkmain.c */ /* * Copyright (C) 1989-2009 Alan R. Baldwin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * * Alan R. Baldwin * 721 Berkeley St. * Kent, Ohio 44240 */ #include "aslink.h" /*)Module lkmain.c * * The module lkmain.c contains the functions which * (1) input the linker options, parameters, and specifications * (2) perform a two pass link * (3) produce the appropriate linked data output and/or * link map file and/or relocated listing files. * * lkmain.c contains the following functions: * FILE * afile() * VOID bassav() * VOID gblsav() * int intsiz() * VOID link_main() * VOID lkexit() * int fndext() * int fndidx() * int main() * VOID map() * int parse() * VOID doparse() * VOID setgbl() * VOID usage() * * lkmain.c contains the following local variables: * char * usetext[] array of pointers to the * command option tect lines * */ /* sdld 8051 specific */ /*JCF: Creates some of the default areas so they are allocated in the right order.*/ void Areas51 (void) { char * rel[] = { "XH", "H 7 areas 0 global symbols", "A _CODE size 0 flags 0", /*Each .rel has one, so...*/ "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/ "A REG_BANK_1 size 0 flags 4", "A REG_BANK_2 size 0 flags 4", "A REG_BANK_3 size 0 flags 4", "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/ "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/ "" }; char * rel2[] = { "XH", "H C areas 0 global symbols", "A _CODE size 0 flags 0", /*Each .rel has one, so...*/ "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/ "A REG_BANK_1 size 0 flags 4", "A REG_BANK_2 size 0 flags 4", "A REG_BANK_3 size 0 flags 4", "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/ "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/ "A BIT_BANK size 0 flags 4", /*Bit register bank is overlayable*/ "A DSEG size 0 flags 0", "A OSEG size 0 flags 4", "A ISEG size 0 flags 0", "A SSEG size 0 flags 4", "" }; int j; struct sym * sp; if (packflag) { for (j = 0; rel2[j][0] != 0; j++) { ip = rel2[j]; link_main(); } } else { for (j = 0; rel[j][0] != 0; j++) { ip = rel[j]; link_main(); } } /*Set the start address of the default areas:*/ for (ap = areap; ap; ap = ap->a_ap) { /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr = 0x00; ap->a_bset = 1; } else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr = 0x08; ap->a_bset = 1; } else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr = 0x10; ap->a_bset = 1; } else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr = 0x18; ap->a_bset = 1; } else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr = 0x20; ap->a_bset = 1; } else if (TARGET_IS_8051 && !strcmp(ap->a_id, "SSEG")) { if (stacksize) ap->a_axp->a_size = stacksize; } } sp = lkpsym("l_IRAM", 1); sp->s_addr = ((iram_size>0) && (iram_size<=0x100)) ? iram_size : 0x0100; sp->s_axp = NULL; sp->s_type |= S_DEF; } /* end sdld 8051 specific */ /*)Function int main(argc,argv) * * int argc number of command line arguments + 1 * char * argv[] array of pointers to the command line * arguments * * The function main() evaluates the command line arguments to * determine if the linker parameters are to input through 'stdin' * or read from a command file. The functions nxtline() and parse() * are to input and evaluate the linker parameters. The linking process * proceeds by making the first pass through each .rel file in the order * presented to the linker. At the end of the first pass the setarea(), * lnkarea(), setgbl(), and symdef() functions are called to evaluate * the base address terms, link all areas, define global variables, * and look for undefined symbols. Following these routines a linker * map file may be produced and the linker output files may be opened. * The second pass through the .rel files will output the linked data * in one of the supported formats. * * local variables: * int c character from argument string * int i loop counter * int j loop counter * int k loop counter * * global variables: * text line in ib[] * lfile *cfp The pointer *cfp points to the * current lfile structure * char ctype[] array of character types, one per * ASCII character * lfile *filep The pointer *filep points to the * beginning of a linked list of * lfile structures. * head *hp Pointer to the current * head structure * char ib[NINPUT] .rel file text line * char *ip pointer into the .rel file * lfile *linkp pointer to first lfile structure * containing an input .rel file * specification * int lkerr error flag * int oflag Output file type flag * int objflg Linked file/library output object flag * int pass linker pass number * int pflag print linker command file flag * int radix current number conversion radix * FILE *sfp The file handle sfp points to the * currently open file * lfile *startp aslink startup file structure * FILE * stdout c_library * * functions called: * VOID chkbank() lkbank.c * int fclose() c_library * int fprintf() c_library * VOID library() lklibr.c * VOID link_main() lkmain.c * VOID lkexit() lkmain.c * VOID lkfopen() lkbank.c * VOID lnkarea() lkarea.c * VOID map() lkmain.c * VOID new() lksym.c * int nxtline() lklex.c * int parse() lkmain.c * VOID reloc() lkreloc.c * VOID search() lklibr.c * VOID setarea() lkarea.c * VOID setbank() lkbank.c * VOID setgbl() lkmain.c * char * sprintf() c_library * VOID symdef() lksym.c * VOID usage() lkmain.c * int fndidx() lkmain.c * * side effects: * Completion of main() completes the linking process * and may produce a map file (.map) and/or a linked * data files (.ihx or .s19) and/or one or more * relocated listing files (.rst). */ int main(int argc, char *argv[]) { int c, i, j, k; if (intsiz() < 4) { fprintf(stderr, "?ASlink-Error-Size of INT32 is not 32 bits or larger.\n\n"); exit(ER_FATAL); } /* sdas specific */ /* sdas initialization */ sdld_init(argv[0]); /* use these defaults for parsing the .lnk script */ a_bytes = 4; a_mask = 0xFFFFFFFF; s_mask = 0x80000000; v_mask = 0x7FFFFFFF; /* end sdas specific */ if (!is_sdld()) fprintf(stdout, "\n"); startp = (struct lfile *) new (sizeof (struct lfile)); startp->f_idp = ""; pflag = 1; for(i=1; i> %s\n", ip); parse(); k++; } } else { strcpy(ip, argv[i]); if(pflag) fprintf(stdout, "ASlink >> %s\n", ip); parse(); } } if (linkp == NULL) usage(ER_FATAL); /* * If no input file is specified * then assume a single file with * the same name as the output file. */ if (lfp == linkp) { lfp->f_flp = (struct lfile *) new (sizeof (struct lfile)); lfp = lfp->f_flp; lfp->f_idp = strsto(linkp->f_idp); lfp->f_idx = fndidx(linkp->f_idp); lfp->f_obj = objflg; lfp->f_type = F_REL; } syminit(); #if SDCDB /* * Open SDCC Debug output file */ SDCDBfopen(); #endif for (pass=0; pass<2; ++pass) { cfp = NULL; sfp = NULL; filep = linkp->f_flp; hp = NULL; radix = 10; /* sdld specific */ if (TARGET_IS_8051) Areas51(); /*JCF: Create the default 8051 areas in the right order*/ /* end sdld specific */ while (nxtline()) { ip = ib; link_main(); } if (pass == 0) { /* * Search libraries for global symbols */ search(); /* sdas specific */ /* use these defaults for parsing the .lk script */ a_bytes = 4; a_mask = 0xFFFFFFFF; s_mask = 0x80000000; v_mask = 0x7FFFFFFF; /* end sdas specific */ /* * Set area base addresses. */ setarea(); /* * Set bank base addresses. */ setbank(); /* * Link all area addresses. */ if (!packflag) lnkarea(); else { /* sdld 8051 specific */ lnkarea2(); /* end sdld 8051 specific */ } /* * Check bank size limits. */ chkbank(stderr); /* * Process global definitions. */ setgbl(); /* * Check for undefined globals. */ symdef(stderr); #if NOICE /* * Open NoICE output file */ NoICEfopen(); #endif /* * Output Link Map. */ map(); /* sdld specific */ if (sflag) { /*JCF: memory usage summary output*/ if (!packflag) { if (summary(areap)) lkexit(1); } else { /* sdld 8051 specific */ if (summary2(areap)) lkexit(1); /* end sdld 8051 specific */ } } if ((iram_size) && (!packflag)) iramcheck(); /* end sdld specific */ /* * Open output file(s) */ lkfopen(); } else { /* * Link in library files */ library(); /* * Complete Processing */ reloc('E'); } } if (TARGET_IS_PDK && get_sdld_target() != TARGET_ID_PDK) { unsigned ram = 0; unsigned rom = 0; for (struct area *it = areap; it; it = it->a_ap) { if (!strcmp(it->a_id, "DATA") || !strcmp(it->a_id, "OSEG")) { if (it->a_addr + it->a_size > ram) { ram = it->a_addr + it->a_size; } } else if (!strcmp(it->a_id, "CODE") || !strcmp(it->a_id, "CONST")) { if (it->a_addr + it->a_size > rom) { rom = it->a_addr + it->a_size; } } } enum sdld_target_e target = get_sdld_target(); const unsigned max_ram = target == TARGET_ID_PDK13 ? 64 : target == TARGET_ID_PDK14 ? 128 : 256; const unsigned max_rom = target == TARGET_ID_PDK13 ? 2048 : target == TARGET_ID_PDK14 ? 4096 : 8192; if (ram > max_ram) { fprintf(stderr, "?ASlink-Warning-" "RAM value %u too large " "(%uB max)\n", ram, max_ram); } if (rom > max_rom) { fprintf(stderr, "?ASlink-Warning-" "ROM value %u too large " "(%uW max)\n", rom / 2, max_rom / 2); } } if (TARGET_IS_8051) { //JCF: CreateAOMF51(); } lkexit(lkerr ? ER_ERROR : ER_NONE); return(0); } /*)Function int intsiz() * * The function intsiz() returns the size of INT32 * * local variables: * none * * global variables: * none * * functions called: * none * * side effects: * none */ int intsiz() { return(sizeof(a_uint)); } /*)Function VOID lkexit(i) * * int i exit code * * The function lkexit() explicitly closes all open * files and then terminates the program. * * local variables: * none * * global variables: * FILE * jfp file handle for .noi * FILE * mfp file handle for .map * FILE * rfp file hanlde for .rst * FILE * sfp file handle for .rel * FILE * tfp file handle for .lst * * functions called: * int fclose() c_library * VOID exit() c_library * VOID lkfclose() lkbank.c * * side effects: * All files closed. Program terminates. */ VOID lkexit(i) int i; { lkfclose(); #if NOICE if (jfp != NULL) fclose(jfp); #endif if (mfp != NULL) fclose(mfp); if (rfp != NULL) fclose(rfp); if (sfp != NULL) { if (sfp != stdin) fclose(sfp); } if (tfp != NULL) fclose(tfp); #if SDCDB if (yfp != NULL) fclose(yfp); #endif exit(i); } /*)Function link_main() * * The function link_main() evaluates the directives for each line of * text read from the .rel file(s). The valid directives processed * are: * X, D, Q, H, M, A, S, T, R, and P. * * local variables: * int c first non blank character of a line * * global variables: * head *headp The pointer to the first * head structure of a linked list * head *hp Pointer to the current * head structure * int a_bytes T Line address bytes * int hilo Byte ordering * int pass linker pass number * int radix current number conversion radix * * functions called: * char endline() lklex.c * VOID module() lkhead.c * VOID newarea() lkarea.c * VOID newhead() lkhead.c * sym * newsym() lksym.c * VOID NoICEmagic() lknoice.c * VOID reloc() lkreloc.c * * side effects: * Head, area, and symbol structures are created and * the radix is set as the .rel file(s) are read. */ VOID link_main() { char c; if ((c=endline()) == 0) { return; } switch (c) { /* sdld specific */ case 'O': /* For some important sdcc options */ if (is_sdld() && pass == 0) { if (NULL == optsdcc) { optsdcc = strsto(&ip[1]); optsdcc_module = hp->m_id; } else { if (strcmp(optsdcc, &ip[1]) != 0) { fprintf(stderr, "?ASlink-Warning-Conflicting sdcc options:\n" " \"%s\" in module \"%s\" and\n" " \"%s\" in module \"%s\".\n", optsdcc, optsdcc_module, &ip[1], hp->m_id); lkerr++; } } } break; /* end sdld specific */ case 'X': case 'D': case 'Q': ASxxxx_VERSION = 3; a_bytes = 2; /* use default if unspecified */ hilo = 0; /* use default if unspecified */ if (c == 'X') { radix = 16; } else if (c == 'D') { radix = 10; } else if (c == 'Q') { radix = 8; } while ((c = get()) != 0) { switch(c) { case 'H': hilo = 1; break; case 'L': hilo = 0; break; case '2': a_bytes = 2; break; case '3': a_bytes = 3; break; case '4': a_bytes = 4; break; default: break; } } #ifdef LONGINT switch(a_bytes) { default: a_bytes = 2; case 2: a_mask = 0x0000FFFFl; s_mask = 0x00008000l; v_mask = 0x00007FFFl; break; case 3: a_mask = 0x00FFFFFFl; s_mask = 0x00800000l; v_mask = 0x007FFFFFl; break; case 4: a_mask = 0xFFFFFFFFl; s_mask = 0x80000000l; v_mask = 0x7FFFFFFFl; break; } #else switch(a_bytes) { default: a_bytes = 2; case 2: a_mask = 0x0000FFFF; s_mask = 0x00008000; v_mask = 0x00007FFF; break; case 3: a_mask = 0x00FFFFFF; s_mask = 0x00800000; v_mask = 0x007FFFFF; break; case 4: a_mask = 0xFFFFFFFF; s_mask = 0x80000000; v_mask = 0x7FFFFFFF; break; } #endif break; case 'H': if (pass == 0) { newhead(); } else { if (hp == 0) { hp = headp; } else { hp = hp->h_hp; } } sdp.s_area = NULL; sdp.s_areax = NULL; sdp.s_addr = 0; break; case 'M': if (pass == 0) module(); break; case 'A': if (pass == 0) newarea(); if (sdp.s_area == NULL) { sdp.s_area = areap; sdp.s_areax = areap->a_axp; sdp.s_addr = 0; } break; case 'S': if (pass == 0) newsym(); break; case 'T': case 'R': case 'P': if (pass == 0) break; reloc(c); break; #if NOICE case ';': unget(c); NoICEmagic(); break; #endif default: break; } } /*)Function VOID map() * * The function map() opens the output map file and calls the various * routines to * (1) output the variables in each area, * (2) list the files processed with module names, * (3) list the libraries file processed, * (4) list base address definitions, * (5) list global variable definitions, and * (6) list any undefined variables. * * local variables: * int i counter * head * hdp pointer to head structure * lbfile *lbfh pointer to library file structure * * global variables: * area *ap Pointer to the current * area structure * area *areap The pointer to the first * area structure of a linked list * base *basep The pointer to the first * base structure * base *bsp Pointer to the current * base structure * lfile *filep The pointer *filep points to the * beginning of a linked list of * lfile structures. * globl *globlp The pointer to the first * globl structure * globl *gsp Pointer to the current * globl structure * head *headp The pointer to the first * head structure of a linked list * lbfile *lbfhead The pointer to the first * lbfile structure of a linked list * lfile *linkp pointer to first lfile structure * containing an input REL file * specification * int lop current line number on page * int mflag Map output flag * FILE *mfp Map output file handle * int page current page number * * functions called: * FILE * afile() lkmain.c * int fprintf() c_library * VOID lkexit() lkmain.c * VOID lstarea() lklist.c * VOID newpag() lklist.c * VOID chkbank() lkbank.c * VOID symdef() lksym.c * * side effects: * The map file is created. */ VOID map(void) { int i; struct head *hdp; struct lbfile *lbfh; if (mflag == 0) return; /* * Open Map File */ mfp = afile(linkp->f_idp, "map", 1); if (mfp == NULL) { lkexit(ER_FATAL); } /* * Output Map Bank/Area Lists */ page = 0; lop = NLPP; for (bp = bankp; bp != NULL; bp = bp->b_bp) { for (ap = areap; ap != NULL; ap = ap->a_ap) { if (ap->a_bp == bp) lstarea(ap, bp); } } /* * List Linked Files */ newpag(mfp); fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n"); hdp = headp; filep = linkp->f_flp; while (filep) { if (strlen (filep->f_idp) > 40) fprintf(mfp, "%s\n%40s [ ", filep->f_idp, ""); else fprintf(mfp, "%-40.40s [ ", filep->f_idp); i = 0; while ((hdp != NULL) && (hdp->h_lfile == filep)) { if (i) fprintf(mfp, ",\n%44s", ""); fprintf(mfp, "%-.32s", hdp->m_id); hdp = hdp->h_hp; i++; } fprintf(mfp, " ]\n"); filep = filep->f_flp; } fprintf(mfp, "\n"); /* * List Linked Libraries */ if (lbfhead != NULL) { fprintf(mfp, "\nLibraries Linked [ object file ]\n\n"); for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) { if (strlen (lbfh->libspc) > 40) fprintf(mfp, "%s\n%40s [ %-.32s ]\n", lbfh->libspc, "", lbfh->relfil); else fprintf(mfp, "%-40.40s [ %-.32s ]\n", lbfh->libspc, lbfh->relfil); } fprintf(mfp, "\n"); } /* * List Base Address Definitions */ if (basep) { newpag(mfp); fprintf(mfp, "\nUser Base Address Definitions\n\n"); bsp = basep; while (bsp) { fprintf(mfp, "%s\n", bsp->b_strp); bsp = bsp->b_base; } } /* * List Global Definitions */ if (globlp) { newpag(mfp); fprintf(mfp, "\nUser Global Definitions\n\n"); gsp = globlp; while (gsp) { fprintf(mfp, "%s\n", gsp->g_strp); gsp = gsp->g_globl; } } fprintf(mfp, "\n\f"); chkbank(mfp); symdef(mfp); } /*)Function int parse() * * The function parse() evaluates all command line or file input * linker directives and updates the appropriate variables. * * local variables: * int c character value * int sv_type save type of processing * char fid[] file id string * * global variables: * char ctype[] array of character types, one per * ASCII character * lfile *lfp pointer to current lfile structure * being processed by parse() * lfile *linkp pointer to first lfile structure * containing an input REL file * specification * int mflag Map output flag * int oflag Output file type flag * int objflg Linked file/library output object flag * int pflag print linker command file flag * FILE * stderr c_library * int uflag Relocated listing flag * int xflag Map file radix type flag * int wflag Wide listing format * int zflag Disable symbol case sensitivity * * Functions called: * VOID addlib() lklibr.c * VOID addpath() lklibr.c * VOID bassav() lkmain.c * VOID doparse() lkmain.c * int fprintf() c_library * VOID gblsav() lkmain.c * VOID getfid() lklex.c * int get() lklex.c * int getnb() lklex.c * VOID lkexit() lkmain.c * char * strsto() lksym.c * int strlen() c_library * int fndidx() lkmain.c * * side effects: * Various linker flags are updated and the linked * structure lfile is created. */ int parse() { int c; int sv_type; char fid[NINPUT]; while ((c = getnb()) != 0) { /* sdld specific */ if ( c == ';') return(0); /* end sdld specific */ if ( c == '-') { while (ctype[c=get()] & LETTER) { switch(c) { case 'C': if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) { codesav(); return(0); } // else fall through case 'c': if (startp->f_type != 0) break; startp->f_type = F_STD; doparse(); return(0); case 'f': case 'F': if (startp->f_type == F_LNK) return(0); unget(getnb()); if (*ip == 0) usage(ER_FATAL); sv_type = startp->f_type; startp->f_idp = strsto(ip); startp->f_idx = fndidx(ip); startp->f_type = F_LNK; doparse(); if (sv_type == F_STD) { cfp = NULL; sfp = NULL; startp->f_type = F_STD; filep = startp; } return(0); case 'I': if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) { iramsav(); return(0); } // else fall through case 'i': oflag = 1; break; case 'S': if (TARGET_IS_8051) { unget(getnb()); if (ip && *ip) { stacksize = expr(0); if (stacksize > 256) stacksize = 256; else if (stacksize < 0) stacksize = 0; } return(0); } // else fall through case 's': oflag = 2; break; case 't': case 'T': oflag = 3; break; case 'o': case 'O': objflg = 0; break; case 'v': case 'V': objflg = 1; break; case 'M': /*JCF: memory usage summary output*/ if (is_sdld()) { sflag = 1; break; } // else fall through case 'm': mflag = 1; break; #if NOICE case 'j': case 'J': jflag = 1; break; #endif case 'r': case 'R': if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) rflag = 1; else goto err; break; case 'u': case 'U': uflag = 1; break; case 'X': if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) { xramsav(); return(0); } // else fall through case 'x': xflag = 0; break; case 'q': case 'Q': xflag = 1; break; case 'd': case 'D': xflag = 2; break; case 'E': if (TARGET_IS_6808 || TARGET_IS_STM8) { oflag = 4; break; } // else fall through case 'e': return(1); case 'n': case 'N': pflag = 0; break; case 'p': case 'P': pflag = 1; break; case 'b': case 'B': bassav(); return(0); case 'g': case 'G': gblsav(); return(0); case 'k': case 'K': addpath(); return(0); case 'l': case 'L': addlib(); return(0); case 'w': case 'W': wflag = 1; break; #if SDCDB case 'Y': if (TARGET_IS_8051) { unget(getnb()); packflag=1; break; } // else fall through case 'y': yflag = 1; break; #endif case 'z': case 'Z': zflag = 1; break; default: err: fprintf(stderr, "Unknown option -%c ignored\n", c); break; } } /* sdld specific */ if ( c == ';') return(0); /* end sdld specific */ } else if (!(ctype[c] & ILL)) { if (linkp == NULL) { linkp = (struct lfile *) new (sizeof (struct lfile)); lfp = linkp; lfp->f_type = F_OUT; } else { lfp->f_flp = (struct lfile *) new (sizeof (struct lfile)); lfp = lfp->f_flp; lfp->f_type = F_REL; } getfid(fid, c); lfp->f_idp = strsto(fid); lfp->f_obj = objflg; } else { fprintf(stderr, "Invalid input\n"); lkexit(ER_FATAL); } } return(0); } /*)Function VOID doparse() * * The function doparse() evaluates all interactive * command line or file input linker directives and * updates the appropriate variables. * * local variables: * none * * global variables: * FILE * stdin standard input * FILE * stdout standard output * lfile *cfp The pointer *cfp points to the * current lfile structure * FILE *sfp The file handle sfp points to the * currently open file * char ib[NINPUT] .rel file text line * char *ip pointer into the .rel file * lfile *filep The pointer *filep points to the * beginning of a linked list of * lfile structures. * lfile *startp asmlnk startup file structure * int pflag print linker command file flag * * Functions called: * int fclose() c_library * int fprintf() c_library * VOID getfid() lklex.c * int nxtline() lklex.c * int parse() lkmain.c * * side effects: * Various linker flags are updated and the linked * structure lfile may be updated. */ VOID doparse() { cfp = NULL; sfp = NULL; filep = startp; while (1) { ip = ib; if (nxtline() == 0) break; if (pflag && cfp->f_type != F_STD) fprintf(stdout, "ASlink >> %s\n", ip); if (*ip == 0 || parse()) break; } if((sfp != NULL) && (sfp != stdin)) { fclose(sfp); } sfp = NULL; startp->f_idp = ""; startp->f_idx = 0; startp->f_type = 0; } /*)Function VOID bassav() * * The function bassav() creates a linked structure containing * the base address strings input to the linker. * * local variables: * none * * global variables: * base *basep The pointer to the first * base structure * base *bsp Pointer to the current * base structure * char *ip pointer into the REL file * text line in ib[] * * functions called: * int getnb() lklex.c * VOID * new() lksym.c * int strlen() c_library * char * strcpy() c_library * VOID unget() lklex.c * * side effects: * The basep structure is created. */ VOID bassav() { if (basep == NULL) { basep = (struct base *) new (sizeof (struct base)); bsp = basep; } else { bsp->b_base = (struct base *) new (sizeof (struct base)); bsp = bsp->b_base; } unget(getnb()); bsp->b_strp = (char *) new (strlen(ip)+1); strcpy(bsp->b_strp, ip); } /*)Function VOID gblsav() * * The function gblsav() creates a linked structure containing * the global variable strings input to the linker. * * local variable: * none * * global variables: * globl *globlp The pointer to the first * globl structure * globl *gsp Pointer to the current * globl structure * char *ip pointer into the REL file * text line in ib[] * int lkerr error flag * * functions called: * int getnb() lklex.c * VOID * new() lksym.c * int strlen() c_library * char * strcpy() c_library * VOID unget() lklex.c * * side effects: * The globlp structure is created. */ VOID gblsav() { if (globlp == NULL) { globlp = (struct globl *) new (sizeof (struct globl)); gsp = globlp; } else { gsp->g_globl = (struct globl *) new (sizeof (struct globl)); gsp = gsp->g_globl; } unget(getnb()); gsp->g_strp = (char *) new (strlen(ip)+1); strcpy(gsp->g_strp, ip); } /*)Function VOID setgbl() * * The function setgbl() scans the global variable lines in the * globlp structure, evaluates the arguments, and sets a variable * to this value. * * local variables: * int v expression value * char id[] base id string * sym * sp pointer to a symbol structure * * global variables: * char *ip pointer into the REL file * text line in ib[] * globl *globlp The pointer to the first * globl structure * globl *gsp Pointer to the current * globl structure * FILE * stderr c_library * int lkerr error flag * * functions called: * a_uint expr() lkeval.c * int fprintf() c_library * VOID getid() lklex.c * int getnb() lklex.c * sym * lkpsym() lksym.c * * side effects: * The value of a variable is set. */ VOID setgbl() { int v; struct sym *sp; char id[NCPS]; gsp = globlp; while (gsp) { ip = gsp->g_strp; getid(id, -1); if (getnb() == '=') { v = (int) expr(0); sp = lkpsym(id, 0); if (sp == NULL) { fprintf(stderr, "No definition of symbol %s\n", id); lkerr++; } else { if (sp->s_type & S_DEF) { fprintf(stderr, "Redefinition of symbol %s\n", id); lkerr++; sp->s_axp = NULL; } sp->s_addr = v; sp->s_type |= S_DEF; } } else { fprintf(stderr, "No '=' in global expression"); lkerr++; } gsp = gsp->g_globl; } } /*)Function FILE * afile(fn, ft, wf) * * char * fn file specification string * char * ft file type string * int wf 0 ==>> read * 1 ==>> write * 2 ==>> binary write * * The function afile() opens a file for reading or writing. * (1) If the file type specification string ft * is not NULL then a file specification is * constructed with the file path\name in fn * and the extension in ft. * (2) If the file type specification string ft * is NULL then the file specification is * constructed from fn. If fn does not have * a file type then the default .rel file * type is appended to the file specification. * * afile() returns a file handle for the opened file or aborts * the assembler on an open error. * * local variables: * int c character value * FILE * fp filehandle for opened file * char * p1 pointer to filespec string fn * char * p2 pointer to filespec string fb * char * p3 pointer to filetype string ft * * global variables: * char afspec[] constructed file specification string * int lkerr error flag * * functions called: * int fndidx() lkmain.c * FILE * fopen() c_library * int fprintf() c_library * * side effects: * File is opened for read or write. */ FILE * afile(char *fn, char *ft, int wf) { char *p1, *p2; int c; char * frmt; FILE *fp; if (strlen(fn) > (FILSPC-7)) { fprintf(stderr, "?ASlink-Error- : \"%s\"\n", fn); lkerr++; return(NULL); } /* * Skip The Path */ strcpy(afspec, fn); c = fndidx(afspec); /* * Skip to File Extension separator */ p1 = strrchr(&afspec[c], FSEPX); /* * Copy File Extension */ p2 = ft ? ft : ""; if (*p2 == 0) { if (p1 == NULL) { p2 = LKOBJEXT; } else { p2 = strrchr(&fn[c], FSEPX) + 1; } } if (p1 == NULL) { p1 = &afspec[strlen(afspec)]; } *p1++ = FSEPX; while ((c = *p2++) != 0) { if (p1 < &afspec[FILSPC-1]) *p1++ = c; } *p1++ = 0; /* * Select Read/Write/Binary Write */ switch(wf) { default: case 0: frmt = "r"; break; case 1: frmt = "w"; break; #ifdef DECUS case 2: frmt = "wn"; break; #else case 2: frmt = "wb"; break; #endif } if ((fp = fopen(afspec, frmt)) == NULL && strcmp(ft,"adb") != 0) { /* Do not complain for optional adb files */ fprintf(stderr, "?ASlink-Error- : \"%s\"\n", wf?"create":"open", afspec); lkerr++; } return (fp); } /*)Function int fndidx(str) * * char * str file specification string * * The function fndidx() scans the file specification string * to find the index to the file name. If the file * specification contains a 'path' then the index will * be non zero. * * fndidx() returns the index value. * * local variables: * char * p1 temporary pointer * char * p2 temporary pointer * * global variables: * none * * functions called: * char * strrchr() c_library * * side effects: * none */ int fndidx(str) char *str; { char *p1, *p2; /* * Skip Path Delimiters */ p1 = str; if ((p2 = strrchr(p1, ':')) != NULL) { p1 = p2 + 1; } if ((p2 = strrchr(p1, '/')) != NULL) { p1 = p2 + 1; } if ((p2 = strrchr(p1, '\\')) != NULL) { p1 = p2 + 1; } return((int) (p1 - str)); } /*)Function int fndext(str) * * char * str file specification string * * The function fndext() scans the file specification string * to find the file.ext separater. * * fndext() returns the index to FSEPX or the end of the string. * * local variables: * char * p1 temporary pointer * char * p2 temporary pointer * * global variables: * none * * functions called: * char * strrchr() c_library * * side effects: * none */ int fndext(str) char * str; { char *p1, *p2; /* * Find the file separator */ p1 = str + strlen(str); if ((p2 = strrchr(str, FSEPX)) != NULL) { p1 = p2; } return((int) (p1 - str)); } /* sdld specific */ /*)Function VOID iramsav() * * The function iramsav() stores the size of the chip's internal RAM. * This is used after linking to check that variable assignment to this * dataspace didn't overflow into adjoining segments. Variables in the * DSEG, OSEG, and ISEG are assigned to this dataspace. * * local variables: * none * * global variables: * char *ip pointer into the REL file * text line in ib[] * unsigned int size of chip's internal * iram_size RAM segment * * functions called: * int getnb() lklex.c * VOID unget() lklex.c * a_uint expr() lkeval.c * * side effects: * The iram_size may be modified. */ VOID iramsav() { unget(getnb()); if (ip && *ip) iram_size = expr(0); /* evaluate size expression */ else iram_size = 128; /* Default is 128 (0x80) bytes */ if ((iram_size<=0) || (iram_size>256)) iram_size = 128; /* Default is 128 (0x80) bytes */ } /*Similar to iramsav but for xram memory*/ VOID xramsav() { unget(getnb()); if (ip && *ip) xram_size = expr(0); /* evaluate size expression */ else xram_size = rflag?0x1000000:0x10000; } /*Similar to iramsav but for code memory*/ VOID codesav() { unget(getnb()); if (ip && *ip) code_size = expr(0); /* evaluate size expression */ else code_size = rflag?0x1000000:0x10000; } /*)Function VOID iramcheck() * * The function iramcheck() is used at the end of linking to check that * the internal RAM area wasn't overflowed by too many variable * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to * the chip's internal RAM. * * local variables: * none * * global variables: * unsigned int size of chip's internal * iram_size RAM segment * struct area linked list of memory * *areap areas * * functions called: * * side effects: */ VOID iramcheck() { register unsigned int last_addr; register struct area *ap; for (ap = areap; ap; ap=ap->a_ap) { if ((ap->a_size != 0) && (!strcmp(ap->a_id, "DSEG") || !strcmp(ap->a_id, "OSEG") || !strcmp(ap->a_id, "ISEG") ) ) { last_addr = ap->a_addr + ap->a_size - 1; if (last_addr >= iram_size) fprintf(stderr, "\nWARNING! Segment %s extends past the end\n" " of internal RAM. Check map file.\n", ap->a_id); } } } /* end sdld specific */ char *usetxt[] = { "Usage: [-Options] [-Option with arg] file", "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]", "Startup:", " -p Echo commands to stdout (default)", " -n No echo of commands to stdout", "Alternates to Command Line Input:", " -c ASlink >> prompt input", " -f file[.lk] Command File input", "Libraries:", " -k Library path specification, one per -k", " -l Library file specification, one per -l", "Relocation:", " -b area base address = expression", " -g global symbol = expression", "Map format:", " -m Map output generated as (out)file[.map]", " -w Wide listing format for map file", " -x Hexadecimal (default)", " -d Decimal", " -q Octal", "Output:", " -i Intel Hex as (out)file[.ihx]", " -s Motorola S Record as (out)file[.s19]", // " -t Tandy CoCo Disk BASIC binary as (out)file[.bi-]", #if NOICE " -j NoICE Debug output as (out)file[.noi]", #endif #if SDCDB " -y SDCDB Debug output as (out)file[.cdb]", #endif // " -o Linked file/library object output enable (default)", // " -v Linked file/library object output disable", "List:", " -u Update listing file(s) with link data as file(s)[.rst]", "Case Sensitivity:", " -z Disable Case Sensitivity for Symbols", "End:", " -e or null line terminates input", "", 0 }; char *usetxt_8051[] = { "Usage: [-Options] [-Option with arg] file", "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]", "Startup:", " -p Echo commands to stdout (default)", " -n No echo of commands to stdout", "Alternates to Command Line Input:", " -c ASlink >> prompt input", " -f file[.lk] Command File input", "Libraries:", " -k Library path specification, one per -k", " -l Library file specification, one per -l", "Relocation:", " -b area base address = expression", " -g global symbol = expression", "Map format:", " -m Map output generated as (out)file[.map]", " -w Wide listing format for map file", " -x Hexadecimal (default)", " -d Decimal", " -q Octal", "Output:", " -i Intel Hex as (out)file[.ihx]", " -s Motorola S Record as (out)file[.s19]", #if NOICE " -j NoICE Debug output as (out)file[.noi]", #endif #if SDCDB " -y SDCDB Debug output as (out)file[.cdb]", #endif "List:", " -u Update listing file(s) with link data as file(s)[.rst]", "Case Sensitivity:", " -z Disable Case Sensitivity for Symbols", "Miscellaneous:\n" " -I [iram-size] Check for internal RAM overflow", " -X [xram-size] Check for external RAM overflow", " -C [code-size] Check for code overflow", " -M Generate memory usage summary file[.mem]", " -Y Pack internal ram", " -S [stack-size] Allocate space for stack", "End:", " -e or null line terminates input", "", 0 }; char *usetxt_6808[] = { "Usage: [-Options] [-Option with arg] file", "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]", "Startup:", " -p Echo commands to stdout (default)", " -n No echo of commands to stdout", "Alternates to Command Line Input:", " -c ASlink >> prompt input", " -f file[.lk] Command File input", "Libraries:", " -k Library path specification, one per -k", " -l Library file specification, one per -l", "Relocation:", " -b area base address = expression", " -g global symbol = expression", "Map format:", " -m Map output generated as (out)file[.map]", " -w Wide listing format for map file", " -x Hexadecimal (default)", " -d Decimal", " -q Octal", "Output:", " -i Intel Hex as (out)file[.ihx]", " -s Motorola S Record as (out)file[.s19]", " -E ELF executable as file[.elf]", #if NOICE " -j NoICE Debug output as (out)file[.noi]", #endif #if SDCDB " -y SDCDB Debug output as (out)file[.cdb]", #endif "List:", " -u Update listing file(s) with link data as file(s)[.rst]", "Case Sensitivity:", " -z Disable Case Sensitivity for Symbols", "Miscellaneous:\n" " -I [iram-size] Check for internal RAM overflow", " -X [xram-size] Check for external RAM overflow", " -C [code-size] Check for code overflow", " -M Generate memory usage summary file[.mem]", "End:", " -e or null line terminates input", "", 0 }; char *usetxt_z80_gb[] = { "Usage: [-Options] [-Option with arg] file", "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]", "Startup:", " -p Echo commands to stdout (default)", " -n No echo of commands to stdout", "Alternates to Command Line Input:", " -c ASlink >> prompt input", " -f file[.lk] Command File input", "Libraries:", " -k Library path specification, one per -k", " -l Library file specification, one per -l", "Relocation:", " -b area base address = expression", " -g global symbol = expression", "Map format:", " -m Map output generated as (out)file[.map]", " -w Wide listing format for map file", " -x Hexadecimal (default)", " -d Decimal", " -q Octal", "Output:", " -i Intel Hex as (out)file[.ihx]", " -s Motorola S Record as (out)file[.s19]", #if SDCDB " -y SDCDB Debug output as (out)file[.cdb]", #endif "List:", " -u Update listing file(s) with link data as file(s)[.rst]", "Case Sensitivity:", " -z Disable Case Sensitivity for Symbols", "End:", " -e or null line terminates input", "", 0 }; /*)Function VOID usage(n) * * int n exit code * * The function usage() outputs to the stderr device the * linker name and version and a list of valid linker options. * * local variables: * char ** dp pointer to an array of * text string pointers. * * global variables: * FILE * stderr c_library * * functions called: * int fprintf() c_library * * side effects: * none */ VOID usage(int n) { char **dp; /* sdld specific */ fprintf(stderr, "\n%s Linker %s\n\n", is_sdld() ? "sdld" : "ASxxxx", VERSION); for (dp = TARGET_IS_8051 ? usetxt_8051 : (TARGET_IS_6808 ? usetxt_6808 : ((TARGET_IS_Z80 || TARGET_IS_GB) ? usetxt_z80_gb : usetxt)); *dp; dp++) fprintf(stderr, "%s\n", *dp); /* end sdld specific */ lkexit(n); } /*)Function VOID copyfile() * * FILE *dest destination file * FILE *src source file * * function will copy source file to destination file * * * functions called: * int fgetc() c_library * int fputc() c_library * * side effects: * none */ VOID copyfile (FILE *dest, FILE *src) { int ch; while ((ch = fgetc(src)) != EOF) { fputc(ch,dest); } }