/* 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 /* Types and constants */ #include /* Types and constants */ #include /* Reloc. type definitions */ #include /* Linker I/O definitions */ #include /* DOS & 286 .EXE data structures */ #if EXE386 #include /* 386 .EXE data structures */ #endif #include /* Error messages */ #include /* 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; }