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

1176 lines
42 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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;
}