3 Copyright (C) 1989-1995 Alan R. Baldwin
4 721 Berkeley St., Kent, Ohio 44240
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 * - lstarea: show s_id as string rather than array [NCPS]
22 * - lstarea: show a_id as string rather than array [NCPS]
23 * 31-Oct-97 JLH: add NoICE output file genration in lstarea
24 * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output
34 * The module lklist.c contains the functions which
35 * output the linker .map file and produce a relocated
38 * lklist.c contains the following functions:
47 * lklist.c contains no local variables.
50 /*)Function VOID slew(fp)
52 * FILE * fp output file handle
54 * The function slew() increments the page line counter.
55 * If the number of lines exceeds the maximum number of
56 * lines per page then a page skip and a page header are
63 * int lop current line number on page
64 * int xflag Map file radix type flag
67 * int fprintf() c_library
68 * VOID newpag() lklist.c
71 * The page line and the page count may be updated.
83 fprintf(fp, "Hexadecimal\n\n");
86 fprintf(fp, "Octal\n\n");
89 fprintf(fp, "Decimal\n\n");
91 fprintf(fp, "Area Addr Size");
92 fprintf(fp, " Decimal Bytes (Attributes)\n");
94 fprintf(fp, " Value--Global");
100 /*)Function VOID newpag()
102 * The function newpag() outputs a page skip, writes the
103 * first page header line, sets the line count to 1, and
104 * increments the page counter.
110 * int lop current line number on page
111 * int page current page number
114 * int fprintf() c_library
117 * The page and line counters are updated.
124 fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page);
128 /* Used for qsort call in lstsym */
129 static int _cmpSymByAddr(const void *p1, const void *p2)
131 struct sym **s1 = (struct sym **)(p1);
132 struct sym **s2 = (struct sym **)(p2);
133 int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
134 ((*s2)->s_addr + (*s2)->s_axp->a_addr);
136 /* Sort first by address, then by name. */
141 return strcmp((*s1)->s_id,(*s2)->s_id);
148 /*)Function VOID lstarea(xp)
150 * area * xp pointer to an area structure
152 * The function lstarea() creates the linker map output for
153 * the area specified by pointer xp. The generated output
154 * area header includes the area name, starting address,
155 * size of area, number of words (in decimal), and the
156 * area attributes. The symbols defined in this area are
157 * sorted by ascending address and output one per line
158 * in the selected radix.
161 * areax * oxp pointer to an area extension structure
162 * int c character value
164 * char * ptr pointer to an id string
165 * int nmsym number of symbols in area
166 * Addr_T ai temporary
167 * Addr_T aj temporary
168 * sym * sp pointer to a symbol structure
169 * sym ** p pointer to an array of
170 * pointers to symbol structures
173 * FILE *mfp Map output file handle
174 * sym *symhash[NHASH] array of pointers to NHASH
175 * linked symbol lists
176 * int xflag Map file radix type flag
179 * int fprintf() c_library
180 * VOID free() c_library
181 * char * malloc() c_library
182 * char putc() c_library
183 * VOID slew() lklist.c
186 * Map output generated.
190 lstarea(struct area *xp)
192 register struct areax *oxp;
204 * Find number of symbols in area
209 for (i=0; i<NHASH; i++) {
212 if (oxp == sp->s_axp)
224 fprintf(mfp, "Hexadecimal\n\n");
227 fprintf(mfp, "Octal\n\n");
230 fprintf(mfp, "Decimal\n\n");
232 fprintf(mfp, "Area ");
233 fprintf(mfp, "Addr Size Decimal %s (Attributes)\n",
234 (xp->a_flag & A_BIT)?"Bits ":"Bytes");/* JCF: For BIT print bits...*/
235 fprintf(mfp, "-------------------------------- ");
236 fprintf(mfp, "---- ---- ------- ----- ------------\n");
241 fprintf(mfp, "%-32s", ptr ); /* JLH: width matches --- above */
245 fprintf(mfp, " %04X %04X", ai, aj);
248 fprintf(mfp, " %06o %06o", ai, aj);
251 fprintf(mfp, " %05u %05u", ai, aj);
253 fprintf(mfp, " = %6u. %s ", aj,
254 (xp->a_flag & A_BIT)?"bits ":"bytes"); /* JCF: For BIT print bits...*/
255 if (xp->a_flag & A_ABS) {
256 fprintf(mfp, "(ABS");
258 fprintf(mfp, "(REL");
260 if (xp->a_flag & A_OVR) {
261 fprintf(mfp, ",OVR");
263 fprintf(mfp, ",CON");
265 if (xp->a_flag & A_PAG) {
266 fprintf(mfp, ",PAG");
270 if (xp->a_flag & A_CODE) {
271 fprintf(mfp, ",CODE");
274 if (xp->a_flag & A_XDATA) {
275 fprintf(mfp, ",XDATA");
278 if (xp->a_flag & A_BIT) {
279 fprintf(mfp, ",BIT");
283 if (xp->a_flag & A_PAG) {
286 if (ai || aj) { fprintf(mfp, " "); }
287 if (ai) { fprintf(mfp, " Boundary"); }
288 if (ai & aj) { fprintf(mfp, " /"); }
289 if (aj) { fprintf(mfp, " Length"); }
290 if (ai || aj) { fprintf(mfp, " Error"); }
294 * Allocate space for an array of pointers to symbols
297 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
299 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
305 for (i=0; i<NHASH; i++) {
308 if (oxp == sp->s_axp) {
317 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
320 * Symbol Table Output
324 fprintf(mfp, "\n\n");
325 fprintf(mfp, " Value Global\n");
326 fprintf(mfp, " -------- --------------------------------");
330 fprintf(mfp, " %02X:", memPage);
335 aj = sp->s_addr + sp->s_axp->a_addr;
337 fprintf(mfp, "%04X ", aj);
340 fprintf(mfp, "%06o ", aj);
343 fprintf(mfp, "%05u ", aj);
346 fprintf(mfp, "%s", ptr );
348 /* if cdb flag set the output cdb Information
349 and the symbol has a '$' sign in it then */
352 fprintf(dfp,"L:%s:%X\n",ptr,aj);
354 /* NoICE output of symbol */
355 if (jflag) DefineNoICE( ptr, aj, memPage );
366 /*)Function VOID lstarea(xp)
368 * area * xp pointer to an area structure
370 * The function lstarea() creates the linker map output for
371 * the area specified by pointer xp. The generated output
372 * area header includes the area name, starting address,
373 * size of area, number of words (in decimal), and the
374 * area attributes. The symbols defined in this area are
375 * sorted by ascending address and output four per line
376 * in the selected radix.
379 * areax * oxp pointer to an area extension structure
380 * int c character value
382 * char * ptr pointer to an id string
383 * int nmsym number of symbols in area
384 * Addr_T ai temporary
385 * Addr_T aj temporary
386 * sym * sp pointer to a symbol structure
387 * sym ** p pointer to an array of
388 * pointers to symbol structures
391 * FILE *mfp Map output file handle
392 * sym *symhash[NHASH] array of pointers to NHASH
393 * linked symbol lists
394 * int xflag Map file radix type flag
397 * int fprintf() c_library
398 * VOID free() c_library
399 * char * malloc() c_library
400 * char putc() c_library
401 * VOID slew() lklist.c
404 * Map output generated.
408 lstarea(struct area *xp)
410 register struct areax *oxp;
425 while (ptr < &xp->a_id[NCPS]) {
426 if ((c = *ptr++) != 0) {
435 fprintf(mfp, " %04X %04X", ai, aj);
438 fprintf(mfp, " %06o %06o", ai, aj);
441 fprintf(mfp, " %05u %05u", ai, aj);
443 fprintf(mfp, " = %6u. bytes ", aj);
444 if (xp->a_flag & A_ABS) {
445 fprintf(mfp, "(ABS");
447 fprintf(mfp, "(REL");
449 if (xp->a_flag & A_OVR) {
450 fprintf(mfp, ",OVR");
452 fprintf(mfp, ",CON");
454 if (xp->a_flag & A_PAG) {
455 fprintf(mfp, ",PAG");
459 if (xp->a_flag & A_CODE) {
460 fprintf(mfp, ",CODE");
463 if (xp->a_flag & A_XDATA) {
464 fprintf(mfp, ",XDATA");
467 if (xp->a_flag & A_BIT) {
468 fprintf(mfp, ",BIT");
472 if (xp->a_flag & A_PAG) {
475 if (ai || aj) { fprintf(mfp, " "); }
476 if (ai) { fprintf(mfp, " Boundary"); }
477 if (ai & aj) { fprintf(mfp, " /"); }
478 if (aj) { fprintf(mfp, " Length"); }
479 if (ai || aj) { fprintf(mfp, " Error"); }
483 * Find number of symbols in area
488 for (i=0; i<NHASH; i++) {
491 if (oxp == sp->s_axp)
505 * Allocate space for an array of pointers to symbols
508 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
510 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
517 for (i=0; i<NHASH; i++) {
520 if (oxp == sp->s_axp) {
529 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
532 * Symbol Table Output
540 aj = sp->s_addr + sp->s_axp->a_addr;
542 fprintf(mfp, " %04X ", aj);
545 fprintf(mfp, "%06o ", aj);
548 fprintf(mfp, " %05u ", aj);
551 fprintf(mfp, "%*s", NCPS, ptr );
553 /* NoICE output of symbol */
554 if (jflag) DefineNoICE( ptr, aj, memPage );
563 VOID lstareatosym(struct area *xp)
565 /* Output the current area symbols to a NO$GMB .sym file */
566 register struct areax *oxp;
574 * Find number of symbols in area
579 for (i=0; i<NHASH; i++) {
582 if (oxp == sp->s_axp)
591 * Symbol Table Output
593 if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
594 /* Dont worry about any area information */
595 fprintf(mfp, "; Area: %s\n", xp->a_id );
598 * Allocate space for an array of pointers to symbols
601 if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
603 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
609 for (i=0; i<NHASH; i++) {
612 if (oxp == sp->s_axp) {
621 qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
625 /* no$gmb requires the symbol names to be less than 32 chars long. Truncate. */
627 strncpy(name, p[i]->s_id, 31);
629 if ((strncmp("l__", name, 3)!=0)&&(strchr(name,' ')==NULL)) {
630 a0=p[i]->s_addr + p[i]->s_axp->a_addr;
632 /* Not inside the ROM, so treat as being in bank zero */
633 fprintf(mfp, "00:%04X %s\n", a0, name);
636 fprintf(mfp, "%02X:%04X %s\n", a0/16384, a0, name);
647 /*)Function VOID lkulist(i)
649 * int i i # 0 process LST to RST file
650 * i = 0 copy remainder of LST file
651 * to RST file and close files
653 * The function lkulist() creates a relocated listing (.rst)
654 * output file from the ASxxxx assembler listing (.lst)
655 * files. The .lst file's program address and code bytes
656 * are changed to reflect the changes made by ASlink as
657 * the .rel files are combined into a single relocated
661 * Addr_T pc current program counter address
664 * int hilo byte order
665 * int gline get a line from the LST file
666 * to translate for the RST file
667 * char rb[] read listing file text line
668 * FILE *rfp The file handle to the current
670 * int rtcnt count of data words
671 * int rtflg[] output the data flag
672 * Addr_T rtval[] relocated data
673 * FILE *tfp The file handle to the current
674 * LST file being scanned
677 * int fclose() c_library
678 * int fgets() c_library
679 * int fprintf() c_library
680 * VOID lkalist() lklist.c
681 * VOID lkglist() lklist.c
684 * A .rst file is created for each available .lst
685 * file associated with a .rel file.
694 * Exit if listing file is not open
700 * Normal processing of LST to RST
704 * Evaluate current code address
707 pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
709 pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
713 * Line with only address
719 * Line with address and code
722 for (i=2; i < rtcnt; i++) {
724 lkglist(pc++, rtval[i] & 0xFF);
730 * Copy remainder of LST to RST
734 fprintf(rfp, "%s", rb);
736 while (fgets(rb, sizeof(rb), tfp) != 0) {
737 fprintf(rfp, "%s", rb);
746 /*)Function VOID lkalist(pc)
748 * int pc current program counter value
750 * The function lkalist() performs the following functions:
752 * (1) if the value of gline = 0 then the current listing
753 * file line is copied to the relocated listing file output.
755 * (2) the listing file is read line by line and copied to
756 * the relocated listing file until a valid source
757 * line number and a program counter value of the correct
758 * radix is found. The new relocated pc value is substituted
759 * and the line is written to the RST file.
763 * char str[] temporary string
766 * int gcntr data byte counter
767 * int gline get a line from the LST file
768 * to translate for the RST file
769 * char rb[] read listing file text line
770 * char *rp pointer to listing file text line
771 * FILE *rfp The file handle to the current
773 * FILE *tfp The file handle to the current
774 * LST file being scanned
778 * int fclose() c_library
779 * int fgets() c_library
780 * int fprintf() c_library
781 * int sprintf() c_library
782 * char * strncpy() c_library
785 * Lines of the LST file are copied to the RST file,
786 * the last line copied has the code address
787 * updated to reflect the program relocation.
797 * Exit if listing file is not open
799 loop: if (tfp == NULL)
803 * Copy current LST to RST
806 fprintf(rfp, "%s", rb);
811 * Clear text line buffer
813 for (i=0,rp=rb; i<sizeof(rb); i++) {
818 * Get next LST text line
820 if (fgets(rb, sizeof(rb), tfp) == NULL) {
829 * Must have an ASxxxx Listing line number
831 if (!dgt(RAD10, &rb[30], 1)) {
832 fprintf(rfp, "%s", rb);
837 * Must have an address in the expected radix
840 if (!dgt(RAD16, &rb[3], 4)) {
841 fprintf(rfp, "%s", rb);
844 sprintf(str, "%04X", pc);
845 strncpy(&rb[3], str, 4);
848 if (!dgt(RAD10, &rb[3], 5)) {
849 fprintf(rfp, "%s", rb);
852 sprintf(str, "%05d", pc);
853 strncpy(&rb[3], str, 5);
856 if (!dgt(RAD8, &rb[3], 6)) {
857 fprintf(rfp, "%s", rb);
860 sprintf(str, "%06o", pc);
861 strncpy(&rb[3], str, 6);
865 * Copy updated LST text line to RST
867 fprintf(rfp, "%s", rb);
871 /*)Function VOID lkglist(pc,v)
873 * int pc current program counter value
874 * int v value of byte at this address
876 * The function lkglist() performs the following functions:
878 * (1) if the value of gline = 1 then the listing file
879 * is read line by line and copied to the
880 * relocated listing file until a valid source
881 * line number and a program counter value of the correct
884 * (2) The new relocated values and code address are
885 * substituted and the line may be written to the RST file.
889 * char str[] temporary string
892 * int gcntr data byte counter
893 * set to -1 for a continuation line
894 * int gline get a line from the LST file
895 * to translate for the RST file
896 * char rb[] read listing file text line
897 * char *rp pointer to listing file text line
898 * FILE *rfp The file handle to the current
900 * FILE *tfp The file handle to the current
901 * LST file being scanned
905 * int fclose() c_library
906 * int fgets() c_library
907 * int fprintf() c_library
908 * int sprintf() c_library
909 * char * strncpy() c_library
912 * Lines of the LST file are copied to the RST file
913 * with updated data values and code addresses.
917 lkglist(Addr_T pc, int v)
923 * Exit if listing file is not open
925 loop: if (tfp == NULL)
929 * Get next LST text line
933 * Clear text line buffer
935 for (i=0,rp=rb; i<sizeof(rb); i++) {
940 * Get next LST text line
942 if (fgets(rb, sizeof(rb), tfp) == NULL) {
951 * Check for a listing line number if required
954 if (!dgt(RAD10, &rb[30], 1)) {
955 fprintf(rfp, "%s", rb);
973 rp = &rb[8 + (3 * gcntr)];
976 * Number must be of proper radix
978 if (!dgt(RAD16, rp, 2)) {
979 fprintf(rfp, "%s", rb);
984 * Output new data value, overwrite relocation codes
986 sprintf(str, " %02X", v);
987 strncpy(rp-1, str, 3);
992 * Output relocated code address
995 if (dgt(RAD16, &rb[3], 4)) {
996 sprintf(str, "%04X", pc);
997 strncpy(&rb[3], str, 4);
1001 * Output text line when updates finished
1004 fprintf(rfp, "%s", rb);
1019 rp = &rb[9 + (3 * gcntr)];
1022 * Number must be of proper radix
1024 if (!dgt(RAD10, rp, 3)) {
1025 fprintf(rfp, "%s", rb);
1030 * Output new data value, overwrite relocation codes
1032 sprintf(str, " %03d", v);
1033 strncpy(rp-1, str, 4);
1038 * Output relocated code address
1041 if (dgt(RAD10, &rb[3], 5)) {
1042 sprintf(str, "%05d", pc);
1043 strncpy(&rb[3], str, 5);
1047 * Output text line when updates finished
1050 fprintf(rfp, "%s", rb);
1065 rp = &rb[10 + (3 * gcntr)];
1068 * Number must be of proper radix
1070 if (!dgt(RAD8, rp, 3)) {
1071 fprintf(rfp, "%s", rb);
1076 * Output new data value, overwrite relocation codes
1078 sprintf(str, " %03o", v);
1079 strncpy(rp-1, str, 4);
1084 * Output relocated code address
1087 if (dgt(RAD8, &rb[3], 6)) {
1088 sprintf(str, "%06o", pc);
1089 strncpy(&rb[3], str, 6);
1093 * Output text line when updates finished
1096 fprintf(rfp, "%s", rb);
1103 /*)Function int dgt(rdx,str,n)
1105 * int rdx radix bit code
1106 * char *str pointer to the test string
1107 * int n number of characters to check
1109 * The function dgt() verifies that the string under test
1110 * is of the specified radix.
1113 * int i loop counter
1116 * ctype[] array of character types
1126 dgt(int rdx, char *str, int n)
1130 for (i=0; i<n; i++) {
1131 if ((ctype[(unsigned char)(*str++)] & rdx) == 0)