4 * (C) Copyright 1989-1995
19 * The module lklist.c contains the functions which
20 * output the linker .map file and produce a relocated
23 * lklist.c contains the following functions:
32 * lklist.c contains no local variables.
35 /*)Function VOID slew(fp)
37 * FILE * fp output file handle
39 * The function slew() increments the page line counter.
40 * If the number of lines exceeds the maximum number of
41 * lines per page then a page skip and a page header are
48 * int lop current line number on page
49 * int xflag Map file radix type flag
52 * int fprintf() c_library
53 * VOID newpag() lklist.c
56 * The page line and the page count may be updated.
68 fprintf(fp, "Hexidecimal\n\n");
71 fprintf(fp, "Octal\n\n");
74 fprintf(fp, "Decimal\n\n");
76 fprintf(fp, "Area Addr Size");
77 fprintf(fp, " Decimal Bytes (Attributes)\n");
79 fprintf(fp, " Value--Global");
85 /*)Function VOID newpag()
87 * The function newpag() outputs a page skip, writes the
88 * first page header line, sets the line count to 1, and
89 * increments the page counter.
95 * int lop current line number on page
96 * int page current page number
99 * int fprintf() c_library
102 * The page and line counters are updated.
109 fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page);
116 /*)Function VOID lstarea(xp)
118 * area * xp pointer to an area structure
120 * The function lstarea() creates the linker map output for
121 * the area specified by pointer xp. The generated output
122 * area header includes the area name, starting address,
123 * size of area, number of words (in decimal), and the
124 * area attributes. The symbols defined in this area are
125 * sorted by ascending address and output one per line
126 * in the selected radix.
129 * areax * oxp pointer to an area extension structure
130 * int c character value
132 * int j bubble sort update status
133 * char * ptr pointer to an id string
134 * int nmsym number of symbols in area
135 * Addr_T a0 temporary
136 * Addr_T ai temporary
137 * Addr_T aj temporary
138 * sym * sp pointer to a symbol structure
139 * sym ** p pointer to an array of
140 * pointers to symbol structures
143 * FILE *mfp Map output file handle
144 * sym *symhash[NHASH] array of pointers to NHASH
145 * linked symbol lists
146 * int xflag Map file radix type flag
149 * int fprintf() c_library
150 * VOID free() c_library
151 * char * malloc() c_library
152 * char putc() c_library
153 * VOID slew() lklist.c
156 * Map output generated.
164 // register struct area *op;
165 register struct areax *oxp;
175 fprintf(mfp, "Hexidecimal\n\n");
178 fprintf(mfp, "Octal\n\n");
181 fprintf(mfp, "Decimal\n\n");
183 fprintf(mfp, "Area ");
184 fprintf(mfp, "Addr Size Decimal Bytes (Attributes)\n");
185 fprintf(mfp, "-------------------------------- ");
186 fprintf(mfp, "---- ---- ------- ----- ------------\n");
191 while (ptr < &xp->a_id[NCPS]) {
192 if ((c = *ptr++) != 0) {
201 fprintf(mfp, " %04X %04X", ai, aj);
204 fprintf(mfp, " %06o %06o", ai, aj);
207 fprintf(mfp, " %05u %05u", ai, aj);
209 fprintf(mfp, " = %6u. bytes ", aj);
210 if (xp->a_flag & A_ABS) {
211 fprintf(mfp, "(ABS");
213 fprintf(mfp, "(REL");
215 if (xp->a_flag & A_OVR) {
216 fprintf(mfp, ",OVR");
218 fprintf(mfp, ",CON");
220 if (xp->a_flag & A_PAG) {
221 fprintf(mfp, ",PAG");
224 if (xp->a_flag & A_PAG) {
227 if (ai || aj) { fprintf(mfp, " "); }
228 if (ai) { fprintf(mfp, " Boundary"); }
229 if (ai & aj) { fprintf(mfp, " /"); }
230 if (aj) { fprintf(mfp, " Length"); }
231 if (ai || aj) { fprintf(mfp, " Error"); }
235 * Find number of symbols in area
240 for (i=0; i<NHASH; i++) {
243 if (oxp == sp->s_axp)
256 * Allocate space for an array of pointers to symbols
259 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
261 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
267 for (i=0; i<NHASH; i++) {
270 if (oxp == sp->s_axp) {
280 * Bubble Sort of Addresses in Symbol Table Array
286 a0 = sp->s_addr + sp->s_axp->a_addr;
287 for (i=1; i<nmsym; ++i) {
289 ai = sp->s_addr + sp->s_axp->a_addr;
300 * Symbol Table Output
303 fprintf(mfp, "\n\n");
304 fprintf(mfp, " Value Global\n");
305 fprintf(mfp, " ----- --------------------------------");
311 aj = sp->s_addr + sp->s_axp->a_addr;
313 fprintf(mfp, " %04X ", aj);
316 fprintf(mfp, "%06o ", aj);
319 fprintf(mfp, " %05u ", aj);
322 while (ptr < &sp->s_id[NCPS]) {
323 if ((c = *ptr++) != 0) {
335 VOID lstarea(struct area *xp)
337 register struct areax *oxp;
340 Addr_T a0, ai = 0, aj = 0;
345 * Find number of symbols in area
350 for (i=0; i<NHASH; i++) {
353 if (oxp == sp->s_axp)
362 * Symbol Table Output
364 if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
365 fprintf(mfp, "AREA %s\n", xp->a_id );
368 fprintf(mfp, "\tRADIX OCTAL\n" );
371 fprintf(mfp, "\tRADIX DEC\n" );
374 fprintf(mfp, "\tRADIX HEX\n" );
377 fprintf( mfp, "\tBASE %04X\n"
380 , xp->a_addr, xp->a_size );
381 if (xp->a_flag & A_ABS) {
386 if (xp->a_flag & A_OVR) {
387 fprintf(mfp, " OVR");
389 fprintf(mfp, " CON");
391 if (xp->a_flag & A_PAG) {
392 fprintf(mfp, " PAG");
394 if (xp->a_flag & A_PAG) {
397 if (ai || aj) { fprintf(mfp, " "); }
398 if (ai) { fprintf(mfp, " Boundary"); }
399 if (ai & aj) { fprintf(mfp, " /"); }
400 if (aj) { fprintf(mfp, " Length"); }
401 if (ai || aj) { fprintf(mfp, " Error"); }
407 * Allocate space for an array of pointers to symbols
410 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
412 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
418 for (i=0; i<NHASH; i++) {
421 if (oxp == sp->s_axp) {
431 * Bubble Sort of Addresses in Symbol Table Array
437 a0 = sp->s_addr + sp->s_axp->a_addr;
438 for (i=1; i<nmsym; ++i) {
440 ai = sp->s_addr + sp->s_axp->a_addr;
450 fprintf( mfp, "\tGLOBALS\n");
453 fprintf(mfp, "\t\t%s\t%04X\n", p[i]->s_id, p[i]->s_addr + p[i]->s_axp->a_addr );
464 /*)Function VOID lstarea(xp)
466 * area * xp pointer to an area structure
468 * The function lstarea() creates the linker map output for
469 * the area specified by pointer xp. The generated output
470 * area header includes the area name, starting address,
471 * size of area, number of words (in decimal), and the
472 * area attributes. The symbols defined in this area are
473 * sorted by ascending address and output four per line
474 * in the selected radix.
477 * areax * oxp pointer to an area extension structure
478 * int c character value
480 * int j bubble sort update status
481 * char * ptr pointer to an id string
482 * int nmsym number of symbols in area
483 * Addr_T a0 temporary
484 * Addr_T ai temporary
485 * Addr_T aj temporary
486 * sym * sp pointer to a symbol structure
487 * sym ** p pointer to an array of
488 * pointers to symbol structures
491 * FILE *mfp Map output file handle
492 * sym *symhash[NHASH] array of pointers to NHASH
493 * linked symbol lists
494 * int xflag Map file radix type flag
497 * int fprintf() c_library
498 * VOID free() c_library
499 * char * malloc() c_library
500 * char putc() c_library
501 * VOID slew() lklist.c
504 * Map output generated.
511 register struct areax *oxp;
525 while (ptr < &xp->a_id[NCPS]) {
526 if ((c = *ptr++) != 0) {
535 fprintf(mfp, " %04X %04X", ai, aj);
538 fprintf(mfp, " %06o %06o", ai, aj);
541 fprintf(mfp, " %05u %05u", ai, aj);
543 fprintf(mfp, " = %6u. bytes ", aj);
544 if (xp->a_flag & A_ABS) {
545 fprintf(mfp, "(ABS");
547 fprintf(mfp, "(REL");
549 if (xp->a_flag & A_OVR) {
550 fprintf(mfp, ",OVR");
552 fprintf(mfp, ",CON");
554 if (xp->a_flag & A_PAG) {
555 fprintf(mfp, ",PAG");
558 if (xp->a_flag & A_PAG) {
561 if (ai || aj) { fprintf(mfp, " "); }
562 if (ai) { fprintf(mfp, " Boundary"); }
563 if (ai & aj) { fprintf(mfp, " /"); }
564 if (aj) { fprintf(mfp, " Length"); }
565 if (ai || aj) { fprintf(mfp, " Error"); }
569 * Find number of symbols in area
574 for (i=0; i<NHASH; i++) {
577 if (oxp == sp->s_axp)
591 * Allocate space for an array of pointers to symbols
594 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
596 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
603 for (i=0; i<NHASH; i++) {
606 if (oxp == sp->s_axp) {
616 * Bubble Sort of Addresses in Symbol Table Array
622 a0 = sp->s_addr + sp->s_axp->a_addr;
623 for (i=1; i<nmsym; ++i) {
625 ai = sp->s_addr + sp->s_axp->a_addr;
636 * Symbol Table Output
646 aj = sp->s_addr + sp->s_axp->a_addr;
648 fprintf(mfp, " %04X ", aj);
651 fprintf(mfp, "%06o ", aj);
654 fprintf(mfp, " %05u ", aj);
657 while (ptr < &sp->s_id[NCPS]) {
658 if ((c = *ptr++) != 0) {
675 VOID lstareatosym(struct area *xp)
677 /* Output the current area symbols to a NO$GMB .sym file */
678 register struct areax *oxp;
686 * Find number of symbols in area
691 for (i=0; i<NHASH; i++) {
694 if (oxp == sp->s_axp)
703 * Symbol Table Output
705 if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
706 /* Dont worry about any area information */
707 fprintf(mfp, "; Area: %s\n", xp->a_id );
710 * Allocate space for an array of pointers to symbols
713 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
715 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
721 for (i=0; i<NHASH; i++) {
724 if (oxp == sp->s_axp) {
734 * Bubble Sort of Addresses in Symbol Table Array
740 a0 = sp->s_addr + sp->s_axp->a_addr;
741 for (i=1; i<nmsym; ++i) {
743 ai = sp->s_addr + sp->s_axp->a_addr;
754 /* no$gmb requires the symbol names to be less than 32 chars long. Truncate. */
756 strncpy(name, p[i]->s_id, 31);
758 if ((strncmp("l__", name, 3)!=0)&&(strchr(name,' ')==NULL)) {
759 a0=p[i]->s_addr + p[i]->s_axp->a_addr;
761 /* Not inside the ROM, so treat as being in bank zero */
762 fprintf(mfp, "00:%04X %s\n", a0, name);
765 fprintf(mfp, "%02X:%04X %s\n", a0/16384, a0, name);
776 /*)Function VOID lkulist(i)
778 * int i i # 0 process LST to RST file
779 * i = 0 copy remainder of LST file
780 * to RST file and close files
782 * The function lkulist() creates a relocated listing (.rst)
783 * output file from the ASxxxx assembler listing (.lst)
784 * files. The .lst file's program address and code bytes
785 * are changed to reflect the changes made by ASlink as
786 * the .rel files are combined into a single relocated
790 * Addr_T pc current program counter address
793 * int hilo byte order
794 * int gline get a line from the LST file
795 * to translate for the RST file
796 * char rb[] read listing file text line
797 * FILE *rfp The file handle to the current
799 * int rtcnt count of data words
800 * int rtflg[] output the data flag
801 * Addr_T rtval[] relocated data
802 * FILE *tfp The file handle to the current
803 * LST file being scanned
806 * int fclose() c_library
807 * int fgets() c_library
808 * int fprintf() c_library
809 * VOID lkalist() lklist.c
810 * VOID lkglist() lklist.c
813 * A .rst file is created for each available .lst
814 * file associated with a .rel file.
824 * Exit if listing file is not open
830 * Normal processing of LST to RST
834 * Evaluate current code address
837 pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
839 pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
843 * Line with only address
849 * Line with address and code
852 for (i=2; i < rtcnt; i++) {
854 lkglist(pc++, rtval[i] & 0xFF);
860 * Copy remainder of LST to RST
866 while (fgets(rb, sizeof(rb), tfp) != 0) {
876 /*)Function VOID lkalist(pc)
878 * int pc current program counter value
880 * The function lkalist() performs the following functions:
882 * (1) if the value of gline = 0 then the current listing
883 * file line is copied to the relocated listing file output.
885 * (2) the listing file is read line by line and copied to
886 * the relocated listing file until a valid source
887 * line number and a program counter value of the correct
888 * radix is found. The new relocated pc value is substituted
889 * and the line is written to the RST file.
893 * char str[] temporary string
896 * int gcntr data byte counter
897 * int gline get a line from the LST file
898 * to translate for the RST file
899 * char rb[] read listing file text line
900 * char *rp pointer to listing file text line
901 * FILE *rfp The file handle to the current
903 * FILE *tfp The file handle to the current
904 * LST file being scanned
908 * int fclose() c_library
909 * int fgets() c_library
910 * int fprintf() c_library
911 * int sprintf() c_library
912 * char * strncpy() c_library
915 * Lines of the LST file are copied to the RST file,
916 * the last line copied has the code address
917 * updated to reflect the program relocation.
928 * Exit if listing file is not open
930 loop: if (tfp == NULL)
934 * Copy current LST to RST
942 * Clear text line buffer
944 for (i=0,rp=rb; i<sizeof(rb); i++) {
949 * Get next LST text line
951 if (fgets(rb, sizeof(rb), tfp) == NULL) {
960 * Must have an ASxxxx Listing line number
962 if (!dgt(RAD10, &rb[30], 1)) {
968 * Must have an address in the expected radix
971 if (!dgt(RAD16, &rb[3], 4)) {
975 sprintf(str, "%04X", pc);
976 strncpy(&rb[3], str, 4);
979 if (!dgt(RAD10, &rb[3], 5)) {
983 sprintf(str, "%05d", pc);
984 strncpy(&rb[3], str, 5);
987 if (!dgt(RAD8, &rb[3], 6)) {
991 sprintf(str, "%06o", pc);
992 strncpy(&rb[3], str, 6);
996 * Copy updated LST text line to RST
1002 /*)Function VOID lkglist(pc,v)
1004 * int pc current program counter value
1005 * int v value of byte at this address
1007 * The function lkglist() performs the following functions:
1009 * (1) if the value of gline = 1 then the listing file
1010 * is read line by line and copied to the
1011 * relocated listing file until a valid source
1012 * line number and a program counter value of the correct
1015 * (2) The new relocated values and code address are
1016 * substituted and the line may be written to the RST file.
1019 * int i loop counter
1020 * char str[] temporary string
1023 * int gcntr data byte counter
1024 * set to -1 for a continuation line
1025 * int gline get a line from the LST file
1026 * to translate for the RST file
1027 * char rb[] read listing file text line
1028 * char *rp pointer to listing file text line
1029 * FILE *rfp The file handle to the current
1031 * FILE *tfp The file handle to the current
1032 * LST file being scanned
1035 * int dgt() lklist.c
1036 * int fclose() c_library
1037 * int fgets() c_library
1038 * int fprintf() c_library
1039 * int sprintf() c_library
1040 * char * strncpy() c_library
1043 * Lines of the LST file are copied to the RST file
1044 * with updated data values and code addresses.
1056 * Exit if listing file is not open
1058 loop: if (tfp == NULL)
1062 * Get next LST text line
1066 * Clear text line buffer
1068 for (i=0,rp=rb; i<sizeof(rb); i++) {
1073 * Get next LST text line
1075 if (fgets(rb, sizeof(rb), tfp) == NULL) {
1084 * Check for a listing line number if required
1087 if (!dgt(RAD10, &rb[30], 1)) {
1106 rp = &rb[8 + (3 * gcntr)];
1109 * Number must be of proper radix
1111 if (!dgt(RAD16, rp, 2)) {
1117 * Output new data value, overwrite relocation codes
1119 sprintf(str, " %02X", v);
1120 strncpy(rp-1, str, 3);
1125 * Output relocated code address
1128 if (dgt(RAD16, &rb[3], 4)) {
1129 sprintf(str, "%04X", pc);
1130 strncpy(&rb[3], str, 4);
1134 * Output text line when updates finished
1152 rp = &rb[9 + (3 * gcntr)];
1155 * Number must be of proper radix
1157 if (!dgt(RAD10, rp, 3)) {
1163 * Output new data value, overwrite relocation codes
1165 sprintf(str, " %03d", v);
1166 strncpy(rp-1, str, 4);
1171 * Output relocated code address
1174 if (dgt(RAD10, &rb[3], 5)) {
1175 sprintf(str, "%05d", pc);
1176 strncpy(&rb[3], str, 5);
1180 * Output text line when updates finished
1198 rp = &rb[10 + (3 * gcntr)];
1201 * Number must be of proper radix
1203 if (!dgt(RAD8, rp, 3)) {
1209 * Output new data value, overwrite relocation codes
1211 sprintf(str, " %03o", v);
1212 strncpy(rp-1, str, 4);
1217 * Output relocated code address
1220 if (dgt(RAD8, &rb[3], 6)) {
1221 sprintf(str, "%06o", pc);
1222 strncpy(&rb[3], str, 6);
1226 * Output text line when updates finished
1236 /*)Function int dgt(rdx,str,n)
1238 * int rdx radix bit code
1239 * char *str pointer to the test string
1240 * int n number of characters to check
1242 * The function dgt() verifies that the string under test
1243 * is of the specified radix.
1246 * int i loop counter
1249 * ctype[] array of character types
1265 for (i=0; i<n; i++) {
1266 if ((ctype[(unsigned char)(*str++)] & rdx) == 0)