mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1175 lines
42 KiB
1175 lines
42 KiB
/* 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;
|
|
}
|