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, "Hexadecimal\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);
113 #if (NCPS==8) || !defined (MLH_MAP)
114 /* Used for qsort call in lstarea */
115 static int _cmpSymByAddr(const void *p1, const void *p2)
117 struct sym **s1 = (struct sym **)(p1);
118 struct sym **s2 = (struct sym **)(p2);
119 int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
120 ((*s2)->s_addr + (*s2)->s_axp->a_addr);
122 /* Sort first by address, then by name. */
127 return strcmp((*s1)->s_id,(*s2)->s_id);
134 /*)Function VOID lstarea(xp)
136 * area * xp pointer to an area structure
138 * The function lstarea() creates the linker map output for
139 * the area specified by pointer xp. The generated output
140 * area header includes the area name, starting address,
141 * size of area, number of words (in decimal), and the
142 * area attributes. The symbols defined in this area are
143 * sorted by ascending address and output one per line
144 * in the selected radix.
147 * areax * oxp pointer to an area extension structure
148 * int c character value
150 * int j bubble sort update status
151 * char * ptr pointer to an id string
152 * int nmsym number of symbols in area
153 * Addr_T a0 temporary
154 * Addr_T ai temporary
155 * Addr_T aj temporary
156 * sym * sp pointer to a symbol structure
157 * sym ** p pointer to an array of
158 * pointers to symbol structures
161 * FILE *mfp Map output file handle
162 * sym *symhash[NHASH] array of pointers to NHASH
163 * linked symbol lists
164 * int xflag Map file radix type flag
167 * int fprintf() c_library
168 * VOID free() c_library
169 * char * malloc() c_library
170 * char putc() c_library
171 * VOID slew() lklist.c
174 * Map output generated.
182 register struct areax *oxp;
192 fprintf(mfp, "Hexadecimal\n\n");
195 fprintf(mfp, "Octal\n\n");
198 fprintf(mfp, "Decimal\n\n");
200 fprintf(mfp, "Area ");
201 fprintf(mfp, "Addr Size Decimal Bytes (Attributes)\n");
202 fprintf(mfp, "-------------------------------- ");
203 fprintf(mfp, "---- ---- ------- ----- ------------\n");
208 fprintf(mfp, "%-32s", ptr ); /* JLH: width matches --- above */
212 fprintf(mfp, " %04X %04X", ai, aj);
215 fprintf(mfp, " %06o %06o", ai, aj);
218 fprintf(mfp, " %05u %05u", ai, aj);
220 fprintf(mfp, " = %6u. bytes ", aj);
221 if (xp->a_flag & A_ABS) {
222 fprintf(mfp, "(ABS");
224 fprintf(mfp, "(REL");
226 if (xp->a_flag & A_OVR) {
227 fprintf(mfp, ",OVR");
229 fprintf(mfp, ",CON");
231 if (xp->a_flag & A_PAG) {
232 fprintf(mfp, ",PAG");
235 if (xp->a_flag & A_PAG) {
238 if (ai || aj) { fprintf(mfp, " "); }
239 if (ai) { fprintf(mfp, " Boundary"); }
240 if (ai & aj) { fprintf(mfp, " /"); }
241 if (aj) { fprintf(mfp, " Length"); }
242 if (ai || aj) { fprintf(mfp, " Error"); }
246 * Find number of symbols in area
251 for (i=0; i<NHASH; i++) {
254 if (oxp == sp->s_axp)
267 * Allocate space for an array of pointers to symbols
270 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
272 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
278 for (i=0; i<NHASH; i++) {
281 if (oxp == sp->s_axp) {
290 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
293 * Symbol Table Output
296 fprintf(mfp, "\n\n");
297 fprintf(mfp, " Value Global\n");
298 fprintf(mfp, " ----- --------------------------------");
304 aj = sp->s_addr + sp->s_axp->a_addr;
306 fprintf(mfp, " %04X ", aj);
309 fprintf(mfp, "%06o ", aj);
312 fprintf(mfp, " %05u ", aj);
315 fprintf(mfp, "%s", ptr );
322 VOID lstarea(struct area *xp)
324 register struct areax *oxp;
327 Addr_T a0, ai = 0, aj = 0;
332 * Find number of symbols in area
337 for (i=0; i<NHASH; i++) {
340 if (oxp == sp->s_axp)
349 * Symbol Table Output
351 if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
352 fprintf(mfp, "AREA %s\n", xp->a_id );
355 fprintf(mfp, "\tRADIX OCTAL\n" );
358 fprintf(mfp, "\tRADIX DEC\n" );
361 fprintf(mfp, "\tRADIX HEX\n" );
364 fprintf( mfp, "\tBASE %04X\n"
367 , xp->a_addr, xp->a_size );
368 if (xp->a_flag & A_ABS) {
373 if (xp->a_flag & A_OVR) {
374 fprintf(mfp, " OVR");
376 fprintf(mfp, " CON");
378 if (xp->a_flag & A_PAG) {
379 fprintf(mfp, " PAG");
381 if (xp->a_flag & A_PAG) {
384 if (ai || aj) { fprintf(mfp, " "); }
385 if (ai) { fprintf(mfp, " Boundary"); }
386 if (ai & aj) { fprintf(mfp, " /"); }
387 if (aj) { fprintf(mfp, " Length"); }
388 if (ai || aj) { fprintf(mfp, " Error"); }
394 * Allocate space for an array of pointers to symbols
397 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
399 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
405 for (i=0; i<NHASH; i++) {
408 if (oxp == sp->s_axp) {
418 * Bubble Sort of Addresses in Symbol Table Array
424 a0 = sp->s_addr + sp->s_axp->a_addr;
425 for (i=1; i<nmsym; ++i) {
427 ai = sp->s_addr + sp->s_axp->a_addr;
437 fprintf( mfp, "\tGLOBALS\n");
440 fprintf(mfp, "\t\t%s\t%04X\n", p[i]->s_id, p[i]->s_addr + p[i]->s_axp->a_addr );
451 /*)Function VOID lstarea(xp)
453 * area * xp pointer to an area structure
455 * The function lstarea() creates the linker map output for
456 * the area specified by pointer xp. The generated output
457 * area header includes the area name, starting address,
458 * size of area, number of words (in decimal), and the
459 * area attributes. The symbols defined in this area are
460 * sorted by ascending address and output four per line
461 * in the selected radix.
464 * areax * oxp pointer to an area extension structure
465 * int c character value
467 * int j bubble sort update status
468 * char * ptr pointer to an id string
469 * int nmsym number of symbols in area
470 * Addr_T a0 temporary
471 * Addr_T ai temporary
472 * Addr_T aj temporary
473 * sym * sp pointer to a symbol structure
474 * sym ** p pointer to an array of
475 * pointers to symbol structures
478 * FILE *mfp Map output file handle
479 * sym *symhash[NHASH] array of pointers to NHASH
480 * linked symbol lists
481 * int xflag Map file radix type flag
484 * int fprintf() c_library
485 * VOID free() c_library
486 * char * malloc() c_library
487 * char putc() c_library
488 * VOID slew() lklist.c
491 * Map output generated.
498 register struct areax *oxp;
512 while (ptr < &xp->a_id[NCPS]) {
513 if ((c = *ptr++) != 0) {
522 fprintf(mfp, " %04X %04X", ai, aj);
525 fprintf(mfp, " %06o %06o", ai, aj);
528 fprintf(mfp, " %05u %05u", ai, aj);
530 fprintf(mfp, " = %6u. bytes ", aj);
531 if (xp->a_flag & A_ABS) {
532 fprintf(mfp, "(ABS");
534 fprintf(mfp, "(REL");
536 if (xp->a_flag & A_OVR) {
537 fprintf(mfp, ",OVR");
539 fprintf(mfp, ",CON");
541 if (xp->a_flag & A_PAG) {
542 fprintf(mfp, ",PAG");
545 if (xp->a_flag & A_PAG) {
548 if (ai || aj) { fprintf(mfp, " "); }
549 if (ai) { fprintf(mfp, " Boundary"); }
550 if (ai & aj) { fprintf(mfp, " /"); }
551 if (aj) { fprintf(mfp, " Length"); }
552 if (ai || aj) { fprintf(mfp, " Error"); }
556 * Find number of symbols in area
561 for (i=0; i<NHASH; i++) {
564 if (oxp == sp->s_axp)
578 * Allocate space for an array of pointers to symbols
581 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
583 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
590 for (i=0; i<NHASH; i++) {
593 if (oxp == sp->s_axp) {
602 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
605 * Symbol Table Output
615 aj = sp->s_addr + sp->s_axp->a_addr;
617 fprintf(mfp, " %04X ", aj);
620 fprintf(mfp, "%06o ", aj);
623 fprintf(mfp, " %05u ", aj);
626 fprintf(mfp, "%*s", NCPS, ptr );
638 VOID lstareatosym(struct area *xp)
640 /* Output the current area symbols to a NO$GMB .sym file */
641 register struct areax *oxp;
649 * Find number of symbols in area
654 for (i=0; i<NHASH; i++) {
657 if (oxp == sp->s_axp)
666 * Symbol Table Output
668 if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
669 /* Dont worry about any area information */
670 fprintf(mfp, "; Area: %s\n", xp->a_id );
673 * Allocate space for an array of pointers to symbols
676 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
678 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
684 for (i=0; i<NHASH; i++) {
687 if (oxp == sp->s_axp) {
697 * Bubble Sort of Addresses in Symbol Table Array
703 a0 = sp->s_addr + sp->s_axp->a_addr;
704 for (i=1; i<nmsym; ++i) {
706 ai = sp->s_addr + sp->s_axp->a_addr;
717 /* no$gmb requires the symbol names to be less than 32 chars long. Truncate. */
719 strncpy(name, p[i]->s_id, 31);
721 if ((strncmp("l__", name, 3)!=0)&&(strchr(name,' ')==NULL)) {
722 a0=p[i]->s_addr + p[i]->s_axp->a_addr;
724 /* Not inside the ROM, so treat as being in bank zero */
725 fprintf(mfp, "00:%04X %s\n", a0, name);
728 fprintf(mfp, "%02X:%04X %s\n", a0/16384, a0, name);
739 /*)Function VOID lkulist(i)
741 * int i i # 0 process LST to RST file
742 * i = 0 copy remainder of LST file
743 * to RST file and close files
745 * The function lkulist() creates a relocated listing (.rst)
746 * output file from the ASxxxx assembler listing (.lst)
747 * files. The .lst file's program address and code bytes
748 * are changed to reflect the changes made by ASlink as
749 * the .rel files are combined into a single relocated
753 * Addr_T pc current program counter address
756 * int hilo byte order
757 * int gline get a line from the LST file
758 * to translate for the RST file
759 * char rb[] read listing file text line
760 * FILE *rfp The file handle to the current
762 * int rtcnt count of data words
763 * int rtflg[] output the data flag
764 * Addr_T rtval[] relocated data
765 * FILE *tfp The file handle to the current
766 * LST file being scanned
769 * int fclose() c_library
770 * int fgets() c_library
771 * int fprintf() c_library
772 * VOID lkalist() lklist.c
773 * VOID lkglist() lklist.c
776 * A .rst file is created for each available .lst
777 * file associated with a .rel file.
787 * Exit if listing file is not open
793 * Normal processing of LST to RST
797 * Evaluate current code address
800 pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
802 pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
806 * Line with only address
812 * Line with address and code
815 for (i=2; i < rtcnt; i++) {
817 lkglist(pc++, rtval[i] & 0xFF);
823 * Copy remainder of LST to RST
827 fprintf(rfp, "%s", rb);
829 while (fgets(rb, sizeof(rb), tfp) != 0) {
830 fprintf(rfp, "%s", rb);
839 /*)Function VOID lkalist(pc)
841 * int pc current program counter value
843 * The function lkalist() performs the following functions:
845 * (1) if the value of gline = 0 then the current listing
846 * file line is copied to the relocated listing file output.
848 * (2) the listing file is read line by line and copied to
849 * the relocated listing file until a valid source
850 * line number and a program counter value of the correct
851 * radix is found. The new relocated pc value is substituted
852 * and the line is written to the RST file.
856 * char str[] temporary string
859 * int gcntr data byte counter
860 * int gline get a line from the LST file
861 * to translate for the RST file
862 * char rb[] read listing file text line
863 * char *rp pointer to listing file text line
864 * FILE *rfp The file handle to the current
866 * FILE *tfp The file handle to the current
867 * LST file being scanned
871 * int fclose() c_library
872 * int fgets() c_library
873 * int fprintf() c_library
874 * int sprintf() c_library
875 * char * strncpy() c_library
878 * Lines of the LST file are copied to the RST file,
879 * the last line copied has the code address
880 * updated to reflect the program relocation.
891 * Exit if listing file is not open
893 loop: if (tfp == NULL)
897 * Copy current LST to RST
900 fprintf(rfp, "%s", rb);
905 * Clear text line buffer
907 for (i=0,rp=rb; i<sizeof(rb); i++) {
912 * Get next LST text line
914 if (fgets(rb, sizeof(rb), tfp) == NULL) {
923 * Must have an ASxxxx Listing line number
925 if (!dgt(RAD10, &rb[30], 1)) {
926 fprintf(rfp, "%s", rb);
931 * Must have an address in the expected radix
934 if (!dgt(RAD16, &rb[3], 4)) {
935 fprintf(rfp, "%s", rb);
938 sprintf(str, "%04X", pc);
939 strncpy(&rb[3], str, 4);
942 if (!dgt(RAD10, &rb[3], 5)) {
943 fprintf(rfp, "%s", rb);
946 sprintf(str, "%05d", pc);
947 strncpy(&rb[3], str, 5);
950 if (!dgt(RAD8, &rb[3], 6)) {
951 fprintf(rfp, "%s", rb);
954 sprintf(str, "%06o", pc);
955 strncpy(&rb[3], str, 6);
959 * Copy updated LST text line to RST
961 fprintf(rfp, "%s", rb);
965 /*)Function VOID lkglist(pc,v)
967 * int pc current program counter value
968 * int v value of byte at this address
970 * The function lkglist() performs the following functions:
972 * (1) if the value of gline = 1 then the listing file
973 * is read line by line and copied to the
974 * relocated listing file until a valid source
975 * line number and a program counter value of the correct
978 * (2) The new relocated values and code address are
979 * substituted and the line may be written to the RST file.
983 * char str[] temporary string
986 * int gcntr data byte counter
987 * set to -1 for a continuation line
988 * int gline get a line from the LST file
989 * to translate for the RST file
990 * char rb[] read listing file text line
991 * char *rp pointer to listing file text line
992 * FILE *rfp The file handle to the current
994 * FILE *tfp The file handle to the current
995 * LST file being scanned
999 * int fclose() c_library
1000 * int fgets() c_library
1001 * int fprintf() c_library
1002 * int sprintf() c_library
1003 * char * strncpy() c_library
1006 * Lines of the LST file are copied to the RST file
1007 * with updated data values and code addresses.
1019 * Exit if listing file is not open
1021 loop: if (tfp == NULL)
1025 * Get next LST text line
1029 * Clear text line buffer
1031 for (i=0,rp=rb; i<sizeof(rb); i++) {
1036 * Get next LST text line
1038 if (fgets(rb, sizeof(rb), tfp) == NULL) {
1047 * Check for a listing line number if required
1050 if (!dgt(RAD10, &rb[30], 1)) {
1051 fprintf(rfp, "%s", rb);
1069 rp = &rb[8 + (3 * gcntr)];
1072 * Number must be of proper radix
1074 if (!dgt(RAD16, rp, 2)) {
1075 fprintf(rfp, "%s", rb);
1080 * Output new data value, overwrite relocation codes
1082 sprintf(str, " %02X", v);
1083 strncpy(rp-1, str, 3);
1088 * Output relocated code address
1091 if (dgt(RAD16, &rb[3], 4)) {
1092 sprintf(str, "%04X", pc);
1093 strncpy(&rb[3], str, 4);
1097 * Output text line when updates finished
1100 fprintf(rfp, "%s", rb);
1115 rp = &rb[9 + (3 * gcntr)];
1118 * Number must be of proper radix
1120 if (!dgt(RAD10, rp, 3)) {
1121 fprintf(rfp, "%s", rb);
1126 * Output new data value, overwrite relocation codes
1128 sprintf(str, " %03d", v);
1129 strncpy(rp-1, str, 4);
1134 * Output relocated code address
1137 if (dgt(RAD10, &rb[3], 5)) {
1138 sprintf(str, "%05d", pc);
1139 strncpy(&rb[3], str, 5);
1143 * Output text line when updates finished
1146 fprintf(rfp, "%s", rb);
1161 rp = &rb[10 + (3 * gcntr)];
1164 * Number must be of proper radix
1166 if (!dgt(RAD8, rp, 3)) {
1167 fprintf(rfp, "%s", rb);
1172 * Output new data value, overwrite relocation codes
1174 sprintf(str, " %03o", v);
1175 strncpy(rp-1, str, 4);
1180 * Output relocated code address
1183 if (dgt(RAD8, &rb[3], 6)) {
1184 sprintf(str, "%06o", pc);
1185 strncpy(&rb[3], str, 6);
1189 * Output text line when updates finished
1192 fprintf(rfp, "%s", rb);
1199 /*)Function int dgt(rdx,str,n)
1201 * int rdx radix bit code
1202 * char *str pointer to the test string
1203 * int n number of characters to check
1205 * The function dgt() verifies that the string under test
1206 * is of the specified radix.
1209 * int i loop counter
1212 * ctype[] array of character types
1228 for (i=0; i<n; i++) {
1229 if ((ctype[(unsigned char)(*str++)] & rdx) == 0)