/* * Copyright Microsoft Corporation, 1983-1989 * * This Module contains Proprietary Information of Microsoft * Corporation and should be treated as Confidential. */ /* Addressing frame for segmented executable */ /* * NEWMAP5.C */ #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 declarations */ #if NOT EXE386 #define SEGTOPADDR ((WORD)0xffff) #endif /* * AssignSegAddr: * * Assign addresses for a segmented-executable format program. * Called by AssignAddresses. */ void NEAR AssignSegAddr() { REGISTER SNTYPE gsn; REGISTER SEGTYPE seg; APROPSNPTR papropSn; ALIGNTYPE align; GRTYPE ggr; SEGTYPE segTop; AHTEPTR pahte; /* Pointer to group name hte */ DWORD sacb; /* Physical segment ("frame") size */ SEGTYPE segi; /* Segment index */ DWORD CurrentPackLim; WORD fMixed; // TRUE if mixing use16 with use32 allowed WORD fUse16; // TRUE if group is use16 #if FALSE AND NOT EXE386 WORD ShiftDelta; #endif segTop = 0; saMac = 1; /* Initialize counter */ #if EXE386 if (ggrFlat) mpggrgsn[ggrFlat] = gsnMac; /* Mark base of pseudo-group */ #endif for(seg = 1; seg <= segLast; ++seg) /* Loop to combine segments */ { if(saMac >= SAMAX) Fatal(ER_fsegmax); /* Check for table overflow */ mpsegsa[seg] = saMac; /* Save phys. seg. in table */ mpsegraFirst[seg] = 0; /* First byte at offset zero */ mpgsndra[mpseggsn[seg]] = 0; /* First byte at offset zero */ papropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[mpseggsn[seg]],FALSE); /* Look up segment definition */ sacb = papropSn->as_cbMx; /* Save initial phys. seg. size */ mpsacb[saMac] = sacb; /* Save in table also */ mpsaflags[saMac] = papropSn->as_flags; /* Save the flags */ mpsacbinit[saMac] = 0L; /* Initialize */ mpsaRlc[saMac] = NULL; /* Initialize */ ggr = papropSn->as_ggr; /* Get global GRPDEF index */ if (ggr != GRNIL) /* If we've found a group member */ { fUse16 = !Is32BIT(papropSn->as_flags); fMixed = (papropSn->as_fExtra & MIXED1632); mpggrgsn[ggr] = mpseggsn[seg]; /* Remember base of group */ for (segTop = segLast; segTop > seg; --segTop) { /* Loop to find highest member */ papropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[mpseggsn[segTop]],FALSE); /* Get segment definition */ if (ggr == papropSn->as_ggr) break; /* Break loop when found */ } } else if (gsnAppLoader && mpseggsn[seg] == gsnAppLoader) { // Don't pack aplication loader with other CODE segments segTop = seg; } #if EXE386 else if (gsnImport && mpseggsn[seg] == gsnImport) { // Don't pack IAT segment with other DATA segments segTop = seg; } #endif else if (packLim != 0L && IsCodeFlg(papropSn->as_flags)) { /* If packing code segments */ segTop = segCodeLast; /* Pack as much code as possible */ #if EXE386 if (!Is32BIT(papropSn->as_flags)) CurrentPackLim = LXIVK - 36; else #endif CurrentPackLim = packLim; } else if(DataPackLim != 0L && IsDataFlg(papropSn->as_flags)) { /* If packing data segments */ segTop = segDataLast; /* Pack as much data as possible */ #if EXE386 if (!Is32BIT(papropSn->as_flags)) CurrentPackLim = LXIVK; else #endif CurrentPackLim = DataPackLim; } else segTop = seg; /* Else stop with current segment */ for(segi = seg + 1; segi <= segTop; ++segi) { /* Loop to end of group */ papropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[mpseggsn[segi]],FALSE); /* Get segment definition */ if (!fMixed && papropSn->as_ggr != GRNIL) fMixed = (papropSn->as_fExtra & MIXED1632); // Check if mixing use16 // and use32 for group allowed if(papropSn->as_ggr != ggr && papropSn->as_ggr != GRNIL) { /* If groups do not match */ if(ggr == GRNIL) /* If not in a true group */ { segTop = segi - 1; /* Stop after last segment */ break; /* Exit loop */ } /* Output warning message */ OutWarn(ER_grpovl, 1 + GetPropName(FetchSym(mpggrrhte[ggr],FALSE)), 1 + GetPropName(FetchSym(mpggrrhte[papropSn->as_ggr],FALSE))); } if(IsIOPL(mpsaflags[saMac]) != IsIOPL(papropSn->as_flags)) { /* Don't pack IOPL with NIOPL */ if (ggr == GRNIL) { /* Not a members of any group - stop packing */ segTop = segi - 1; break; } else { /* Issue error and continue */ pahte = (AHTEPTR ) FetchSym(mpggrrhte[ggr],FALSE); /* Get hash table entry */ OutError(ER_iopl, 1 + GetPropName(papropSn), 1 + GetFarSb(pahte->cch)); } } #if EXE386 if(Is32BIT(mpsaflags[saMac]) != Is32BIT(papropSn->as_flags)) { /* Don't pack 32-bit segments with 16-bit segments */ if (ggr == GRNIL) { /* Not a members of any group - stop packing */ segTop = segi - 1; break; } else if (!fMixed) { /* Issue error and continue */ pahte = (AHTEPTR ) FetchSym(mpggrrhte[ggr],FALSE); /* Get hash table entry */ OutError(ER_32_16_bit, 1 + GetPropName(papropSn), 1 + GetFarSb(pahte->cch)); } } #endif if (IsDataFlg(mpsaflags[saMac]) && IsDataFlg(papropSn->as_flags)) { // If we are packing DATA segments, check NSSHARED bit #if EXE386 if (IsSHARED(mpsaflags[saMac]) != IsSHARED(papropSn->as_flags)) #else if ((mpsaflags[saMac] & NSSHARED) != (papropSn->as_flags & NSSHARED)) #endif { // Don't pack SHARED with NONSHARED data segments if (ggr == GRNIL) { // Not a members of any group - stop packing segTop = segi - 1; break; } else { // Issue error and continue pahte = (AHTEPTR ) FetchSym(mpggrrhte[ggr],FALSE); OutError(ER_shared, 1 + GetPropName(papropSn), 1 + GetFarSb(pahte->cch)); } } } mpsegsa[segi] = saMac; /* Assign phys. seg. to segment */ /* Fix the flags */ #if EXE386 if (IsCODEOBJ(mpsaflags[saMac]) && !IsCODEOBJ(papropSn->as_flags)) #else if((mpsaflags[saMac] & NSTYPE) != (papropSn->as_flags & NSTYPE)) #endif { /* If types do not agree */ /* If packing code or data segs, stop current packing group. * But allow program to explicitly group code and data. */ if(ggr == GRNIL) { segTop = segi - 1; break; } #if EXE386 else { /* Issue warning and convert segment type */ WORD warningKind; if (IsCODEOBJ(papropSn->as_flags)) warningKind = ER_codeindata; else warningKind = ER_dataincode; pahte = (AHTEPTR ) FetchSym(mpggrrhte[ggr],FALSE); /* Get hash table entry */ OutWarn(warningKind, 1 + GetPropName(papropSn), 1 + GetFarSb(pahte->cch)); } #else mpsaflags[saMac] &= (~NSSHARED & ~NSTYPE); mpsaflags[saMac] |= NSCODE; /* Set type to impure code */ #endif } #if EXE386 else if (!IsSHARED(papropSn->as_flags)) mpsaflags[saMac] &= ~OBJ_SHARED; #else else if(!(papropSn->as_flags & NSSHARED)) mpsaflags[saMac] &= ~NSSHARED; #endif /* Turn off pure bit if impure */ #if EXE386 if (!IsREADABLE(papropSn->as_flags)) mpsaflags[saMac] &= ~OBJ_READ; #else #if O68K if((papropSn->as_flags & (NSMOVE | NSPRELOAD | NSEXRD)) != (mpsaflags[saMac] & (NSMOVE | NSPRELOAD | NSEXRD))) { if(ggr == GRNIL) { segTop = segi - 1; break; } else #else { #endif { if(!(papropSn->as_flags & NSMOVE)) mpsaflags[saMac] &= ~NSMOVE; /* Turn off movable bit if fixed */ if(papropSn->as_flags & NSPRELOAD) mpsaflags[saMac] |= NSPRELOAD; /* Set preload bit if preloaded */ if (!(papropSn->as_flags & NSEXRD)) mpsaflags[saMac] &= ~NSEXRD; /* Turn off execute/read-only */ } } #endif /* Adjust alignment */ align = (ALIGNTYPE) ((papropSn->as_tysn >> 5) & 7); /* Get alignment type */ switch(align) /* Switch on alignment type */ { case ALGNWRD: /* Word-aligned */ sacb = (sacb + 1) & ~1L; /* Round up size to word boundary */ break; #if OMF386 case ALGNDBL: /* Double word-aligned */ sacb = (sacb + 3) & ~3L; /* Round up to dword offset */ break; #endif case ALGNPAR: /* Paragraph-aligned */ sacb = (sacb + 0xF) & ~0xFL; /* Round up size to para boundary */ break; case ALGNPAG: /* Page-aligned */ sacb = (sacb + 0xFF) & ~0xFFL; /* Round up size to page boundary */ break; } mpsegraFirst[segi] = sacb; /* Save offset of first byte */ mpgsndra[mpseggsn[segi]] = sacb; /* Save offset of first byte */ sacb += papropSn->as_cbMx; /* Increment size of file segment */ #if NOT EXE386 if(ggr != GRNIL) /* If true group */ { if (fMixed && !fUse16) { pahte = (AHTEPTR ) FetchSym(mpggrrhte[ggr],FALSE); /* Get hash table entry */ OutWarn(ER_mixgrp32, 1 + GetFarSb(pahte->cch)); } if(sacb > LXIVK || (IsCodeFlg(mpsaflags[saMac]) && sacb > LXIVK - 36)) { /* If group overflow or unreliable */ pahte = (AHTEPTR ) FetchSym(mpggrrhte[ggr],FALSE); /* Get hash table entry */ if(sacb > LXIVK) Fatal(ER_grpovf,1 + GetFarSb(pahte->cch)); else OutWarn(ER_codunsf,1 + GetFarSb(pahte->cch)); } } else #endif if(sacb > CurrentPackLim)/* Else if packing limit exceeded */ { segTop = segi - 1; /* Set top to last segment that fit */ break; /* Break inner loop */ } mpsacb[saMac] = sacb; /* Update file segment size */ } #if NOT EXE386 /* * Make DGROUP segment flags conform to auto data. It is assumed * that all conflicts have been resolved earlier. */ if(ggr == ggrDGroup) { if(vFlags & NESOLO) mpsaflags[saMac] |= NSSHARED; else if(vFlags & NEINST) mpsaflags[saMac] &= ~NSSHARED; } #if FALSE if (IsDataFlg(mpsaflags[saMac]) && (mpsaflags[saMac] & NSEXPDOWN)) { /* If this is data segment and NSEXPDOWN big is set - shitf it up */ ShiftDelta = SEGTOPADDR - mpsacb[saMac]; for (segi = seg; segi <= segTop; segi++) { mpsegraFirst[segi] += ShiftDelta; mpgsndra[mpseggsn[segi]] += ShiftDelta; } } #endif #endif if(mpsacb[saMac] != 0L) ++saMac; seg = segTop; /* Set counter appropriately */ } /* We haven't yet assigned absolute segments (it is assumed * they are empty and are used only for addressing purposes), * but now we must assign them somewhere. */ segTop = segLast; /* Initialize */ for(gsn = 1; gsn < gsnMac; ++gsn) /* Loop to complete initialization */ { papropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn],TRUE); /* Get symbol table entry */ seg = mpgsnseg[gsn]; /* Get segment number */ if(seg == SEGNIL) /* If we have an absolute segment */ { mpgsnseg[gsn] = ++segTop; /* Assign a segment order number */ mpsegsa[segTop] = (SATYPE) papropSn->as_cbMx; /* Assign absolute segs their loc. */ } /* Define special symbols "_edata" and "_end" */ if (fSegOrder) Define_edata_end(papropSn); } if (fSegOrder) Check_edata_end(0, 0); #if O68K /* The Macintosh addresses data as a negative offset to the A5 register. This limits "near" data to within 32k of A5; "far" data is defined as anything beyond the 32k limit and requires special addressing to reach it. To fold this into the standard linker model, the Macintosh post-processor treats the first data segment as "near" data and all subsequent data segments as "far". Thus, N data segments are arranged as follows: A5 -> +----------+ High memory | DATA 0 | +----------+ | DATA N | +----------+ | DATA N-1 | +----------+ | . | | . | | . | +----------+ | DATA 2 | +----------+ | DATA 1 | +----------+ Low memory Consequently, we must calculate the displacment from the start of each data segment to its ultimate place in memory relative to A5. */ if (iMacType != MAC_NONE) { RATYPE draDP; SATYPE sa; SATYPE saDataFirst; draDP = -((mpsacb[saDataFirst = mpsegsa[mpgsnseg[mpggrgsn[ggrDGroup]]]] + 3L) & ~3L); mpsadraDP[saDataFirst] = draDP; for (sa = mpsegsa[segDataLast]; sa > saDataFirst; sa--) draDP = mpsadraDP[sa] = draDP - ((mpsacb[sa] + 3L) & ~3L); } #endif }