/* lklist.c */ /* * (C) Copyright 1989-1995 * All Rights Reserved * * Alan R. Baldwin * 721 Berkeley St. * Kent, Ohio 44240 * * 28-Oct-97 JLH: * - lstarea: show s_id as string rather than array [NCPS] * - lstarea: show a_id as string rather than array [NCPS] * 31-Oct-97 JLH: add NoICE output file genration in lstarea * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output */ #include #include #include #include "aslink.h" /*)Module lklist.c * * The module lklist.c contains the functions which * output the linker .map file and produce a relocated * listing .rst file. * * lklist.c contains the following functions: * int dgt() * VOID lstarea() * VOID lkulist() * VOID lkalist() * VOID lkglist() * VOID newpag() * VOID slew() * * lklist.c contains no local variables. */ /*)Function VOID slew(fp) * * FILE * fp output file handle * * The function slew() increments the page line counter. * If the number of lines exceeds the maximum number of * lines per page then a page skip and a page header are * output. * * local variables: * int i loop counter * * global variables: * int lop current line number on page * int xflag Map file radix type flag * * functions called: * int fprintf() c_library * VOID newpag() lklist.c * * side effects: * The page line and the page count may be updated. */ VOID slew(fp) FILE *fp; { register int i; if (lop++ >= NLPP) { newpag(fp); if (xflag == 0) { fprintf(fp, "Hexadecimal\n\n"); } else if (xflag == 1) { fprintf(fp, "Octal\n\n"); } else if (xflag == 2) { fprintf(fp, "Decimal\n\n"); } fprintf(fp, "Area Addr Size"); fprintf(fp, " Decimal Bytes (Attributes)\n"); for(i=0;i<4;++i) fprintf(fp, " Value--Global"); fprintf(fp, "\n\n"); lop += 6; } } /*)Function VOID newpag() * * The function newpag() outputs a page skip, writes the * first page header line, sets the line count to 1, and * increments the page counter. * * local variables: * none * * global variables: * int lop current line number on page * int page current page number * * functions called: * int fprintf() c_library * * side effects: * The page and line counters are updated. */ VOID newpag(fp) FILE *fp; { fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page); lop = 1; } /* Used for qsort call in lstsym */ static int _cmpSymByAddr(const void *p1, const void *p2) { struct sym **s1 = (struct sym **)(p1); struct sym **s2 = (struct sym **)(p2); int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) - ((*s2)->s_addr + (*s2)->s_axp->a_addr); /* Sort first by address, then by name. */ if (delta) { return delta; } return strcmp((*s1)->s_id,(*s2)->s_id); } #if NCPS-8 /* NCPS != 8 */ /*)Function VOID lstarea(xp) * * area * xp pointer to an area structure * * The function lstarea() creates the linker map output for * the area specified by pointer xp. The generated output * area header includes the area name, starting address, * size of area, number of words (in decimal), and the * area attributes. The symbols defined in this area are * sorted by ascending address and output one per line * in the selected radix. * * local variables: * areax * oxp pointer to an area extension structure * int c character value * int i loop counter * int j bubble sort update status * char * ptr pointer to an id string * int nmsym number of symbols in area * Addr_T a0 temporary * Addr_T ai temporary * Addr_T aj temporary * sym * sp pointer to a symbol structure * sym ** p pointer to an array of * pointers to symbol structures * * global variables: * FILE *mfp Map output file handle * sym *symhash[NHASH] array of pointers to NHASH * linked symbol lists * int xflag Map file radix type flag * * functions called: * int fprintf() c_library * VOID free() c_library * char * malloc() c_library * char putc() c_library * VOID slew() lklist.c * * side effects: * Map output generated. */ VOID lstarea(xp) struct area *xp; { register struct areax *oxp; register int i; /* int j; */ register char *ptr; int nmsym; /* Addr_T a0; */ Addr_T ai, aj; struct sym *sp; struct sym **p; int memPage; putc('\n', mfp); if (xflag == 0) { fprintf(mfp, "Hexadecimal\n\n"); } else if (xflag == 1) { fprintf(mfp, "Octal\n\n"); } else if (xflag == 2) { fprintf(mfp, "Decimal\n\n"); } fprintf(mfp, "Area "); fprintf(mfp, "Addr Size Decimal Bytes (Attributes)\n"); fprintf(mfp, "-------------------------------- "); fprintf(mfp, "---- ---- ------- ----- ------------\n"); /* * Output Area Header */ ptr = &xp->a_id[0]; fprintf(mfp, "%-32s", ptr ); /* JLH: width matches --- above */ ai = xp->a_addr; aj = xp->a_size; if (xflag == 0) { fprintf(mfp, " %04X %04X", ai, aj); } else if (xflag == 1) { fprintf(mfp, " %06o %06o", ai, aj); } else if (xflag == 2) { fprintf(mfp, " %05u %05u", ai, aj); } fprintf(mfp, " = %6u. bytes ", aj); if (xp->a_flag & A_ABS) { fprintf(mfp, "(ABS"); } else { fprintf(mfp, "(REL"); } if (xp->a_flag & A_OVR) { fprintf(mfp, ",OVR"); } else { fprintf(mfp, ",CON"); } if (xp->a_flag & A_PAG) { fprintf(mfp, ",PAG"); } memPage = 0x00; if (xp->a_flag & A_CODE) { fprintf(mfp, ",CODE"); memPage = 0x0C; } if (xp->a_flag & A_XDATA) { fprintf(mfp, ",XDATA"); memPage = 0x0D; } if (xp->a_flag & A_BIT) { fprintf(mfp, ",BIT"); memPage = 0x0B; } fprintf(mfp, ")"); if (xp->a_flag & A_PAG) { ai = (ai & 0xFF); aj = (aj > 256); if (ai || aj) { fprintf(mfp, " "); } if (ai) { fprintf(mfp, " Boundary"); } if (ai & aj) { fprintf(mfp, " /"); } if (aj) { fprintf(mfp, " Length"); } if (ai || aj) { fprintf(mfp, " Error"); } } /* * Find number of symbols in area */ nmsym = 0; oxp = xp->a_axp; while (oxp) { for (i=0; is_axp) ++nmsym; sp = sp->s_sp; } } oxp = oxp->a_axp; } if (nmsym == 0) { putc('\n', mfp); return; } /* * Allocate space for an array of pointers to symbols * and load array. */ if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) == NULL) { fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); return; } nmsym = 0; oxp = xp->a_axp; while (oxp) { for (i=0; is_axp) { p[nmsym++] = sp; } sp = sp->s_sp; } } oxp = oxp->a_axp; } #if 0 /* * Bubble Sort of Addresses in Symbol Table Array */ j = 1; while (j) { j = 0; sp = p[0]; a0 = sp->s_addr + sp->s_axp->a_addr; for (i=1; is_addr + sp->s_axp->a_addr; if (a0 > ai) { j = 1; p[i] = p[i-1]; p[i-1] = sp; } a0 = ai; } } #else qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr); #endif /* * Symbol Table Output */ i = 0; fprintf(mfp, "\n\n"); fprintf(mfp, " Value Global\n"); fprintf(mfp, " -------- --------------------------------"); while (i < nmsym) { fprintf(mfp, "\n"); if (memPage != 0) fprintf(mfp, " %02X:", memPage); else fprintf(mfp, " "); sp = p[i]; aj = sp->s_addr + sp->s_axp->a_addr; if (xflag == 0) { fprintf(mfp, "%04X ", aj); } else if (xflag == 1) { fprintf(mfp, "%06o ", aj); } else if (xflag == 2) { fprintf(mfp, "%05u ", aj); } ptr = &sp->s_id[0]; fprintf(mfp, "%s", ptr ); /* if cdb flag set the output cdb Information and the symbol has a '$' sign in it then */ if (dflag && strchr(ptr,'$')) fprintf(dfp,"L:%s:%X\n",ptr,aj); /* NoICE output of symbol */ if (jflag) DefineNoICE( ptr, aj, memPage ); i++; } putc('\n', mfp); free(p); } #else /* NCPS == 8 */ /*)Function VOID lstarea(xp) * * area * xp pointer to an area structure * * The function lstarea() creates the linker map output for * the area specified by pointer xp. The generated output * area header includes the area name, starting address, * size of area, number of words (in decimal), and the * area attributes. The symbols defined in this area are * sorted by ascending address and output four per line * in the selected radix. * * local variables: * areax * oxp pointer to an area extension structure * int c character value * int i loop counter * int j bubble sort update status * char * ptr pointer to an id string * int nmsym number of symbols in area * Addr_T a0 temporary * Addr_T ai temporary * Addr_T aj temporary * sym * sp pointer to a symbol structure * sym ** p pointer to an array of * pointers to symbol structures * * global variables: * FILE *mfp Map output file handle * sym *symhash[NHASH] array of pointers to NHASH * linked symbol lists * int xflag Map file radix type flag * * functions called: * int fprintf() c_library * VOID free() c_library * char * malloc() c_library * char putc() c_library * VOID slew() lklist.c * * side effects: * Map output generated. */ VOID lstarea(xp) struct area *xp; { register struct areax *oxp; register c, i, j; register char *ptr; int nmsym; Addr_T a0, ai, aj; struct sym *sp; struct sym **p; int page; putc('\n', mfp); slew(mfp); /* * Output Area Header */ ptr = &xp->a_id[0]; while (ptr < &xp->a_id[NCPS]) { if ((c = *ptr++) != 0) { putc(c, mfp); } else { putc(' ', mfp); } } ai = xp->a_addr; aj = xp->a_size; if (xflag == 0) { fprintf(mfp, " %04X %04X", ai, aj); } else if (xflag == 1) { fprintf(mfp, " %06o %06o", ai, aj); } else if (xflag == 2) { fprintf(mfp, " %05u %05u", ai, aj); } fprintf(mfp, " = %6u. bytes ", aj); if (xp->a_flag & A_ABS) { fprintf(mfp, "(ABS"); } else { fprintf(mfp, "(REL"); } if (xp->a_flag & A_OVR) { fprintf(mfp, ",OVR"); } else { fprintf(mfp, ",CON"); } if (xp->a_flag & A_PAG) { fprintf(mfp, ",PAG"); } page = 0x00; if (xp->a_flag & A_CODE) { fprintf(mfp, ",CODE"); memPage = 0x0C; } if (xp->a_flag & A_XDATA) { fprintf(mfp, ",XDATA"); memPage = 0x0D; } if (xp->a_flag & A_BIT) { fprintf(mfp, ",BIT"); memPage = 0x0B; } fprintf(mfp, ")"); if (xp->a_flag & A_PAG) { ai = (ai & 0xFF); aj = (aj > 256); if (ai || aj) { fprintf(mfp, " "); } if (ai) { fprintf(mfp, " Boundary"); } if (ai & aj) { fprintf(mfp, " /"); } if (aj) { fprintf(mfp, " Length"); } if (ai || aj) { fprintf(mfp, " Error"); } } /* * Find number of symbols in area */ nmsym = 0; oxp = xp->a_axp; while (oxp) { for (i=0; is_axp) ++nmsym; sp = sp->s_sp; } } oxp = oxp->a_axp; } if (nmsym == 0) { putc('\n', mfp); slew(mfp); return; } /* * Allocate space for an array of pointers to symbols * and load array. */ if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) == NULL) { fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); slew(mfp); return; } nmsym = 0; oxp = xp->a_axp; while (oxp) { for (i=0; is_axp) { p[nmsym++] = sp; } sp = sp->s_sp; } } oxp = oxp->a_axp; } #if 0 /* * Bubble Sort of Addresses in Symbol Table Array */ j = 1; while (j) { j = 0; sp = p[0]; a0 = sp->s_addr + sp->s_axp->a_addr; for (i=1; is_addr + sp->s_axp->a_addr; if (a0 > ai) { j = 1; p[i] = p[i-1]; p[i-1] = sp; } a0 = ai; } } #else qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr); #endif /* * Symbol Table Output */ i = 0; while (i < nmsym) { fprintf(mfp, "\n"); slew(mfp); fprintf(mfp, " "); sp = p[i]; aj = sp->s_addr + sp->s_axp->a_addr; if (xflag == 0) { fprintf(mfp, " %04X ", aj); } else if (xflag == 1) { fprintf(mfp, "%06o ", aj); } else if (xflag == 2) { fprintf(mfp, " %05u ", aj); } ptr = &sp->s_id[0]; fprintf(mfp, "%s", ptr ); /* NoICE output of symbol */ if (jflag) DefineNoICE( ptr, aj, memPage ); } putc('\n', mfp); free(p); slew(mfp); } #endif /*)Function VOID lkulist(i) * * int i i # 0 process LST to RST file * i = 0 copy remainder of LST file * to RST file and close files * * The function lkulist() creates a relocated listing (.rst) * output file from the ASxxxx assembler listing (.lst) * files. The .lst file's program address and code bytes * are changed to reflect the changes made by ASlink as * the .rel files are combined into a single relocated * output file. * * local variables: * Addr_T pc current program counter address * * global variables: * int hilo byte order * int gline get a line from the LST file * to translate for the RST file * char rb[] read listing file text line * FILE *rfp The file handle to the current * output RST file * int rtcnt count of data words * int rtflg[] output the data flag * Addr_T rtval[] relocated data * FILE *tfp The file handle to the current * LST file being scanned * * functions called: * int fclose() c_library * int fgets() c_library * int fprintf() c_library * VOID lkalist() lklist.c * VOID lkglist() lklist.c * * side effects: * A .rst file is created for each available .lst * file associated with a .rel file. */ VOID lkulist(i) int i; { Addr_T pc; /* * Exit if listing file is not open */ if (tfp == NULL) return; /* * Normal processing of LST to RST */ if (i) { /* * Evaluate current code address */ if (hilo == 0) { pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF); } else { pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF); } /* * Line with only address */ if (rtcnt == 2) { lkalist(pc); /* * Line with address and code */ } else { for (i=2; i < rtcnt; i++) { if (rtflg[i]) { lkglist(pc++, rtval[i] & 0xFF); } } } /* * Copy remainder of LST to RST */ } else { if (gline == 0) fprintf(rfp, "%s", rb); while (fgets(rb, sizeof(rb), tfp) != 0) { fprintf(rfp, "%s", rb); } fclose(tfp); tfp = NULL; fclose(rfp); rfp = NULL; } } /*)Function VOID lkalist(pc) * * int pc current program counter value * * The function lkalist() performs the following functions: * * (1) if the value of gline = 0 then the current listing * file line is copied to the relocated listing file output. * * (2) the listing file is read line by line and copied to * the relocated listing file until a valid source * line number and a program counter value of the correct * radix is found. The new relocated pc value is substituted * and the line is written to the RST file. * * local variables: * int i loop counter * char str[] temporary string * * global variables: * int gcntr data byte counter * int gline get a line from the LST file * to translate for the RST file * char rb[] read listing file text line * char *rp pointer to listing file text line * FILE *rfp The file handle to the current * output RST file * FILE *tfp The file handle to the current * LST file being scanned * * functions called: * int dgt() lklist.c * int fclose() c_library * int fgets() c_library * int fprintf() c_library * int sprintf() c_library * char * strncpy() c_library * * side effects: * Lines of the LST file are copied to the RST file, * the last line copied has the code address * updated to reflect the program relocation. */ VOID lkalist(pc) Addr_T pc; { char str[8]; int i; /* * Exit if listing file is not open */ loop: if (tfp == NULL) return; /* * Copy current LST to RST */ if (gline == 0) { fprintf(rfp, "%s", rb); gline = 1; } /* * Clear text line buffer */ for (i=0,rp=rb; i