1176 lines
42 KiB
C
1176 lines
42 KiB
C
/* SCCSID = %W% %E% */
|
||
/*
|
||
* Copyright Microsoft Corporation, 1983-1987
|
||
*
|
||
* This Module contains Proprietary Information of Microsoft
|
||
* Corporation and should be treated as Confidential.
|
||
*/
|
||
/****************************************************************
|
||
* *
|
||
* NEWADR.C *
|
||
* *
|
||
* Common address-assignment routines. *
|
||
* *
|
||
****************************************************************/
|
||
|
||
#include <minlit.h> /* Types and constants */
|
||
#include <bndtrn.h> /* Types and constants */
|
||
#include <bndrel.h> /* Reloc. type definitions */
|
||
#include <lnkio.h> /* Linker I/O definitions */
|
||
#include <newexe.h> /* DOS & 286 .EXE data structures */
|
||
#if EXE386
|
||
#include <exe386.h> /* 386 .EXE data structures */
|
||
#endif
|
||
#include <lnkmsg.h> /* Error messages */
|
||
#include <extern.h> /* External function declarations */
|
||
|
||
/*
|
||
* FUNCTION PROTOTYPES
|
||
*/
|
||
|
||
|
||
LOCAL void FixSymRa(APROPNAMEPTR papropName,
|
||
RBTYPE rhte,
|
||
RBTYPE rprop,
|
||
WORD fNewHte);
|
||
LOCAL void AllocateCommon(APROPNAMEPTR papropName,
|
||
RBTYPE rhte,
|
||
RBTYPE rprop,
|
||
WORD fNewHte);
|
||
#if OSEGEXE AND SYMDEB AND NOT EXE386
|
||
LOCAL void GenImports(APROPNAMEPTR papropName,
|
||
RBTYPE rhte,
|
||
RBTYPE rprop,
|
||
FTYPE fNewHte);
|
||
#endif
|
||
LOCAL void NEAR AssignClasses(unsigned short (NEAR *ffun)(APROPSNPTR prop));
|
||
LOCAL WORD NEAR IsNotAbs(APROPSNPTR apropSn);
|
||
LOCAL WORD NEAR IsCode(APROPSNPTR prop);
|
||
LOCAL WORD NEAR IsNotDGroup(APROPSNPTR prop);
|
||
LOCAL WORD NEAR IsBegdata(APROPSNPTR prop);
|
||
LOCAL WORD NEAR IsNotBssStack(APROPSNPTR prop);
|
||
LOCAL WORD NEAR IsNotStack(APROPSNPTR prop);
|
||
|
||
|
||
#if QBLIB
|
||
extern RBTYPE rhteFarData; /* "FARDATA" class name */
|
||
extern RBTYPE rhteFarBss; /* "FARBSS" class name */
|
||
extern SEGTYPE segFD1st, segFDLast;
|
||
extern SEGTYPE segFB1st, segFBLast;
|
||
#endif
|
||
|
||
#define IsAbsTysn(tysn) ((tysn & ~(BIGBIT | CODE386BIT)) == TYSNABS)
|
||
|
||
SNTYPE gsnText; /* Global SEGDEF for _TEXT */
|
||
|
||
/* Local variables */
|
||
LOCAL long cbCommon; /* Count of bytes in COMMON */
|
||
LOCAL long cbFar; /* Count of bytes in far common */
|
||
LOCAL GRTYPE ggrCommon; /* Global group no. for common */
|
||
LOCAL SNTYPE gsnCommon; /* Global SEGDEF for common */
|
||
LOCAL SNTYPE gsnFar; /* Far common SEGDEF number */
|
||
LOCAL FTYPE fNoEdata = (FTYPE) TRUE;
|
||
LOCAL FTYPE fNoEnd = (FTYPE) TRUE;
|
||
|
||
|
||
#if SYMDEB
|
||
LOCAL int NEAR IsDebug(APROPSNPTR propSn);
|
||
|
||
/************************************************************
|
||
* *
|
||
* Returns true if segment definition record is a debug *
|
||
* segment: private and a recognized class. *
|
||
* *
|
||
************************************************************/
|
||
|
||
LOCAL int NEAR IsDebug(APROPSNPTR propSn)
|
||
{
|
||
return (fSymdeb && propSn->as_attr == ATTRLSN &&
|
||
(propSn->as_rCla == rhteDebTyp ||
|
||
propSn->as_rCla == rhteDebSym || propSn->as_rCla == rhteDebSrc));
|
||
}
|
||
#else
|
||
#define IsDebug(a) FALSE
|
||
#endif
|
||
|
||
AHTEPTR GetHte(rprop) /* Get hash table entry */
|
||
RBTYPE rprop; /* Property cell address */
|
||
{
|
||
REGISTER AHTEPTR ahte; /* Hash table entry pointer */
|
||
|
||
ahte = (AHTEPTR ) FetchSym(rprop,FALSE);
|
||
/* Fetch property cell */
|
||
/* While not at hash table entry, get next cell in chain */
|
||
while(ahte->attr != ATTRNIL)
|
||
ahte = (AHTEPTR ) FetchSym(ahte->rhteNext,FALSE);
|
||
return(ahte); /* Return ptr to hash table entry */
|
||
}
|
||
|
||
|
||
/****************************************************************
|
||
* *
|
||
* FixSymRa: *
|
||
* *
|
||
* Fix symbol offset. Called by EnSyms. *
|
||
* *
|
||
****************************************************************/
|
||
|
||
LOCAL void FixSymRa (papropName,rhte,rprop,fNewHte)
|
||
APROPNAMEPTR papropName; /* Symbol property cell */
|
||
RBTYPE rhte; /* Hash table virt address */
|
||
RBTYPE rprop; /* Symbol virt address */
|
||
WORD fNewHte;
|
||
{
|
||
SNTYPE gsn;
|
||
#if O68K
|
||
SATYPE sa;
|
||
#endif /* O68K */
|
||
|
||
if(!(gsn = papropName->an_gsn)) return;
|
||
papropName->an_ra += mpgsndra[gsn];
|
||
|
||
#if O68K
|
||
if (iMacType != MAC_NONE && IsDataFlg(mpsaflags[sa =
|
||
mpsegsa[mpgsnseg[gsn]]]))
|
||
papropName->an_ra += mpsadraDP[sa];
|
||
#endif /* O68K */
|
||
|
||
MARKVP();
|
||
}
|
||
|
||
/****************************************************************
|
||
* *
|
||
* GenSeg: *
|
||
* *
|
||
* Generate a segment definition. *
|
||
* *
|
||
****************************************************************/
|
||
|
||
#if EXE386
|
||
APROPSNPTR GenSeg(sbName,sbClass,ggr,fPublic)
|
||
#else
|
||
APROPSNPTR NEAR GenSeg(sbName,sbClass,ggr,fPublic)
|
||
#endif
|
||
BYTE *sbName; /* Segment name */
|
||
BYTE *sbClass; /* Class name */
|
||
GRTYPE ggr; /* Global GRPDEF number */
|
||
WORD fPublic; /* True if public segment */
|
||
{
|
||
APROPSNPTR apropSn; /* Pointer to SEGDEF */
|
||
RBTYPE rhteClass; /* Class name virt addr */
|
||
|
||
PropSymLookup(sbClass, ATTRNIL, TRUE);/* Insert class name in hash table */
|
||
rhteClass = vrhte; /* Save class name virt addr */
|
||
if(fPublic) /* If public segment */
|
||
{
|
||
apropSn = (APROPSNPTR ) PropSymLookup(sbName, ATTRPSN, TRUE);
|
||
/* Create segment */
|
||
if(!vfCreated) return(apropSn); /* If it existed, return pointer */
|
||
#if EXE386
|
||
apropSn->as_tysn = DWORDPUBSEG; /* Segment is public */
|
||
#else
|
||
apropSn->as_tysn = PARAPUBSEG; /* Segment is public */
|
||
#endif
|
||
}
|
||
else /* Else if private segment */
|
||
{
|
||
PropSymLookup(sbName, ATTRNIL, TRUE);
|
||
/* Look up name */
|
||
apropSn = (APROPSNPTR ) PropAdd(vrhte,ATTRLSN);
|
||
/* Segment is local */
|
||
#if EXE386
|
||
apropSn->as_tysn = DWORDPRVSEG; /* Segment is private */
|
||
#else
|
||
apropSn->as_tysn = PARAPRVSEG; /* Segment is private */
|
||
#endif
|
||
}
|
||
if(gsnMac >= gsnMax) Fatal(ER_segmax);
|
||
/* Check for table overflow */
|
||
apropSn->as_rCla = rhteClass; /* Save segment's class */
|
||
mpgsnrprop[gsnMac] = vrprop; /* Save property cell address */
|
||
apropSn->as_gsn = gsnMac++; /* Give it a global SEGDEF number */
|
||
apropSn->as_ggr = ggr; /* Give specified group association */
|
||
return(apropSn); /* Return global SEGDEF */
|
||
}
|
||
|
||
|
||
#if FALSE AND OSEGEXE AND SYMDEB AND NOT EXE386
|
||
/* Postponed CV not ready yet */
|
||
|
||
/*** GenImports - fill in $$IMPORTS segment for CV
|
||
*
|
||
* Purpose:
|
||
* Build $$IMPORTS segment for CV. This segment enables symbolic information
|
||
* in CV for dyncalls. The $$IMPORTS segment contains sequence of entries
|
||
* in the following format:
|
||
*
|
||
* 16-bit 16-bit 32-bit
|
||
* +--------+--------+-----------------+
|
||
* | iMod | iName | far address |
|
||
* +--------+--------+-----------------+
|
||
*
|
||
* Where:
|
||
* - iMod - index to Module Reference Table in .EXE
|
||
* - iName - index to Imported Names Table in .EXE (32-bit for 386)
|
||
* - address - import's address fixed up by loader
|
||
*
|
||
* Input:
|
||
* This function is called by EnSyms, so it takes standard set of arguments.
|
||
* papropName - pointer to import property cell
|
||
* rprop - virtual address of property cell
|
||
* rhte - virt address of hash table entry
|
||
* fNewHte - TRUE if name has been written
|
||
*
|
||
* Output:
|
||
* No explicit value is returned. Segment data is created and run-time
|
||
* fiuxps.
|
||
*
|
||
* Exceptions:
|
||
* None.
|
||
*
|
||
* Notes:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
|
||
LOCAL void GenImports(papropName,rhte,rprop,fNewHte)
|
||
APROPNAMEPTR papropName;
|
||
RBTYPE rhte;
|
||
RBTYPE rprop;
|
||
FTYPE fNewHte;
|
||
{
|
||
static WORD raImpSeg = 0;
|
||
APROPIMPPTR lpImport;
|
||
APROPNAMEPTR lpPublic;
|
||
CVIMP cvImp;
|
||
RELOCATION r; /* Relocation item */
|
||
|
||
|
||
lpImport = (APROPIMPPTR) papropName;
|
||
if (lpImport->am_mod)
|
||
return; /* Skip module name */
|
||
|
||
/* Build CV import descriptor and save it in $$IMPORTS segment */
|
||
|
||
cvImp.iName = lpImport->am_offset; /* Save index to Imported Name Table */
|
||
cvImp.address = (char far *) 0L;
|
||
lpPublic = (APROPNAMEPTR) FetchSym((RBTYPE)lpImport->am_public, FALSE);
|
||
cvImp.iMod = lpPublic->an_module; /* Save index to Module Reference Table */
|
||
vgsnCur = gsnImports;
|
||
MoveToVm(sizeof(CVIMP), (BYTE *) &cvImp, mpgsnseg[gsnImports], raImpSeg);
|
||
|
||
/* Emit run-time fixup for import, so loader will fill in addrss field */
|
||
|
||
#if EXE386
|
||
R32_SOFF(r) = (WORD) ((raImpSeg + 6) % OBJPAGELEN);
|
||
#else
|
||
NR_SOFF(r) = (WORD) raImpSeg + 4;
|
||
#endif
|
||
NR_STYPE(r) = (BYTE) NRSPTR; /* Save fixup type - 16:16 pointer */
|
||
NR_FLAGS(r) = (lpPublic->an_flags & FIMPORD) ? NRRORD : NRRNAM;
|
||
#if EXE386
|
||
R32_MODORD(r) = lpPublic->an_module;/* Get module specification */
|
||
if (NR_FLAGS(r) & NRRNAM) /* Get entry specification */
|
||
{
|
||
if (cbImports < LXIVK)
|
||
R32_PROCOFF16(r) = (WORD) lpPublic->an_entry;
|
||
/* 16-bit offset */
|
||
else
|
||
{ /* 32-bit offset */
|
||
R32_PROCOFF32(r) = lpPublic->an_entry;
|
||
NR_FLAGS(r) |= NR32BITOFF;
|
||
}
|
||
}
|
||
else
|
||
R32_PROCORD(r) = (WORD) lpPublic->an_entry;
|
||
SaveFixup(mpsegsa[mpgsnseg[gsnImports]], ((raImpSeg + 6) >> pageAlign) + 1, &r);
|
||
#else
|
||
NR_MOD(r) = lpPublic->an_module; /* Get module specification */
|
||
NR_PROC(r) = lpPublic->an_entry; /* Get entry specification */
|
||
SaveFixup(mpsegsa[mpgsnseg[gsnImports]],&r);
|
||
#endif
|
||
raImpSeg += sizeof(CVIMP);
|
||
}
|
||
#endif
|
||
|
||
|
||
/****************************************************************
|
||
* *
|
||
* AllocateCommon: *
|
||
* *
|
||
* Allocate space for C common variables. Called by EnSyms. *
|
||
* *
|
||
****************************************************************/
|
||
LOCAL void AllocateCommon(papropName,rhte,rprop,fNewHte)
|
||
APROPNAMEPTR papropName;
|
||
RBTYPE rhte;
|
||
RBTYPE rprop;
|
||
WORD fNewHte;
|
||
{
|
||
APROPUNDEFPTR papropUndef; /* Pointer to undefined symbol */
|
||
APROPSNPTR apropSn; /* SEGDEF pointer */
|
||
long len; /* Length of common variable */
|
||
WORD cbElem; /* Bytes per element */
|
||
long cbSeg; /* Number of bytes per segment */
|
||
|
||
|
||
papropUndef = (APROPUNDEFPTR ) papropName;
|
||
/* Recast pointer */
|
||
if (papropUndef->au_flags & COMMUNAL)/* If symbol is defined common */
|
||
{
|
||
len = papropUndef->au_len; /* Get object's length */
|
||
cbElem = papropUndef->au_cbEl; /* Get number of bytes per element */
|
||
papropName->an_attr = ATTRPNM; /* Give it the public attribute */
|
||
papropName->an_flags = FPRINT; /* Symbol is printable */
|
||
#if ILINK
|
||
papropName->an_module = 0; /* Special "module" for communals */
|
||
#endif
|
||
MARKVP(); /* Mark virtual page as dirty */
|
||
++pubMac; /* Increment count of public symbols */
|
||
if(!cbElem) /* If near variable */
|
||
{
|
||
#if OMF386
|
||
if (f386) /* DWORD-align objects >= len 4 */
|
||
{
|
||
if(len >= 4 && cbCommon + 3 > cbCommon)
|
||
cbCommon = (cbCommon + 3) & ~3L;
|
||
}
|
||
else
|
||
#endif
|
||
if(!(len & 1)) cbCommon = (cbCommon + 1) & ~1L;
|
||
/* Word-align even-lengthed objects */
|
||
papropName->an_ra = (RATYPE) cbCommon;
|
||
/* Assign an offset */
|
||
papropName->an_gsn = gsnCommon;
|
||
/* Assign to c_common segment */
|
||
papropName->an_ggr = ggrCommon;
|
||
/* Set up group association */
|
||
#if OMF386
|
||
if(f386)
|
||
{
|
||
if(cbCommon + len < cbCommon) Fatal(ER_32comarea);
|
||
else cbCommon += len;
|
||
} else
|
||
#endif
|
||
if((cbCommon += len) > LXIVK) Fatal(ER_comarea);
|
||
/* Fatal if too much common */
|
||
}
|
||
else if ((len *= cbElem) < LXIVK)
|
||
{ /* Else if object not "huge" */
|
||
if (cbFar + len > LXIVK) /* If new segment needed */
|
||
{
|
||
if (gsnFar != SNNIL) /* If there is an "old" segment */
|
||
{
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnFar],TRUE);
|
||
/* Get old SEGDEF */
|
||
apropSn->as_cbMx = cbFar;
|
||
/* Save old length */
|
||
}
|
||
apropSn = GenSeg((BYTE *) "\007FAR_BSS",
|
||
(BYTE *) "\007FAR_BSS", GRNIL, FALSE);
|
||
/* Generate one */
|
||
apropSn->as_flags = dfData;
|
||
/* Use default data flags */
|
||
#if EXE386
|
||
apropSn->as_flags &= ~OBJ_INITDATA;
|
||
// Clear initialized data bit
|
||
apropSn->as_flags |= OBJ_UNINITDATA;
|
||
// Set uninitialized data bit
|
||
#endif
|
||
#if O68K
|
||
if(f68k)
|
||
apropSn->as_flags |= NS32BIT;
|
||
// 32-bit data
|
||
#endif
|
||
gsnFar = apropSn->as_gsn;
|
||
/* Get global SEGDEF number */
|
||
cbFar = 0L; /* Initialize size */
|
||
papropName = (APROPNAMEPTR ) FetchSym(rprop,TRUE);
|
||
/* Refetch */
|
||
}
|
||
if (!(len & 1))
|
||
cbFar = (cbFar + 1) & ~1L;
|
||
/* Word-align even-lengthed objects */
|
||
papropName->an_ra = (RATYPE) cbFar;
|
||
/* Assign an offset */
|
||
papropName->an_gsn = gsnFar;/* Assign to far segment */
|
||
papropName->an_ggr = GRNIL; /* No group association */
|
||
cbFar += len; /* Update length */
|
||
}
|
||
else /* Else if "huge" object */
|
||
{
|
||
cbSeg = (LXIVK / cbElem)*cbElem;
|
||
/* Calculate bytes per seg */
|
||
papropName->an_ra = LXIVK - cbSeg;
|
||
/* Assign offset so last element in
|
||
first seg. not split */
|
||
papropName->an_gsn = gsnMac;/* Assign to segment */
|
||
papropName->an_ggr = GRNIL; /* No group association */
|
||
while(len) /* While bytes remain */
|
||
{
|
||
if(cbSeg > len) cbSeg = len;
|
||
/* Clamp segment length to len */
|
||
apropSn = GenSeg((BYTE *) "\010HUGE_BSS",
|
||
(BYTE *) "\010HUGE_BSS",GRNIL,FALSE);
|
||
/* Create segment */
|
||
apropSn->as_cbMx = len > LXIVK ? LXIVK : len;
|
||
/* Set segment size */
|
||
apropSn->as_flags = dfData;
|
||
/* Use default data flags */
|
||
#if EXE386
|
||
apropSn->as_flags &= ~OBJ_INITDATA;
|
||
// Clear initialized data bit
|
||
apropSn->as_flags |= OBJ_UNINITDATA;
|
||
// Set uninitialized data bit
|
||
#endif
|
||
#if O68K
|
||
if(f68k)
|
||
apropSn->as_flags |= NS32BIT;
|
||
// 32-bit data
|
||
#endif
|
||
len -= cbSeg; /* Decrement length */
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/****************************************************************
|
||
* *
|
||
* AssignClasses: *
|
||
* *
|
||
* Assign the ordering of all segments in all classes that *
|
||
* pass the given test function. *
|
||
* *
|
||
****************************************************************/
|
||
|
||
LOCAL void NEAR AssignClasses(WORD (NEAR *ffun)(APROPSNPTR prop))
|
||
{
|
||
REGISTER SNTYPE gsn; /* Index */
|
||
REGISTER APROPSNPTR apropSn; /* Segment definition pointer */
|
||
SNTYPE gsnFirst; /* Index of first segment in class */
|
||
RBTYPE rhteClass; /* Class name */
|
||
|
||
for(gsnFirst = 1; gsnFirst < gsnMac; ++gsnFirst)
|
||
{ /* Loop through the segments */
|
||
rhteClass = RHTENIL; /* Initialize */
|
||
for(gsn = gsnFirst; gsn < gsnMac; ++gsn)
|
||
{ /* Loop to examine segment records */
|
||
if(mpgsnseg[gsn] != SEGNIL) continue;
|
||
/* Skip assigned segments */
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn],FALSE);
|
||
/* Fetch SEGDEF from virt. mem. */
|
||
if(rhteClass == RHTENIL) rhteClass = apropSn->as_rCla;
|
||
/* Get class if we don't have one */
|
||
if(apropSn->as_rCla == rhteClass &&
|
||
(ffun == ((WORD (NEAR *)(APROPSNPTR)) 0) || (*ffun)(apropSn)))
|
||
{ /* If class member found */
|
||
mpgsnseg[gsn] = ++segLast;
|
||
/* Save ordering number */
|
||
#if QBLIB
|
||
if(fQlib)
|
||
{
|
||
if(rhteClass == rhteFarData && segFD1st == SEGNIL)
|
||
segFD1st = segLast;
|
||
else if(rhteClass == rhteFarBss && segFB1st == SEGNIL)
|
||
segFB1st = segLast;
|
||
}
|
||
#endif
|
||
mpseggsn[segLast] = gsn;// Map the other way
|
||
if(IsCodeFlg(apropSn->as_flags))
|
||
{
|
||
#if OSEGEXE AND ODOS3EXE
|
||
/* Set FCODE here for 3.x segments. FNOTEMPTY later */
|
||
if(!fNewExe)
|
||
mpsegFlags[segLast] = FCODE;
|
||
#endif
|
||
segCodeLast = segLast;
|
||
/* Remember last code segment */
|
||
}
|
||
else if(IsDataFlg(apropSn->as_flags))
|
||
segDataLast = segLast;
|
||
/* Remember last data segment */
|
||
#if NOT OSEGEXE
|
||
mpsegFlags[segLast] = apropSn->as_flags;
|
||
#endif
|
||
}
|
||
}
|
||
#if QBLIB
|
||
if(fQlib)
|
||
{
|
||
if(rhteClass == rhteFarData && segFD1st != SEGNIL)
|
||
segFDLast = segLast;
|
||
else if(rhteClass == rhteFarBss && segFB1st != SEGNIL)
|
||
segFBLast = segLast;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
#if OEXE
|
||
/****************************************************************
|
||
* *
|
||
* MkPubSym: *
|
||
* *
|
||
* Adds a public symbol record with the given parameters *
|
||
* to the symbol table. Used for things like "$$MAIN". *
|
||
* *
|
||
****************************************************************/
|
||
|
||
void MkPubSym(sb,ggr,gsn,ra)
|
||
BYTE *sb; /* Length-prefixed symbol name */
|
||
GRTYPE ggr; /* Global GRPDEF number */
|
||
SNTYPE gsn; /* Global SEGDEF number */
|
||
RATYPE ra; /* Segment offset */
|
||
{
|
||
APROPNAMEPTR apropName; /* Public name pointer */
|
||
|
||
if(PropSymLookup(sb,ATTRPNM,FALSE) != PROPNIL)
|
||
{ /* If symbol already defined */
|
||
OutError(ER_pubdup,sb + 1);
|
||
return; /* And return */
|
||
}
|
||
/* If not undefined, create as public */
|
||
if((apropName = (APROPNAMEPTR )
|
||
PropSymLookup(sb,ATTRUND,FALSE)) == PROPNIL)
|
||
apropName = (APROPNAMEPTR ) PropSymLookup(sb,ATTRPNM,TRUE);
|
||
apropName->an_attr = ATTRPNM; /* Public symbol */
|
||
apropName->an_gsn = gsn; /* Save segment definition number */
|
||
apropName->an_ra = ra; /* Starts at 4th byte of segment */
|
||
apropName->an_ggr = ggr; /* Save group definition number */
|
||
++pubMac; /* Increment public count */
|
||
apropName->an_flags = FPRINT; /* Public is printable */
|
||
MARKVP(); /* Page has changed */
|
||
#if SYMDEB
|
||
if (fSymdeb) /* If ISLAND support on */
|
||
DebPublic(vrprop, PUBDEF);
|
||
/* Make a PUBLICS entry */
|
||
#endif
|
||
#if ILINK
|
||
if (fIncremental)
|
||
apropName->an_module = imodFile;
|
||
#endif
|
||
}
|
||
#endif /* OEXE */
|
||
|
||
LOCAL WORD NEAR IsNotAbs(apropSn)
|
||
APROPSNPTR apropSn; /* Pointer to segment record */
|
||
{
|
||
return(!IsDebug(apropSn) && !IsAbsTysn(apropSn->as_tysn));
|
||
/* Return true if not absolute segment */
|
||
}
|
||
|
||
#if EXE386
|
||
LOCAL WORD NEAR IsImportData(prop)
|
||
APROPSNPTR prop; /* Pointer to segment record */
|
||
{
|
||
return(prop->as_gsn == gsnImport); /* Return true if import data segment */
|
||
}
|
||
#endif
|
||
|
||
LOCAL WORD NEAR IsCode(prop)
|
||
APROPSNPTR prop; /* Pointer to segment record */
|
||
{
|
||
return(IsCodeFlg(prop->as_flags) && !IsAbsTysn(prop->as_tysn));
|
||
/* Return true if code segment */
|
||
}
|
||
|
||
#if OEXE
|
||
LOCAL WORD NEAR IsNotDGroup(prop)
|
||
APROPSNPTR prop; /* Pointer to segment record */
|
||
{
|
||
return(prop->as_ggr != ggrDGroup && !IsDebug(prop) &&
|
||
!IsAbsTysn(prop->as_tysn));
|
||
/* True if segment not in DGROUP */
|
||
}
|
||
|
||
LOCAL WORD NEAR IsBegdata(prop)
|
||
APROPSNPTR prop; /* Pointer to segment record */
|
||
{
|
||
return(prop->as_rCla == rhteBegdata && !IsAbsTysn(prop->as_tysn));
|
||
/* True if segment class BEGDATA */
|
||
}
|
||
|
||
LOCAL WORD NEAR IsNotBssStack(prop)
|
||
APROPSNPTR prop; /* Pointer to segment record */
|
||
{
|
||
return(prop->as_rCla != rhteBss && prop->as_rCla != rhteStack &&
|
||
!IsDebug(prop) && !IsAbsTysn(prop->as_tysn));
|
||
/* True if neither BSS nor STACK */
|
||
}
|
||
|
||
LOCAL WORD NEAR IsNotStack(prop)
|
||
APROPSNPTR prop; /* Pointer to segment record */
|
||
{
|
||
return(prop->as_rCla != rhteStack && !IsDebug(prop) &&
|
||
!IsAbsTysn(prop->as_tysn)); /* True if not class STACK */
|
||
}
|
||
#endif /* OEXE */
|
||
|
||
#if INMEM
|
||
WORD saExe = FALSE;
|
||
|
||
void SetInMem ()
|
||
{
|
||
WORD cparExe;
|
||
WORD cparSave;
|
||
|
||
if(fOverlays || fSymdeb)
|
||
return;
|
||
cparExe = mpsegsa[segLast] +
|
||
((mpsegraFirst[segLast] + mpsegcb[segLast] + 0xf) >> 4);
|
||
cparSave = cparExe;
|
||
if(!(saExe = Dos3AllocMem(&cparExe)))
|
||
return;
|
||
if(cparExe != cparSave)
|
||
{
|
||
Dos3FreeMem(saExe);
|
||
saExe = 0;
|
||
return;
|
||
}
|
||
Dos3ClrMem(saExe,cparExe);
|
||
}
|
||
#endif /* INMEM */
|
||
|
||
/****************************************************************
|
||
* *
|
||
* AssignAddresses: *
|
||
* *
|
||
* This function scans the set of segments, given their *
|
||
* ordering, and assigns segment registers and addresses. *
|
||
* *
|
||
****************************************************************/
|
||
|
||
void NEAR AssignAddresses()
|
||
{
|
||
APROPSNPTR apropSn; /* Ptr to a segment record */
|
||
#if FDEBUG
|
||
SNTYPE gsn; /* Current global segment number */
|
||
long dbsize; /* Length of segment */
|
||
RBTYPE rbClass; /* Pointer to segment class */
|
||
#endif
|
||
BSTYPE bsTmp;
|
||
#if QBLIB
|
||
SNTYPE gsnQbSym; /* gsn of SYMBOL segment for .QLB */
|
||
#endif
|
||
#if OSEGEXE
|
||
extern FTYPE fNoNulls; /* True if not inserting 16 nulls */
|
||
#else
|
||
#define fNoNulls FALSE
|
||
#endif
|
||
|
||
|
||
// Set up stack allocation
|
||
|
||
if (gsnStack != SNNIL) /* If stack segment exists */
|
||
{
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnStack],TRUE);
|
||
/* Fetch segment definition */
|
||
#if OEXE
|
||
apropSn->as_tysn = (BYTE) ((apropSn->as_tysn & 0x1F) | (ALGNPAR << 5));
|
||
/* Force paragraph alignment */
|
||
#if EXE386
|
||
if (!cbStack)
|
||
cbStack = apropSn->as_cbMx;
|
||
cbStack = (cbStack + 3) & ~3; /* Must be even number of bytes */
|
||
apropSn->as_cbMx = cbStack;
|
||
#else
|
||
if (!cbStack)
|
||
cbStack = (WORD) apropSn->as_cbMx;
|
||
cbStack = (cbStack + 1) & ~1; /* Must be even number of bytes */
|
||
apropSn->as_cbMx = (DWORD) cbStack;
|
||
#endif /* Save size of stack segment */
|
||
#else
|
||
/* Force size to 0 for Xenix executables */
|
||
apropSn->as_cbMx = 0L;
|
||
#endif
|
||
}
|
||
#if OEXE
|
||
#if OSEGEXE
|
||
else if(cbStack == 0 &&
|
||
#if O68K
|
||
iMacType == MAC_NONE &&
|
||
#endif
|
||
#if EXE386
|
||
IsAPLIPROG(vFlags))
|
||
#else
|
||
!(vFlags & NENOTP) && !fBinary)
|
||
#endif
|
||
#else
|
||
else if(cbStack == 0 && !fBinary)
|
||
#endif
|
||
{ /* Else if no stack and not library */
|
||
#if 0
|
||
/* Issue warning message */
|
||
if(fLstFileOpen && bsLst != stderr)
|
||
{
|
||
bsTmp = bsErr;
|
||
bsErr = bsLst;
|
||
OutWarn(ER_nostack);
|
||
bsErr = bsTmp;
|
||
}
|
||
OutWarn(ER_nostack);
|
||
#endif
|
||
}
|
||
#endif
|
||
if(fCommon) /* If there are communal variables */
|
||
{
|
||
apropSn = GenSeg((BYTE *) "\010c_common",
|
||
(BYTE *) "\003BSS",ggrDGroup,TRUE);
|
||
/* Generate communal variable seg */
|
||
if(vfCreated) apropSn->as_flags = dfData;
|
||
/* Use default data flags */
|
||
gsnCommon = apropSn->as_gsn; /* Save common segment number */
|
||
ggrCommon = apropSn->as_ggr; /* Save common group number */
|
||
cbCommon = apropSn->as_cbMx; /* Initialize size of common */
|
||
gsnFar = SNNIL; /* No far BSS yet */
|
||
#if NOT EXE386
|
||
#if OMF386
|
||
if(f386)
|
||
{
|
||
cbFar = ~0L;
|
||
apropSn->as_flags |= FCODE386;
|
||
}
|
||
else
|
||
#endif
|
||
#if O68K
|
||
if(f68k)
|
||
{
|
||
cbFar = LXIVK + 1; /* Force creation of far BSS segment */
|
||
apropSn->as_flags |= NS32BIT;
|
||
}
|
||
else
|
||
#endif
|
||
#endif
|
||
cbFar = LXIVK + 1; /* Force creation of far BSS segment */
|
||
DEBUGVALUE(cbCommon); /* Debug info */
|
||
EnSyms(AllocateCommon,ATTRUND);
|
||
/* Assign common variables */
|
||
/* Don't use SmallEnEnsyms - symbol */
|
||
/* table may grow while in EnSyms */
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnCommon],TRUE);
|
||
apropSn->as_cbMx = cbCommon; /* Save segment size */
|
||
if(gsnFar != SNNIL) /* If far BSS created */
|
||
{
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnFar],TRUE);
|
||
apropSn->as_cbMx = cbFar; /* Save segment size */
|
||
}
|
||
}
|
||
#if FALSE AND OSEGEXE AND SYMDEB AND NOT EXE386
|
||
if (fSymdeb && fNewExe && cImpMods)
|
||
{
|
||
apropSn = GenSeg("\011$$IMPORTS", "\010FAR_DATA", GRNIL, FALSE);
|
||
/* Support for dyncalls for CV */
|
||
gsnImports = apropSn->as_gsn;
|
||
apropSn->as_flags = dfData; /* Use default data flags */
|
||
apropSn->as_cbMx = cbImpSeg; /* Save segment size */
|
||
}
|
||
#endif
|
||
#if EXE386
|
||
GenImportTable();
|
||
#endif
|
||
|
||
/* Initialize segment-based tables for pass 2 */
|
||
|
||
InitP2Tabs();
|
||
#if OVERLAYS
|
||
if(fOverlays) SetupOverlays();
|
||
#endif
|
||
#if OEXE
|
||
/*
|
||
* If /DOSSEG is enabled and /NONULLSDOSSEG is not enabled, look for
|
||
* segment _TEXT. If found, increase size by 16 in preparation for
|
||
* reserving first 16 addresses for the sake of signal().
|
||
*/
|
||
if(fSegOrder && !fNoNulls)
|
||
{
|
||
apropSn = (APROPSNPTR ) PropSymLookup((BYTE *) "\005_TEXT",ATTRPSN,FALSE);
|
||
/* Look for public segment _TEXT */
|
||
if(apropSn != PROPNIL) /* If it exists */
|
||
{
|
||
gsnText = apropSn->as_gsn; /* Save the segment index */
|
||
if ((apropSn->as_tysn)>>5 == ALGNPAG)
|
||
NullDelta = 256;
|
||
#if EXE386
|
||
if (apropSn->as_cbMx > CBMAXSEG32 - NullDelta)
|
||
Fatal(ER_txtmax);
|
||
else
|
||
apropSn->as_cbMx += NullDelta;
|
||
#else
|
||
if((apropSn->as_cbMx += NullDelta) > LXIVK)
|
||
Fatal(ER_txtmax);
|
||
#endif
|
||
fTextMoved = TRUE;
|
||
/* Bump the size up */
|
||
MARKVP(); /* Page has changed */
|
||
}
|
||
}
|
||
#endif
|
||
#if FDEBUG
|
||
if(fDebug && fLstFileOpen) /* If debugging on */
|
||
{
|
||
/* Dump segments and lengths */
|
||
for(gsn = 1; gsn < gsnMac; ++gsn)
|
||
{
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn],FALSE);
|
||
dbsize = apropSn->as_cbMx;
|
||
rbClass = apropSn->as_rCla;
|
||
FmtPrint("%3d segment \"%s\"",gsn,1 + GetPropName(apropSn));
|
||
FmtPrint(" class \"%s\" length %lxH bytes\r\n",
|
||
1 + GetPropName(FetchSym(rbClass,FALSE)),dbsize);
|
||
}
|
||
}
|
||
#endif
|
||
#if OSEGEXE
|
||
if (gsnAppLoader)
|
||
{
|
||
// Make sure that aplication loder gets its own segment
|
||
|
||
mpgsnseg[gsnAppLoader] = ++segLast;
|
||
mpseggsn[segLast] = gsnAppLoader;
|
||
}
|
||
#endif
|
||
#if OEXE
|
||
if (fSegOrder) /* If forcing segment ordering */
|
||
{
|
||
AssignClasses(IsCode); /* Code first,... */
|
||
#if EXE386
|
||
AssignClasses(IsImportData); /* ...then import data */
|
||
#endif
|
||
AssignClasses(IsNotDGroup); /* ...then non-DGROUP,... */
|
||
AssignClasses(IsBegdata); /* ...then class BEGDATA,... */
|
||
AssignClasses(IsNotBssStack); /* ...then all but BSS and STACK,... */
|
||
AssignClasses(IsNotStack); /* ...then all but class STACK */
|
||
}
|
||
#endif
|
||
#if OXOUT OR OIAPX286
|
||
if(fIandD) /* If separate code and data */
|
||
AssignClasses(IsCode); /* Assign ordering to code */
|
||
#endif
|
||
AssignClasses(IsNotAbs); /* Assign order to segments */
|
||
#if QBLIB
|
||
/* If building QB userlib, generate the symbol segment last */
|
||
if(fQlib)
|
||
{
|
||
gsnQbSym = GenSeg("\006SYMBOL", "", GRNIL, FALSE)->as_gsn;
|
||
mpgsnseg[gsnQbSym] = ++segLast;
|
||
}
|
||
#endif
|
||
#if NOT EXE386
|
||
if (fBinary && cbStack && mpgsnseg[gsnStack] == 1)
|
||
{
|
||
/*
|
||
* In .COM file first segment is a stack and it has non zero
|
||
* size. We warn user about making his stack segment size
|
||
* equal zero.
|
||
*/
|
||
apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnStack],TRUE);
|
||
apropSn->as_cbMx = 0L;
|
||
OutWarn(ER_stksize);
|
||
|
||
}
|
||
#endif
|
||
|
||
/* Assign addresses according to which format exe is being produced */
|
||
|
||
#if OIAPX286
|
||
AssignXenAddr();
|
||
#endif
|
||
|
||
#if OSEGEXE AND ODOS3EXE
|
||
|
||
if (fNewExe)
|
||
AssignSegAddr();
|
||
else
|
||
AssignDos3Addr();
|
||
|
||
#else
|
||
|
||
#if OSEGEXE
|
||
AssignSegAddr();
|
||
#endif
|
||
|
||
#if ODOS3EXE
|
||
AssignDos3Addr();
|
||
#endif
|
||
|
||
#endif
|
||
|
||
// Remember index for first debug segment
|
||
|
||
segDebFirst = segLast +
|
||
#if ODOS3EXE
|
||
csegsAbs +
|
||
#endif
|
||
(SEGTYPE) 1;
|
||
#if OEXE
|
||
|
||
// If /DOSSEG enabled and segment _TEXT found, initialize offset
|
||
// of _TEXT to 16 to reserve addresses 0-15. WARNING: gsnText must
|
||
// be initialized to SNNIL.
|
||
|
||
if (gsnText != SNNIL)
|
||
{
|
||
mpgsndra[gsnText] += NullDelta;
|
||
|
||
// If no program starting address, initialize it to 0:NullDelta
|
||
|
||
if (segStart == SEGNIL && !raStart && !mpsegsa[mpgsnseg[gsnText]])
|
||
raStart = NullDelta;
|
||
|
||
// If /DOSSEG enabled and segment _TEXT found, initialize offset
|
||
// of _TEXT to NulDelta to reserve addresses 0-NullDelta-1.
|
||
// This was done after the COMDAT's were allocated so the offsets
|
||
// of COMDAT's allocated in _TEXT segment are off by NullDelta bytes.
|
||
// Here we adjust them, so the data block associated with COMDAT
|
||
// is placed in the right spot in the memory image. The matching
|
||
// public symbol will be shifted by the call to EnSyms(FixSymRa, ATTRPNM).
|
||
|
||
FixComdatRa();
|
||
}
|
||
#endif
|
||
EnSyms(FixSymRa, ATTRPNM);
|
||
#if LOCALSYMS
|
||
if (fLocals)
|
||
EnSyms(FixSymRa, ATTRLNM);
|
||
#endif
|
||
#if INMEM
|
||
SetInMem();
|
||
#endif
|
||
|
||
// Allocate memory blocks for the final program's memory image
|
||
|
||
if (fNewExe)
|
||
{
|
||
// Segmented-executable
|
||
|
||
mpsaMem = (BYTE FAR * FAR *) GetMem(saMac * sizeof(BYTE FAR *));
|
||
}
|
||
else
|
||
{
|
||
// DOS executable
|
||
|
||
mpsegMem = (BYTE FAR * FAR *) GetMem((segLast + 1) * sizeof(BYTE FAR *));
|
||
}
|
||
|
||
#if OVERLAYS
|
||
if (fOverlays && gsnOvlData != SNNIL)
|
||
FixOvlData(); // Initialize overlay data tables
|
||
#endif
|
||
#if QBLIB
|
||
if(fQlib) BldQbSymbols(gsnQbSym); /* Build QB SYMBOL segment */
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
/*** Define_edata_end - define special C run-time symbols
|
||
*
|
||
* Purpose:
|
||
* Define special symbols _edata and _end used by the C run-time.
|
||
* These symbols are defined as follows:
|
||
*
|
||
* The DGROUP layout
|
||
*
|
||
* +------------+
|
||
* | |
|
||
* | |
|
||
* | |
|
||
* | Near Heap |
|
||
* | |
|
||
* | |
|
||
* +------------+
|
||
* | |
|
||
* | |
|
||
* | STACK |
|
||
* | |
|
||
* | |
|
||
* +------------+ <-- _end
|
||
* | |
|
||
* | _BSS |
|
||
* | |
|
||
* +------------+ <-- _edata
|
||
* | |
|
||
* | _CONST |
|
||
* | |
|
||
* +------------+
|
||
* | |
|
||
* | _DATA |
|
||
* | |
|
||
* +------------+
|
||
*
|
||
* Input:
|
||
* papropSn - pointer to segment descriptor
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
* Exceptions:
|
||
* None.
|
||
*
|
||
* Notes:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
|
||
void NEAR Define_edata_end(APROPSNPTR papropSn)
|
||
{
|
||
APROPNAMEPTR apropName; // Public name pointer
|
||
SNTYPE gsn; // Global segment number
|
||
|
||
|
||
// Symbols were defined by SwDosseg(), now adjust addresses.
|
||
|
||
if (papropSn->as_tysn != TYSNABS && papropSn->as_ggr == ggrDGroup)
|
||
{
|
||
// This is not absolute segment and it belong to DGROUP
|
||
|
||
gsn = papropSn->as_gsn;
|
||
if (fNoEdata && papropSn->as_rCla == rhteBss)
|
||
{
|
||
fNoEdata = FALSE;
|
||
apropName = (APROPNAMEPTR )
|
||
PropSymLookup((BYTE *) "\006_edata",ATTRPNM,FALSE);
|
||
// Fetch symbol
|
||
apropName->an_gsn = gsn; // Save segment definition number
|
||
apropName->an_ggr = ggrDGroup;
|
||
// Save group definition number
|
||
MARKVP(); // Page has changed
|
||
}
|
||
else if (fNoEnd && papropSn->as_rCla == rhteStack)
|
||
{
|
||
fNoEnd = FALSE;
|
||
apropName = (APROPNAMEPTR )
|
||
PropSymLookup((BYTE *) "\004_end",ATTRPNM,FALSE);
|
||
// Fetch symbol
|
||
apropName->an_gsn = gsn; // Save segment definition number
|
||
apropName->an_ggr = ggrDGroup;
|
||
// Save group definition number
|
||
MARKVP(); // Page has changed
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*** Check_edata_end - check the definiton of special C run-time symbols
|
||
*
|
||
* Purpose:
|
||
* Check the definition of special symbols _edata and _end used
|
||
* by the C run-time.
|
||
*
|
||
* Input:
|
||
* None.
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
* Exceptions:
|
||
* None.
|
||
*
|
||
* Notes:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
|
||
void NEAR Check_edata_end(SNTYPE gsnTop, SEGTYPE segTop)
|
||
{
|
||
APROPNAMEPTR apropName; // Public name pointer
|
||
APROPNAMEPTR apropName1; // Public name pointer
|
||
|
||
|
||
// Check if both symbols are defined properly
|
||
|
||
if (fNoEdata)
|
||
{
|
||
// No class 'BSS' segment defined;
|
||
// make _edata point to end of 'DATA' segments
|
||
|
||
apropName = (APROPNAMEPTR )
|
||
PropSymLookup((BYTE *) "\006_edata",ATTRPNM,FALSE);
|
||
// Fetch symbol
|
||
if (fNoEnd)
|
||
{
|
||
// No class 'STACK' segment defined;
|
||
// set _edata to end of DGROUP
|
||
|
||
if (fNewExe)
|
||
{
|
||
apropName->an_gsn = mpggrgsn[ggrDGroup];
|
||
// Save segment definition number
|
||
apropName->an_ggr = ggrDGroup;
|
||
// Save group definition number
|
||
apropName->an_ra = mpsacb[mpsegsa[mpgsnseg[apropName->an_gsn]]];
|
||
// Save 'DATA' segments size
|
||
}
|
||
#if NOT EXE386
|
||
else
|
||
{
|
||
apropName->an_gsn = gsnTop;
|
||
apropName->an_ggr = ggrDGroup;
|
||
apropName->an_ra = mpsegcb[segTop];
|
||
}
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
// set _edata to _end
|
||
|
||
apropName1 = (APROPNAMEPTR )
|
||
PropSymLookup((BYTE *) "\004_end",ATTRPNM,FALSE);
|
||
// Fetch symbol
|
||
apropName->an_gsn = apropName1->an_gsn;
|
||
// Save segment definition number
|
||
apropName->an_ggr = apropName1->an_ggr;
|
||
// Save group definition number
|
||
apropName->an_ra = apropName1->an_ra;
|
||
// Save 'DATA' segments size
|
||
}
|
||
MARKVP(); // Page has changed
|
||
}
|
||
|
||
if (fNoEnd)
|
||
{
|
||
// No class 'STACK' segment defined;
|
||
// make _end point to end of 'BSS' or 'DATA' segments
|
||
|
||
apropName = (APROPNAMEPTR )
|
||
PropSymLookup((BYTE *) "\004_end",ATTRPNM,FALSE);
|
||
// Fetch symbol
|
||
if (fNewExe)
|
||
{
|
||
apropName->an_gsn = mpggrgsn[ggrDGroup];
|
||
// Save segment definition number
|
||
apropName->an_ggr = ggrDGroup;
|
||
// Save group definition number
|
||
apropName->an_ra = mpsacb[mpsegsa[mpgsnseg[apropName->an_gsn]]];
|
||
// Save 'BSS' segments size
|
||
}
|
||
#if NOT EXE386
|
||
else
|
||
{
|
||
apropName->an_gsn = gsnTop;
|
||
apropName->an_ggr = ggrDGroup;
|
||
apropName->an_ra = mpsegcb[segTop];
|
||
}
|
||
#endif
|
||
MARKVP(); // Page has changed
|
||
}
|
||
|
||
// Make __end and __edata the same as _end and _edata
|
||
|
||
apropName = (APROPNAMEPTR ) PropSymLookup((BYTE *) "\006_edata",ATTRPNM,FALSE);
|
||
apropName1 = (APROPNAMEPTR ) PropSymLookup((BYTE *) "\007__edata",ATTRPNM,TRUE);
|
||
apropName1->an_gsn = apropName->an_gsn;
|
||
apropName1->an_ggr = apropName->an_ggr;
|
||
apropName1->an_ra = apropName->an_ra;
|
||
|
||
apropName = (APROPNAMEPTR ) PropSymLookup((BYTE *) "\004_end",ATTRPNM,FALSE);
|
||
apropName1 = (APROPNAMEPTR ) PropSymLookup((BYTE *) "\005__end",ATTRPNM,TRUE);
|
||
apropName1->an_gsn = apropName->an_gsn;
|
||
apropName1->an_ggr = apropName->an_ggr;
|
||
apropName1->an_ra = apropName->an_ra;
|
||
}
|