4 * (C) Copyright 1989-1995
12 * - lstarea: show s_id as string rather than array [NCPS]
13 * - lstarea: show a_id as string rather than array [NCPS]
14 * 31-Oct-97 JLH: add NoICE output file genration in lstarea
15 * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output
25 * The module lklist.c contains the functions which
26 * output the linker .map file and produce a relocated
29 * lklist.c contains the following functions:
38 * lklist.c contains no local variables.
41 /*)Function VOID slew(fp)
43 * FILE * fp output file handle
45 * The function slew() increments the page line counter.
46 * If the number of lines exceeds the maximum number of
47 * lines per page then a page skip and a page header are
54 * int lop current line number on page
55 * int xflag Map file radix type flag
58 * int fprintf() c_library
59 * VOID newpag() lklist.c
62 * The page line and the page count may be updated.
74 fprintf(fp, "Hexadecimal\n\n");
77 fprintf(fp, "Octal\n\n");
80 fprintf(fp, "Decimal\n\n");
82 fprintf(fp, "Area Addr Size");
83 fprintf(fp, " Decimal Bytes (Attributes)\n");
85 fprintf(fp, " Value--Global");
91 /*)Function VOID newpag()
93 * The function newpag() outputs a page skip, writes the
94 * first page header line, sets the line count to 1, and
95 * increments the page counter.
101 * int lop current line number on page
102 * int page current page number
105 * int fprintf() c_library
108 * The page and line counters are updated.
115 fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page);
119 /* Used for qsort call in lstsym */
120 static int _cmpSymByAddr(const void *p1, const void *p2)
122 struct sym **s1 = (struct sym **)(p1);
123 struct sym **s2 = (struct sym **)(p2);
124 int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
125 ((*s2)->s_addr + (*s2)->s_axp->a_addr);
127 /* Sort first by address, then by name. */
132 return strcmp((*s1)->s_id,(*s2)->s_id);
139 /*)Function VOID lstarea(xp)
141 * area * xp pointer to an area structure
143 * The function lstarea() creates the linker map output for
144 * the area specified by pointer xp. The generated output
145 * area header includes the area name, starting address,
146 * size of area, number of words (in decimal), and the
147 * area attributes. The symbols defined in this area are
148 * sorted by ascending address and output one per line
149 * in the selected radix.
152 * areax * oxp pointer to an area extension structure
153 * int c character value
155 * int j bubble sort update status
156 * char * ptr pointer to an id string
157 * int nmsym number of symbols in area
158 * Addr_T a0 temporary
159 * Addr_T ai temporary
160 * Addr_T aj temporary
161 * sym * sp pointer to a symbol structure
162 * sym ** p pointer to an array of
163 * pointers to symbol structures
166 * FILE *mfp Map output file handle
167 * sym *symhash[NHASH] array of pointers to NHASH
168 * linked symbol lists
169 * int xflag Map file radix type flag
172 * int fprintf() c_library
173 * VOID free() c_library
174 * char * malloc() c_library
175 * char putc() c_library
176 * VOID slew() lklist.c
179 * Map output generated.
186 register struct areax *oxp;
199 fprintf(mfp, "Hexadecimal\n\n");
202 fprintf(mfp, "Octal\n\n");
205 fprintf(mfp, "Decimal\n\n");
207 fprintf(mfp, "Area ");
208 fprintf(mfp, "Addr Size Decimal %s (Attributes)\n",
209 (xp->a_flag & A_BIT)?"Bits ":"Bytes");/* JCF: For BIT print bits...*/
210 fprintf(mfp, "-------------------------------- ");
211 fprintf(mfp, "---- ---- ------- ----- ------------\n");
216 fprintf(mfp, "%-32s", ptr ); /* JLH: width matches --- above */
220 fprintf(mfp, " %04X %04X", ai, aj);
223 fprintf(mfp, " %06o %06o", ai, aj);
226 fprintf(mfp, " %05u %05u", ai, aj);
228 fprintf(mfp, " = %6u. %s ", aj,
229 (xp->a_flag & A_BIT)?"bits ":"bytes"); /* JCF: For BIT print bits...*/
230 if (xp->a_flag & A_ABS) {
231 fprintf(mfp, "(ABS");
233 fprintf(mfp, "(REL");
235 if (xp->a_flag & A_OVR) {
236 fprintf(mfp, ",OVR");
238 fprintf(mfp, ",CON");
240 if (xp->a_flag & A_PAG) {
241 fprintf(mfp, ",PAG");
245 if (xp->a_flag & A_CODE) {
246 fprintf(mfp, ",CODE");
249 if (xp->a_flag & A_XDATA) {
250 fprintf(mfp, ",XDATA");
253 if (xp->a_flag & A_BIT) {
254 fprintf(mfp, ",BIT");
258 if (xp->a_flag & A_PAG) {
261 if (ai || aj) { fprintf(mfp, " "); }
262 if (ai) { fprintf(mfp, " Boundary"); }
263 if (ai & aj) { fprintf(mfp, " /"); }
264 if (aj) { fprintf(mfp, " Length"); }
265 if (ai || aj) { fprintf(mfp, " Error"); }
269 * Find number of symbols in area
274 for (i=0; i<NHASH; i++) {
277 if (oxp == sp->s_axp)
290 * Allocate space for an array of pointers to symbols
293 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
295 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
301 for (i=0; i<NHASH; i++) {
304 if (oxp == sp->s_axp) {
315 * Bubble Sort of Addresses in Symbol Table Array
321 a0 = sp->s_addr + sp->s_axp->a_addr;
322 for (i=1; i<nmsym; ++i) {
324 ai = sp->s_addr + sp->s_axp->a_addr;
334 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
338 * Symbol Table Output
342 fprintf(mfp, "\n\n");
343 fprintf(mfp, " Value Global\n");
344 fprintf(mfp, " -------- --------------------------------");
348 fprintf(mfp, " %02X:", memPage);
353 aj = sp->s_addr + sp->s_axp->a_addr;
355 fprintf(mfp, "%04X ", aj);
358 fprintf(mfp, "%06o ", aj);
361 fprintf(mfp, "%05u ", aj);
364 fprintf(mfp, "%s", ptr );
366 /* if cdb flag set the output cdb Information
367 and the symbol has a '$' sign in it then */
370 fprintf(dfp,"L:%s:%X\n",ptr,aj);
372 /* NoICE output of symbol */
373 if (jflag) DefineNoICE( ptr, aj, memPage );
384 /*)Function VOID lstarea(xp)
386 * area * xp pointer to an area structure
388 * The function lstarea() creates the linker map output for
389 * the area specified by pointer xp. The generated output
390 * area header includes the area name, starting address,
391 * size of area, number of words (in decimal), and the
392 * area attributes. The symbols defined in this area are
393 * sorted by ascending address and output four per line
394 * in the selected radix.
397 * areax * oxp pointer to an area extension structure
398 * int c character value
400 * int j bubble sort update status
401 * char * ptr pointer to an id string
402 * int nmsym number of symbols in area
403 * Addr_T a0 temporary
404 * Addr_T ai temporary
405 * Addr_T aj temporary
406 * sym * sp pointer to a symbol structure
407 * sym ** p pointer to an array of
408 * pointers to symbol structures
411 * FILE *mfp Map output file handle
412 * sym *symhash[NHASH] array of pointers to NHASH
413 * linked symbol lists
414 * int xflag Map file radix type flag
417 * int fprintf() c_library
418 * VOID free() c_library
419 * char * malloc() c_library
420 * char putc() c_library
421 * VOID slew() lklist.c
424 * Map output generated.
431 register struct areax *oxp;
446 while (ptr < &xp->a_id[NCPS]) {
447 if ((c = *ptr++) != 0) {
456 fprintf(mfp, " %04X %04X", ai, aj);
459 fprintf(mfp, " %06o %06o", ai, aj);
462 fprintf(mfp, " %05u %05u", ai, aj);
464 fprintf(mfp, " = %6u. bytes ", aj);
465 if (xp->a_flag & A_ABS) {
466 fprintf(mfp, "(ABS");
468 fprintf(mfp, "(REL");
470 if (xp->a_flag & A_OVR) {
471 fprintf(mfp, ",OVR");
473 fprintf(mfp, ",CON");
475 if (xp->a_flag & A_PAG) {
476 fprintf(mfp, ",PAG");
480 if (xp->a_flag & A_CODE) {
481 fprintf(mfp, ",CODE");
484 if (xp->a_flag & A_XDATA) {
485 fprintf(mfp, ",XDATA");
488 if (xp->a_flag & A_BIT) {
489 fprintf(mfp, ",BIT");
493 if (xp->a_flag & A_PAG) {
496 if (ai || aj) { fprintf(mfp, " "); }
497 if (ai) { fprintf(mfp, " Boundary"); }
498 if (ai & aj) { fprintf(mfp, " /"); }
499 if (aj) { fprintf(mfp, " Length"); }
500 if (ai || aj) { fprintf(mfp, " Error"); }
504 * Find number of symbols in area
509 for (i=0; i<NHASH; i++) {
512 if (oxp == sp->s_axp)
526 * Allocate space for an array of pointers to symbols
529 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
531 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
538 for (i=0; i<NHASH; i++) {
541 if (oxp == sp->s_axp) {
552 * Bubble Sort of Addresses in Symbol Table Array
558 a0 = sp->s_addr + sp->s_axp->a_addr;
559 for (i=1; i<nmsym; ++i) {
561 ai = sp->s_addr + sp->s_axp->a_addr;
571 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
575 * Symbol Table Output
583 aj = sp->s_addr + sp->s_axp->a_addr;
585 fprintf(mfp, " %04X ", aj);
588 fprintf(mfp, "%06o ", aj);
591 fprintf(mfp, " %05u ", aj);
594 fprintf(mfp, "%s", ptr );
596 /* NoICE output of symbol */
597 if (jflag) DefineNoICE( ptr, aj, memPage );
605 /*)Function VOID lkulist(i)
607 * int i i # 0 process LST to RST file
608 * i = 0 copy remainder of LST file
609 * to RST file and close files
611 * The function lkulist() creates a relocated listing (.rst)
612 * output file from the ASxxxx assembler listing (.lst)
613 * files. The .lst file's program address and code bytes
614 * are changed to reflect the changes made by ASlink as
615 * the .rel files are combined into a single relocated
619 * Addr_T pc current program counter address
622 * int hilo byte order
623 * int gline get a line from the LST file
624 * to translate for the RST file
625 * char rb[] read listing file text line
626 * FILE *rfp The file handle to the current
628 * int rtcnt count of data words
629 * int rtflg[] output the data flag
630 * Addr_T rtval[] relocated data
631 * FILE *tfp The file handle to the current
632 * LST file being scanned
635 * int fclose() c_library
636 * int fgets() c_library
637 * int fprintf() c_library
638 * VOID lkalist() lklist.c
639 * VOID lkglist() lklist.c
642 * A .rst file is created for each available .lst
643 * file associated with a .rel file.
653 * Exit if listing file is not open
659 * Normal processing of LST to RST
663 * Evaluate current code address
666 pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
668 pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
672 * Line with only address
678 * Line with address and code
681 for (i=2; i < rtcnt; i++) {
683 lkglist(pc++, rtval[i] & 0xFF);
689 * Copy remainder of LST to RST
693 fprintf(rfp, "%s", rb);
695 while (fgets(rb, sizeof(rb), tfp) != 0) {
696 fprintf(rfp, "%s", rb);
705 /*)Function VOID lkalist(pc)
707 * int pc current program counter value
709 * The function lkalist() performs the following functions:
711 * (1) if the value of gline = 0 then the current listing
712 * file line is copied to the relocated listing file output.
714 * (2) the listing file is read line by line and copied to
715 * the relocated listing file until a valid source
716 * line number and a program counter value of the correct
717 * radix is found. The new relocated pc value is substituted
718 * and the line is written to the RST file.
722 * char str[] temporary string
725 * int gcntr data byte counter
726 * int gline get a line from the LST file
727 * to translate for the RST file
728 * char rb[] read listing file text line
729 * char *rp pointer to listing file text line
730 * FILE *rfp The file handle to the current
732 * FILE *tfp The file handle to the current
733 * LST file being scanned
737 * int fclose() c_library
738 * int fgets() c_library
739 * int fprintf() c_library
740 * int sprintf() c_library
741 * char * strncpy() c_library
744 * Lines of the LST file are copied to the RST file,
745 * the last line copied has the code address
746 * updated to reflect the program relocation.
757 * Exit if listing file is not open
759 loop: if (tfp == NULL)
763 * Copy current LST to RST
766 fprintf(rfp, "%s", rb);
771 * Clear text line buffer
773 for (i=0,rp=rb; i<sizeof(rb); i++) {
778 * Get next LST text line
780 if (fgets(rb, sizeof(rb), tfp) == NULL) {
789 * Must have an ASxxxx Listing line number
791 if (!dgt(RAD10, &rb[30], 1)) {
792 fprintf(rfp, "%s", rb);
797 * Must have an address in the expected radix
800 if (!dgt(RAD16, &rb[3], 4)) {
801 fprintf(rfp, "%s", rb);
804 sprintf(str, "%04X", pc);
805 strncpy(&rb[3], str, 4);
808 if (!dgt(RAD10, &rb[3], 5)) {
809 fprintf(rfp, "%s", rb);
812 sprintf(str, "%05d", pc);
813 strncpy(&rb[3], str, 5);
816 if (!dgt(RAD8, &rb[3], 6)) {
817 fprintf(rfp, "%s", rb);
820 sprintf(str, "%06o", pc);
821 strncpy(&rb[3], str, 6);
825 * Copy updated LST text line to RST
827 fprintf(rfp, "%s", rb);
831 /*)Function VOID lkglist(pc,v)
833 * int pc current program counter value
834 * int v value of byte at this address
836 * The function lkglist() performs the following functions:
838 * (1) if the value of gline = 1 then the listing file
839 * is read line by line and copied to the
840 * relocated listing file until a valid source
841 * line number and a program counter value of the correct
844 * (2) The new relocated values and code address are
845 * substituted and the line may be written to the RST file.
849 * char str[] temporary string
852 * int gcntr data byte counter
853 * set to -1 for a continuation line
854 * int gline get a line from the LST file
855 * to translate for the RST file
856 * char rb[] read listing file text line
857 * char *rp pointer to listing file text line
858 * FILE *rfp The file handle to the current
860 * FILE *tfp The file handle to the current
861 * LST file being scanned
865 * int fclose() c_library
866 * int fgets() c_library
867 * int fprintf() c_library
868 * int sprintf() c_library
869 * char * strncpy() c_library
872 * Lines of the LST file are copied to the RST file
873 * with updated data values and code addresses.
885 * Exit if listing file is not open
887 loop: if (tfp == NULL)
891 * Get next LST text line
895 * Clear text line buffer
897 for (i=0,rp=rb; i<sizeof(rb); i++) {
902 * Get next LST text line
904 if (fgets(rb, sizeof(rb), tfp) == NULL) {
913 * Check for a listing line number if required
916 if (!dgt(RAD10, &rb[30], 1)) {
917 fprintf(rfp, "%s", rb);
935 rp = &rb[8 + (3 * gcntr)];
938 * Number must be of proper radix
940 if (!dgt(RAD16, rp, 2)) {
941 fprintf(rfp, "%s", rb);
946 * Output new data value, overwrite relocation codes
948 sprintf(str, " %02X", v);
949 strncpy(rp-1, str, 3);
954 * Output relocated code address
957 if (dgt(RAD16, &rb[3], 4)) {
958 sprintf(str, "%04X", pc);
959 strncpy(&rb[3], str, 4);
963 * Output text line when updates finished
966 fprintf(rfp, "%s", rb);
981 rp = &rb[9 + (3 * gcntr)];
984 * Number must be of proper radix
986 if (!dgt(RAD10, rp, 3)) {
987 fprintf(rfp, "%s", rb);
992 * Output new data value, overwrite relocation codes
994 sprintf(str, " %03d", v);
995 strncpy(rp-1, str, 4);
1000 * Output relocated code address
1003 if (dgt(RAD10, &rb[3], 5)) {
1004 sprintf(str, "%05d", pc);
1005 strncpy(&rb[3], str, 5);
1009 * Output text line when updates finished
1012 fprintf(rfp, "%s", rb);
1027 rp = &rb[10 + (3 * gcntr)];
1030 * Number must be of proper radix
1032 if (!dgt(RAD8, rp, 3)) {
1033 fprintf(rfp, "%s", rb);
1038 * Output new data value, overwrite relocation codes
1040 sprintf(str, " %03o", v);
1041 strncpy(rp-1, str, 4);
1046 * Output relocated code address
1049 if (dgt(RAD8, &rb[3], 6)) {
1050 sprintf(str, "%06o", pc);
1051 strncpy(&rb[3], str, 6);
1055 * Output text line when updates finished
1058 fprintf(rfp, "%s", rb);
1065 /*)Function int dgt(rdx,str,n)
1067 * int rdx radix bit code
1068 * char *str pointer to the test string
1069 * int n number of characters to check
1071 * The function dgt() verifies that the string under test
1072 * is of the specified radix.
1075 * int i loop counter
1078 * ctype[] array of character types
1094 for (i=0; i<n; i++) {
1095 if ((ctype[(int)*str++] & rdx) == 0)