#include /* Types and constants */ #include /* More of the same */ #include /* More of the same */ #include /* Linker I/O definitions */ #include /* Error messages */ #include /* External declarations */ RBTYPE rhteBlank; RBTYPE rhteBc_vars; RBTYPE rhteFarData; RBTYPE rhteFarBss; SEGTYPE segFD1st; SEGTYPE segFDLast; SEGTYPE segFB1st; SEGTYPE segFBLast; SNTYPE gsnComBl; SEGTYPE segQCode; LOCAL RBTYPE *psymrb; /* pointer to table of sym addr's */ LOCAL WORD symCodeMac; /* # of code symbols */ LOCAL RATYPE raNames; /* offset into $name_list */ LOCAL RATYPE raQbSym; /* offset into SYMBOL segment */ LOCAL SEGTYPE segQbSym; /* segment number of SYMBOL segment */ LOCAL WORD symQbMac; /* count of all symbols */ LOCAL RBTYPE rbQbstart; /* Property address of __aulstart */ #define CBQBHDR sizeof(QBHDRTYPE) #define CBSYMENTRY (4*sizeof(WORD)) #define QBTYP_CODE 1 /* code symbol */ #define QBTYP_DATA 2 /* data symbol */ #define QBTYP_SEG 3 /* segment symbol */ #define QBTYP_BCSEG 4 /* class BC_VARS, or name COMMON * and class BLANK */ #define QBTYP_ABS 5 /* absolute symbol */ #define QBMAGIC 0x6c75 /* "ul" */ #define JMPFAR 0xea /* JMP FAR */ #define QB_RACODELST CBQBHDR #define QBVER 2 /* QB symbol table header */ typedef struct qbhdr { BYTE jmpstart[5]; /* JMP FAR __aulstart */ BYTE version; /* version number */ WORD magic; /* Magic word */ WORD raCodeLst; /* Start of code symbols */ WORD raDataLst; /* Start of data symbols */ WORD raSegLst; /* Start of segment symbols */ WORD saCode; /* Segment addr of seg _CODE */ WORD saData; /* Segment addr of seg DGROUP */ WORD saSymbol; /* Segment addr of seg SYMBOL (us) */ WORD cbSymbol; /* Size of seg SYMBOL */ WORD saFarData; /* Segment addr of 1st 'FAR_DATA' seg */ long cbFarData; /* Total size of 'FAR_DATA' segs */ WORD saFarBss; /* Segment addr of 1st 'FAR_BSS' seg */ long cbFarBss; /* Total size of 'FAR_BSS' segs */ } QBHDRTYPE; /* Offsets into qbhdr */ #define QH_SAQBSTART 3 /* Segment part of __aulstart */ #define QH_SACODE 14 /* saCode */ #define QH_SADATA 16 /* saData */ #define QH_SASYMBOL 18 /* saSymbol */ #define QH_SAFARDATA 22 /* saFarData */ #define QH_SAFARBSS 28 /* saFarBss */ typedef struct qbsym { WORD flags; /* symbol type (code, data, segment) */ WORD raName; /* offset into name_list */ WORD ra; /* symbol address offset */ SATYPE sa; /* symbol address segment base */ } QBSYMTYPE; /* * LOCAL FUNCTION PROTOTYPES */ LOCAL void QbSaveSym(APROPNAMEPTR prop, RBTYPE rhte, RBTYPE rprop, WORD fNewHte); LOCAL void NEAR MoveToQbSym(unsigned short cb,void *pData); LOCAL void NEAR BldQbHdr(void); LOCAL void NEAR QbAddName(AHTEPTR ahte); LOCAL void NEAR BldSegSym(unsigned short gsn); LOCAL void NEAR BldSym(void FAR *prop); /* * Initializes items for Quick Basic symbol table. */ void NEAR InitQbLib () { SBTYPE sb; /* String buffer */ BYTE *psbRunfile; /* Name of runfile */ #if OVERLAYS /* If overlays are specified, issue fatal error. */ if(fOverlays) Fatal(ER_swbadovl, "/QUICKLIB"); #endif PropSymLookup("\005BLANK",ATTRNIL,TRUE); rhteBlank = vrhte; PropSymLookup("\007BC_VARS",ATTRNIL,TRUE); rhteBc_vars = vrhte; PropSymLookup("\012__aulstart",ATTRUND,TRUE); rbQbstart = vrprop; PropSymLookup("\010FAR_DATA",ATTRNIL,TRUE); rhteFarData = vrhte; PropSymLookup("\007FAR_BSS",ATTRNIL,TRUE); rhteFarBss = vrhte; /* Assign default runfile extension, as appropriate. * First, make sb contain .QLB updated with user-supplied * name and extension, if any. */ memcpy(sb,sbDotQlb,sizeof(sbDotQlb)); UpdateFileParts(sb,bufg); /* Next, get the name of the runfile and update it with sb. */ psbRunfile = GetFarSb(((AHTEPTR) FetchSym(rhteRunfile,FALSE))->cch); memcpy(bufg,psbRunfile,1 + B2W(*psbRunfile)); UpdateFileParts(bufg,sb); /* If the name has changed, issue a warning and update rhteRunfile. */ if(!SbCompare(bufg,psbRunfile,TRUE)) { bufg[1 + B2W(*bufg)] = 0; OutWarn(ER_outputname, bufg + 1); PropSymLookup(bufg,ATTRNIL,TRUE); rhteRunfile = vrhte; } } void NEAR PrintQbStart(void) { fprintf(bsLst,"\r\nProgram entry point at %04x:%04x\r\n", mpsegsa[segStart],(WORD)raStart); /* Print entry point */ } LOCAL void QbSaveSym(APROPNAMEPTR prop, RBTYPE rhte, RBTYPE rprop, WORD fNewHte) { AHTEPTR hte = (AHTEPTR) rhte; /* Omit nonprintable symbols from the symbol table */ if (!(prop->an_flags & FPRINT)) return; /* Omit printable symbols which starts with "B$..." or "b$..." */ if(hte->cch[2] == '$' && hte->cch[0] >= 2 && (hte->cch[1] == 'b' || hte->cch[1] == 'B')) return; if (prop->an_gsn != SNNIL && mpsegFlags[mpgsnseg[prop->an_gsn]] & FCODE) symCodeMac++; psymrb[symQbMac++] = rprop; /* Save the prop addr */ } LOCAL void NEAR MoveToQbSym (cb, pData) WORD cb; char *pData; { MoveToVm(cb, pData, segQbSym, raQbSym); raQbSym += cb; } LOCAL void NEAR BldQbHdr () { QBHDRTYPE hdr; /* QB symbol table headr */ APROPNAMEPTR aprop; SATYPE sa; memset(&hdr,0,sizeof(hdr)); /* Clear all header fields */ hdr.jmpstart[0] = JMPFAR; aprop = (APROPNAMEPTR ) FetchSym(rbQbstart,FALSE); if(aprop == PROPNIL || aprop->an_attr != ATTRPNM) OutError(ER_qlib); else { hdr.jmpstart[1] = (BYTE) aprop->an_ra; hdr.jmpstart[2] = (BYTE) (aprop->an_ra >> 8); sa = mpsegsa[mpgsnseg[aprop->an_gsn]]; hdr.jmpstart[3] = (BYTE) sa; hdr.jmpstart[4] = (BYTE) (sa >> 8); RecordSegmentReference(segQbSym,(long)QH_SAQBSTART,1); } hdr.raCodeLst = QB_RACODELST; /* $code_list starts at known offset */ hdr.raDataLst = (symCodeMac * CBSYMENTRY) + hdr.raCodeLst + 2; hdr.raSegLst = ((symQbMac - symCodeMac) * CBSYMENTRY) + hdr.raDataLst + 2; if(segQCode != SEGNIL) { hdr.saCode = mpsegsa[segQCode]; /* 1st code segment */ RecordSegmentReference(segQbSym,(long)QH_SACODE,1); } if(ggrDGroup != GRNIL) { hdr.saData = mpsegsa[mpgsnseg[mpggrgsn[ggrDGroup]]]; RecordSegmentReference(segQbSym,(long)QH_SADATA,1); } hdr.saSymbol = mpsegsa[segQbSym]; /* segment base of SYMBOL (us) */ RecordSegmentReference(segQbSym,(long)QH_SASYMBOL,1); /* Get starting segment and size of FAR_DATA */ if(segFD1st != SEGNIL) { hdr.saFarData = mpsegsa[segFD1st]; RecordSegmentReference(segQbSym,(long)QH_SAFARDATA,1); hdr.cbFarData = mpsegcb[segFDLast] + ((long)(mpsegsa[segFDLast] - mpsegsa[segFD1st]) << 4); } /* Get starting segment and size of FAR_BSS */ if(segFB1st != SEGNIL) { hdr.saFarBss = mpsegsa[segFB1st]; RecordSegmentReference(segQbSym,(long)QH_SAFARBSS,1); hdr.cbFarBss = mpsegcb[segFBLast] + ((long)(mpsegsa[segFBLast] - mpsegsa[segFB1st]) << 4); } hdr.version = QBVER; hdr.magic = QBMAGIC; hdr.cbSymbol = (WORD) raQbSym; raQbSym = 0; MoveToQbSym(sizeof hdr, &hdr); } int cdecl QbCompSym (const RBTYPE *prb1, const RBTYPE *prb2) { APROPNAMEPTR prop; SNTYPE gsn1, gsn2; FTYPE fCode1, fCode2; RBTYPE rb1, rb2; gsn1 = ((APROPNAMEPTR ) FetchSym(*prb1, FALSE))->an_gsn; gsn2 = ((APROPNAMEPTR ) FetchSym(*prb2, FALSE))->an_gsn; if (gsn1 == gsn2) { prop = (APROPNAMEPTR ) FetchSym(*prb1,FALSE); while(prop->an_attr != ATTRNIL) prop = (APROPNAMEPTR ) FetchSym(rb1 = prop->an_next,FALSE); prop = (APROPNAMEPTR ) FetchSym(*prb2,FALSE); while(prop->an_attr != ATTRNIL) prop = (APROPNAMEPTR ) FetchSym(rb2 = prop->an_next,FALSE); return(FGtName(&rb1, &rb2)); } /* For sorting, absolute symbols are treated as data */ /* 1 code, 2 data: 1 < 2 : -1 * 1 data, 2 code: 1 > 2 : 1 * same: 1 = 2 : 0 */ fCode1 = (FTYPE) (gsn1 != SNNIL && mpsegFlags[mpgsnseg[gsn1]] & FCODE); fCode2 = (FTYPE) (gsn2 != SNNIL && mpsegFlags[mpgsnseg[gsn2]] & FCODE); if(fCode1 && !fCode2) return(-1); if(!fCode1 && fCode2) return(1); return(0); } LOCAL void NEAR QbAddName (ahte) AHTEPTR ahte; { SBTYPE sbName; WORD cbName; BYTE *sb; sb = GetPropName(ahte); cbName = B2W(sb[0]); memcpy(sbName,sb+1,cbName); /* Copy name sans length byte */ sbName[cbName] = '\0'; /* Terminate with null */ MoveToVm((short)(cbName + 1), sbName, segQbSym, raNames); raNames += cbName + 1; /* Update the name_list offset */ } LOCAL void NEAR BldSegSym (gsn) SNTYPE gsn; { APROPSNPTR apropSn; QBSYMTYPE entry; apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn], FALSE); if(apropSn->as_rCla == rhteBc_vars || gsn == gsnComBl) entry.flags = QBTYP_BCSEG; else entry.flags = QBTYP_SEG; /* other segment */ entry.raName = (WORD) raNames; /* offset to name string */ entry.ra = (WORD) mpsegraFirst[mpgsnseg[gsn]]; entry.sa = mpsegsa[mpgsnseg[gsn]]; RecordSegmentReference(segQbSym, (long) (raQbSym + 6), 1); MoveToQbSym(sizeof entry, &entry); /* Move to symbol segment */ QbAddName((AHTEPTR) apropSn); /* Append name to name_list */ } /* * BldSym : Build a Quick symbol table entry for a given symbol prop addr */ LOCAL void NEAR BldSym (prop) APROPNAMEPTR prop; /* Symbol property cell */ { QBSYMTYPE entry; /* Quick symbol entry structure */ SNTYPE seg; /* Segment number */ SATYPE saGroup; /* Group base */ APROPSNPTR papropSn; /* Segment property cell */ #if NOT NEWSYM prop = (APROPNAMEPTR ) FetchSym((RBTYPE) prop, FALSE); #endif /* Set the symbol type in the flags field */ if(prop->an_gsn == SNNIL) entry.flags = QBTYP_ABS; else if (mpsegFlags[mpgsnseg[prop->an_gsn]] & FCODE) entry.flags = QBTYP_CODE; else entry.flags = QBTYP_DATA; entry.raName = (WORD) raNames; /* offset to name string */ entry.ra = (WORD) prop->an_ra; /* symbol address offset */ if(entry.flags == QBTYP_ABS) entry.sa = 0; else { entry.sa = mpsegsa[seg = mpgsnseg[prop->an_gsn]]; /* symbol address segment */ if(seg <= segLast) { /* If segment is member of a group, adjust symbol offset * to be group-relative. */ papropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[prop->an_gsn], FALSE); if(papropSn->as_ggr != GRNIL) { saGroup = mpsegsa[mpgsnseg[mpggrgsn[papropSn->as_ggr]]]; entry.ra = (WORD)((entry.ra + ((entry.sa - saGroup) << 4)) & ~(~0 << WORDLN)); /* Fix offset */ entry.sa = saGroup; /* Set base to base of group */ } } RecordSegmentReference(segQbSym, (long) (raQbSym + 6), 1); } MoveToQbSym(sizeof entry, &entry); /* Move to SYMBOL segment */ QbAddName((AHTEPTR) prop); /* Append name to name_list */ } void NEAR BldQbSymbols (gsnQbSym) SNTYPE gsnQbSym; { SNTYPE seg; SNTYPE gsn; WORD zero = 0; APROPSNPTR apropSn; WORD sym; extern WORD pubMac; psymrb = (RBTYPE FAR *) GetMem((pubMac+1) * sizeof(RBTYPE)); segStart = segQbSym = mpgsnseg[gsnQbSym]; raStart = 0; mpsegFlags[segQbSym] |= FNOTEMPTY; /* Make sure it is output */ if (mpsegMem[segQbSym]) FFREE(mpsegMem[segQbSym]); // Initial allocation was incorrect mpsegMem[segQbSym] = GetMem(LXIVK); // Allocate 64k mpsegcb[segQbSym] = LXIVK; raQbSym = CBQBHDR; /* Skip header for now */ EnSyms(QbSaveSym, ATTRPNM); /* Save the symbol addr's in symrb */ qsort(psymrb, symQbMac, sizeof(RBTYPE), (int (__cdecl *)(const void *, const void *)) QbCompSym); /* Sort into code, data, & by name */ raNames = raQbSym + ((symQbMac + segLast) * CBSYMENTRY) + 6; for (sym = 0; sym < symCodeMac; sym++) BldSym(psymrb[sym]); MoveToQbSym(2, &zero); for (; sym < symQbMac; sym++) BldSym(psymrb[sym]); MoveToQbSym(2, &zero); /* Look for segment COMMON class BLANK */ apropSn = (APROPSNPTR ) PropSymLookup("\006COMMON",ATTRPSN,FALSE); if(apropSn != PROPNIL) { while(apropSn->as_attr != ATTRNIL) { if(apropSn->as_attr == ATTRPSN && apropSn->as_rCla == rhteBlank) break; apropSn = (APROPSNPTR ) FetchSym(apropSn->as_next,FALSE); } if(apropSn->as_attr != ATTRNIL) gsnComBl = apropSn->as_gsn; } for (seg = 1; seg <= segLast; seg++) { for (gsn = 1; gsn <= gsnMac && seg != mpgsnseg[gsn]; gsn++); BldSegSym(gsn); if(segQCode == SEGNIL && (mpsegFlags[seg] & FCODE)) segQCode = seg; } raQbSym = raNames; MoveToQbSym(2, &zero); mpsegcb[segQbSym] = (long) raQbSym; ((APROPSNPTR ) FetchSym(mpgsnrprop[gsnQbSym], TRUE))->as_cbMx = raQbSym; BldQbHdr(); }