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 * char * ptr pointer to an id string
156 * int nmsym number of symbols in area
157 * Addr_T ai temporary
158 * Addr_T aj temporary
159 * sym * sp pointer to a symbol structure
160 * sym ** p pointer to an array of
161 * pointers to symbol structures
164 * FILE *mfp Map output file handle
165 * sym *symhash[NHASH] array of pointers to NHASH
166 * linked symbol lists
167 * int xflag Map file radix type flag
170 * int fprintf() c_library
171 * VOID free() c_library
172 * char * malloc() c_library
173 * char putc() c_library
174 * VOID slew() lklist.c
177 * Map output generated.
181 lstarea(struct area *xp)
183 register struct areax *oxp;
195 * Find number of symbols in area
200 for (i=0; i<NHASH; i++) {
203 if (oxp == sp->s_axp)
215 fprintf(mfp, "Hexadecimal\n\n");
218 fprintf(mfp, "Octal\n\n");
221 fprintf(mfp, "Decimal\n\n");
223 fprintf(mfp, "Area ");
224 fprintf(mfp, "Addr Size Decimal %s (Attributes)\n",
225 (xp->a_flag & A_BIT)?"Bits ":"Bytes");/* JCF: For BIT print bits...*/
226 fprintf(mfp, "-------------------------------- ");
227 fprintf(mfp, "---- ---- ------- ----- ------------\n");
232 fprintf(mfp, "%-32s", ptr ); /* JLH: width matches --- above */
236 fprintf(mfp, " %04X %04X", ai, aj);
239 fprintf(mfp, " %06o %06o", ai, aj);
242 fprintf(mfp, " %05u %05u", ai, aj);
244 fprintf(mfp, " = %6u. %s ", aj,
245 (xp->a_flag & A_BIT)?"bits ":"bytes"); /* JCF: For BIT print bits...*/
246 if (xp->a_flag & A_ABS) {
247 fprintf(mfp, "(ABS");
249 fprintf(mfp, "(REL");
251 if (xp->a_flag & A_OVR) {
252 fprintf(mfp, ",OVR");
254 fprintf(mfp, ",CON");
256 if (xp->a_flag & A_PAG) {
257 fprintf(mfp, ",PAG");
261 if (xp->a_flag & A_CODE) {
262 fprintf(mfp, ",CODE");
265 if (xp->a_flag & A_XDATA) {
266 fprintf(mfp, ",XDATA");
269 if (xp->a_flag & A_BIT) {
270 fprintf(mfp, ",BIT");
274 if (xp->a_flag & A_PAG) {
277 if (ai || aj) { fprintf(mfp, " "); }
278 if (ai) { fprintf(mfp, " Boundary"); }
279 if (ai & aj) { fprintf(mfp, " /"); }
280 if (aj) { fprintf(mfp, " Length"); }
281 if (ai || aj) { fprintf(mfp, " Error"); }
285 * Allocate space for an array of pointers to symbols
288 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
290 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
296 for (i=0; i<NHASH; i++) {
299 if (oxp == sp->s_axp) {
308 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
311 * Symbol Table Output
315 fprintf(mfp, "\n\n");
316 fprintf(mfp, " Value Global\n");
317 fprintf(mfp, " -------- --------------------------------");
321 fprintf(mfp, " %02X:", memPage);
326 aj = sp->s_addr + sp->s_axp->a_addr;
328 fprintf(mfp, "%04X ", aj);
331 fprintf(mfp, "%06o ", aj);
334 fprintf(mfp, "%05u ", aj);
337 fprintf(mfp, "%s", ptr );
339 /* if cdb flag set the output cdb Information
340 and the symbol has a '$' sign in it then */
343 fprintf(dfp,"L:%s:%X\n",ptr,aj);
345 /* NoICE output of symbol */
346 if (jflag) DefineNoICE( ptr, aj, memPage );
357 /*)Function VOID lstarea(xp)
359 * area * xp pointer to an area structure
361 * The function lstarea() creates the linker map output for
362 * the area specified by pointer xp. The generated output
363 * area header includes the area name, starting address,
364 * size of area, number of words (in decimal), and the
365 * area attributes. The symbols defined in this area are
366 * sorted by ascending address and output four per line
367 * in the selected radix.
370 * areax * oxp pointer to an area extension structure
371 * int c character value
373 * char * ptr pointer to an id string
374 * int nmsym number of symbols in area
375 * Addr_T ai temporary
376 * Addr_T aj temporary
377 * sym * sp pointer to a symbol structure
378 * sym ** p pointer to an array of
379 * pointers to symbol structures
382 * FILE *mfp Map output file handle
383 * sym *symhash[NHASH] array of pointers to NHASH
384 * linked symbol lists
385 * int xflag Map file radix type flag
388 * int fprintf() c_library
389 * VOID free() c_library
390 * char * malloc() c_library
391 * char putc() c_library
392 * VOID slew() lklist.c
395 * Map output generated.
399 lstarea(struct area *xp)
401 register struct areax *oxp;
416 while (ptr < &xp->a_id[NCPS]) {
417 if ((c = *ptr++) != 0) {
426 fprintf(mfp, " %04X %04X", ai, aj);
429 fprintf(mfp, " %06o %06o", ai, aj);
432 fprintf(mfp, " %05u %05u", ai, aj);
434 fprintf(mfp, " = %6u. bytes ", aj);
435 if (xp->a_flag & A_ABS) {
436 fprintf(mfp, "(ABS");
438 fprintf(mfp, "(REL");
440 if (xp->a_flag & A_OVR) {
441 fprintf(mfp, ",OVR");
443 fprintf(mfp, ",CON");
445 if (xp->a_flag & A_PAG) {
446 fprintf(mfp, ",PAG");
450 if (xp->a_flag & A_CODE) {
451 fprintf(mfp, ",CODE");
454 if (xp->a_flag & A_XDATA) {
455 fprintf(mfp, ",XDATA");
458 if (xp->a_flag & A_BIT) {
459 fprintf(mfp, ",BIT");
463 if (xp->a_flag & A_PAG) {
466 if (ai || aj) { fprintf(mfp, " "); }
467 if (ai) { fprintf(mfp, " Boundary"); }
468 if (ai & aj) { fprintf(mfp, " /"); }
469 if (aj) { fprintf(mfp, " Length"); }
470 if (ai || aj) { fprintf(mfp, " Error"); }
474 * Find number of symbols in area
479 for (i=0; i<NHASH; i++) {
482 if (oxp == sp->s_axp)
496 * Allocate space for an array of pointers to symbols
499 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
501 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
508 for (i=0; i<NHASH; i++) {
511 if (oxp == sp->s_axp) {
520 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
523 * Symbol Table Output
531 aj = sp->s_addr + sp->s_axp->a_addr;
533 fprintf(mfp, " %04X ", aj);
536 fprintf(mfp, "%06o ", aj);
539 fprintf(mfp, " %05u ", aj);
542 fprintf(mfp, "%*s", NCPS, ptr );
544 /* NoICE output of symbol */
545 if (jflag) DefineNoICE( ptr, aj, memPage );
554 VOID lstareatosym(struct area *xp)
556 /* Output the current area symbols to a NO$GMB .sym file */
557 register struct areax *oxp;
565 * Find number of symbols in area
570 for (i=0; i<NHASH; i++) {
573 if (oxp == sp->s_axp)
582 * Symbol Table Output
584 if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
585 /* Dont worry about any area information */
586 fprintf(mfp, "; Area: %s\n", xp->a_id );
589 * Allocate space for an array of pointers to symbols
592 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
594 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
600 for (i=0; i<NHASH; i++) {
603 if (oxp == sp->s_axp) {
612 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
616 /* no$gmb requires the symbol names to be less than 32 chars long. Truncate. */
618 strncpy(name, p[i]->s_id, 31);
620 if ((strncmp("l__", name, 3)!=0)&&(strchr(name,' ')==NULL)) {
621 a0=p[i]->s_addr + p[i]->s_axp->a_addr;
623 /* Not inside the ROM, so treat as being in bank zero */
624 fprintf(mfp, "00:%04X %s\n", a0, name);
627 fprintf(mfp, "%02X:%04X %s\n", a0/16384, a0, name);
638 /*)Function VOID lkulist(i)
640 * int i i # 0 process LST to RST file
641 * i = 0 copy remainder of LST file
642 * to RST file and close files
644 * The function lkulist() creates a relocated listing (.rst)
645 * output file from the ASxxxx assembler listing (.lst)
646 * files. The .lst file's program address and code bytes
647 * are changed to reflect the changes made by ASlink as
648 * the .rel files are combined into a single relocated
652 * Addr_T pc current program counter address
655 * int hilo byte order
656 * int gline get a line from the LST file
657 * to translate for the RST file
658 * char rb[] read listing file text line
659 * FILE *rfp The file handle to the current
661 * int rtcnt count of data words
662 * int rtflg[] output the data flag
663 * Addr_T rtval[] relocated data
664 * FILE *tfp The file handle to the current
665 * LST file being scanned
668 * int fclose() c_library
669 * int fgets() c_library
670 * int fprintf() c_library
671 * VOID lkalist() lklist.c
672 * VOID lkglist() lklist.c
675 * A .rst file is created for each available .lst
676 * file associated with a .rel file.
685 * Exit if listing file is not open
691 * Normal processing of LST to RST
695 * Evaluate current code address
698 pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
700 pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
704 * Line with only address
710 * Line with address and code
713 for (i=2; i < rtcnt; i++) {
715 lkglist(pc++, rtval[i] & 0xFF);
721 * Copy remainder of LST to RST
725 fprintf(rfp, "%s", rb);
727 while (fgets(rb, sizeof(rb), tfp) != 0) {
728 fprintf(rfp, "%s", rb);
737 /*)Function VOID lkalist(pc)
739 * int pc current program counter value
741 * The function lkalist() performs the following functions:
743 * (1) if the value of gline = 0 then the current listing
744 * file line is copied to the relocated listing file output.
746 * (2) the listing file is read line by line and copied to
747 * the relocated listing file until a valid source
748 * line number and a program counter value of the correct
749 * radix is found. The new relocated pc value is substituted
750 * and the line is written to the RST file.
754 * char str[] temporary string
757 * int gcntr data byte counter
758 * int gline get a line from the LST file
759 * to translate for the RST file
760 * char rb[] read listing file text line
761 * char *rp pointer to listing file text line
762 * FILE *rfp The file handle to the current
764 * FILE *tfp The file handle to the current
765 * LST file being scanned
769 * int fclose() c_library
770 * int fgets() c_library
771 * int fprintf() c_library
772 * int sprintf() c_library
773 * char * strncpy() c_library
776 * Lines of the LST file are copied to the RST file,
777 * the last line copied has the code address
778 * updated to reflect the program relocation.
788 * Exit if listing file is not open
790 loop: if (tfp == NULL)
794 * Copy current LST to RST
797 fprintf(rfp, "%s", rb);
802 * Clear text line buffer
804 for (i=0,rp=rb; i<sizeof(rb); i++) {
809 * Get next LST text line
811 if (fgets(rb, sizeof(rb), tfp) == NULL) {
820 * Must have an ASxxxx Listing line number
822 if (!dgt(RAD10, &rb[30], 1)) {
823 fprintf(rfp, "%s", rb);
828 * Must have an address in the expected radix
831 if (!dgt(RAD16, &rb[3], 4)) {
832 fprintf(rfp, "%s", rb);
835 sprintf(str, "%04X", pc);
836 strncpy(&rb[3], str, 4);
839 if (!dgt(RAD10, &rb[3], 5)) {
840 fprintf(rfp, "%s", rb);
843 sprintf(str, "%05d", pc);
844 strncpy(&rb[3], str, 5);
847 if (!dgt(RAD8, &rb[3], 6)) {
848 fprintf(rfp, "%s", rb);
851 sprintf(str, "%06o", pc);
852 strncpy(&rb[3], str, 6);
856 * Copy updated LST text line to RST
858 fprintf(rfp, "%s", rb);
862 /*)Function VOID lkglist(pc,v)
864 * int pc current program counter value
865 * int v value of byte at this address
867 * The function lkglist() performs the following functions:
869 * (1) if the value of gline = 1 then the listing file
870 * is read line by line and copied to the
871 * relocated listing file until a valid source
872 * line number and a program counter value of the correct
875 * (2) The new relocated values and code address are
876 * substituted and the line may be written to the RST file.
880 * char str[] temporary string
883 * int gcntr data byte counter
884 * set to -1 for a continuation line
885 * int gline get a line from the LST file
886 * to translate for the RST file
887 * char rb[] read listing file text line
888 * char *rp pointer to listing file text line
889 * FILE *rfp The file handle to the current
891 * FILE *tfp The file handle to the current
892 * LST file being scanned
896 * int fclose() c_library
897 * int fgets() c_library
898 * int fprintf() c_library
899 * int sprintf() c_library
900 * char * strncpy() c_library
903 * Lines of the LST file are copied to the RST file
904 * with updated data values and code addresses.
908 lkglist(Addr_T pc, int v)
914 * Exit if listing file is not open
916 loop: if (tfp == NULL)
920 * Get next LST text line
924 * Clear text line buffer
926 for (i=0,rp=rb; i<sizeof(rb); i++) {
931 * Get next LST text line
933 if (fgets(rb, sizeof(rb), tfp) == NULL) {
942 * Check for a listing line number if required
945 if (!dgt(RAD10, &rb[30], 1)) {
946 fprintf(rfp, "%s", rb);
964 rp = &rb[8 + (3 * gcntr)];
967 * Number must be of proper radix
969 if (!dgt(RAD16, rp, 2)) {
970 fprintf(rfp, "%s", rb);
975 * Output new data value, overwrite relocation codes
977 sprintf(str, " %02X", v);
978 strncpy(rp-1, str, 3);
983 * Output relocated code address
986 if (dgt(RAD16, &rb[3], 4)) {
987 sprintf(str, "%04X", pc);
988 strncpy(&rb[3], str, 4);
992 * Output text line when updates finished
995 fprintf(rfp, "%s", rb);
1010 rp = &rb[9 + (3 * gcntr)];
1013 * Number must be of proper radix
1015 if (!dgt(RAD10, rp, 3)) {
1016 fprintf(rfp, "%s", rb);
1021 * Output new data value, overwrite relocation codes
1023 sprintf(str, " %03d", v);
1024 strncpy(rp-1, str, 4);
1029 * Output relocated code address
1032 if (dgt(RAD10, &rb[3], 5)) {
1033 sprintf(str, "%05d", pc);
1034 strncpy(&rb[3], str, 5);
1038 * Output text line when updates finished
1041 fprintf(rfp, "%s", rb);
1056 rp = &rb[10 + (3 * gcntr)];
1059 * Number must be of proper radix
1061 if (!dgt(RAD8, rp, 3)) {
1062 fprintf(rfp, "%s", rb);
1067 * Output new data value, overwrite relocation codes
1069 sprintf(str, " %03o", v);
1070 strncpy(rp-1, str, 4);
1075 * Output relocated code address
1078 if (dgt(RAD8, &rb[3], 6)) {
1079 sprintf(str, "%06o", pc);
1080 strncpy(&rb[3], str, 6);
1084 * Output text line when updates finished
1087 fprintf(rfp, "%s", rb);
1094 /*)Function int dgt(rdx,str,n)
1096 * int rdx radix bit code
1097 * char *str pointer to the test string
1098 * int n number of characters to check
1100 * The function dgt() verifies that the string under test
1101 * is of the specified radix.
1104 * int i loop counter
1107 * ctype[] array of character types
1117 dgt(int rdx, char *str, int n)
1121 for (i=0; i<n; i++) {
1122 if ((ctype[(unsigned char)(*str++)] & rdx) == 0)