windows-nt/Source/XPSP1/NT/sdktools/link16/qbsym.c
2020-09-26 16:20:57 +08:00

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();
}