408 lines
15 KiB
C
408 lines
15 KiB
C
#include <minlit.h> /* Types and constants */
|
|
#include <bndtrn.h> /* More of the same */
|
|
#include <bndrel.h> /* More of the same */
|
|
#include <lnkio.h> /* Linker I/O definitions */
|
|
#include <lnkmsg.h> /* Error messages */
|
|
#include <extern.h> /* 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();
|
|
}
|