/* * TITLE * newfix.c * Pete Stewart * (C) Copyright Microsoft Corp 1984-89 * 12 October 1984 * * DESCRIPTION * This file contains routines for the linker that * read and interpret fixup records during the second * pass of the linking process. * */ #include /* Types and constants */ #include /* Basic types and constants */ #include /* Relocation definitions */ #include /* Linker I/O definitions */ #include /* DOS & 286 .EXE format structure def.s */ #if EXE386 #include /* 386 .EXE format structure def.s */ #include /* Linker internal fixup representation */ #endif #include /* Error messages */ #include /* External declarations */ #include /* Near message strings */ #define RelocWarn(a,b,c,d,e) FixErrSub(a,b,c,d,e,(FTYPE)FALSE) #define RelocErr(a,b,c,d,e) FixErrSub(a,b,c,d,e,(FTYPE)TRUE) #define FixupOverflow(a,b,c,d) RelocErr(ER_fixovf,a,b,c,d) #define IsSELECTED(x) ((x)&SELECTED_BIT) __inline void addword(BYTE *pdata, WORD w) // add a word to the word at location pdata... enforce little endian add // even if linker hosted on a big endian machine { w += pdata[0] + (pdata[1]<>BYTELN); } #if defined( _WIN32 ) #define fixword(x,y) ((*(WORD UNALIGNED *)(x)) = (WORD)(y)) #define fixdword(x,y) ((*(DWORD UNALIGNED *)(x)) = (DWORD)(y)) #else #if M_I386 #define fixword(x,y) ((*(WORD *)(x)) = (WORD)(y)) #define fixdword(x,y) ((*(DWORD *)(x)) = (DWORD)(y)) #else #define fixword(x,y) ((x)[0]) = (BYTE)(y); \ ((x)[1]) = (BYTE)((y) >> BYTELN); #define fixdword(x,y) ((x)[0]) = (BYTE)(y); \ ((x)[1]) = (BYTE)((y) >> BYTELN); \ ((x)[2]) = (BYTE)((y) >> (BYTELN*2)); \ ((x)[3]) = (BYTE)((y) >> (BYTELN*3)); #endif // NOT M_I386 #endif // NOT _WIN32 #if OSEGEXE extern RLCPTR rlcLidata; /* Pointer to LIDATA fixup array */ extern RLCPTR rlcCurLidata; /* Pointer to current LIDATA fixup */ # if ODOS3EXE OR defined(LEGO) #define DoFixup (*pfProcFixup) # else #if EXE386 #define DoFixup Fix386 #else #define DoFixup FixNew #endif # endif #else #define DoFixup FixOld #endif #if NOT ODOS3EXE #define fNoGrpAssoc FALSE #endif WORD mpthdidx[RLCMAX]; /* f(thread) = tgt index */ KINDTYPE mpthdmtd[RLCMAX]; /* f(thread) = tgt method */ LOCAL WORD mpthdfidx[RLCMAX]; /* f(thread) = frm index */ LOCAL KINDTYPE mpthdfmtd[RLCMAX]; /* f(thread) = frm method */ FIXINFO fi; /* Fixup information record */ #if EXE386 LOCAL RATYPE objraCur; /* Current offset in object */ #endif #if POOL_BAKPAT LOCAL void * poolBakpat; #endif /* * FUNCTION PROTOTYPES */ LOCAL void NEAR GetFixdat(void); LOCAL unsigned char NEAR GetFixup(void); #if OSEGEXE LOCAL void NEAR SaveLiRel(RLCPTR pr); LOCAL RATYPE NEAR FinishRlc(RLCPTR r, unsigned short sa, RATYPE ra); #if NOT EXE386 #if O68K LOCAL WORD NEAR GetFixupWord(BYTE *); LOCAL DWORD NEAR GetFixupDword(BYTE *); #else /* NOT O68K */ #define GetFixupWord getword #define GetFixupDword getdword #endif /* NOT O68K */ #endif /* NOT EXE386 */ #endif /* OSEGEXE */ LOCAL unsigned char NEAR lastbyte(unsigned char *pdata, RATYPE ra, unsigned char optest, unsigned char opnew); LOCAL void NEAR Getgsn(unsigned char kind, unsigned short idx, unsigned short *pgsn, RATYPE *pra); LOCAL unsigned char NEAR TransFAR(unsigned char *pdata, RATYPE ra, RATYPE raTarget); LOCAL void NEAR StartAddrOld(void); LOCAL unsigned short NEAR Mpgsnosn(unsigned short gsn); LOCAL void NEAR GetFrameTarget(unsigned short *pgsnFrame, unsigned short *pgsnTarget, RATYPE *praTarget); #if EXE386 LOCAL void NEAR Fix386(); #endif #if ODOS3EXE LOCAL WORD NEAR InOneGroup(WORD gsnTarget, WORD gsnFrame); #endif LOCAL WORD NEAR CallGateRequired(SATYPE saTarget); extern void AddTceEntryPoint( APROPCOMDAT *pC ); /* * GetFixdat: * * Process the FIXDAT byte of a FIXUPP record. */ LOCAL void NEAR GetFixdat() { REGISTER WORD fixdat; /* The FIXDAT byte */ WORD i; /* Temporary index */ fixdat = Gets(); /* Get FIXDAT byte */ i = (WORD) ((fixdat >> 4) & 7); /* Get frame info */ if (fixdat & F_BIT) /* If frame thread-specified */ { i &= 3; /* Threads numbered from 0 to 3 */ fi.f_fmtd = mpthdfmtd[i]; /* Get method */ fi.f_fidx = mpthdfidx[i]; /* Get index */ } else /* Else if frame explicit */ { fi.f_fmtd = (KINDTYPE) i; /* Save frame method */ switch(i) /* Switch on frame method */ { case F0: /* Index to get */ fi.f_fidx = GetIndex(1, (WORD) (snMac - 1)); break; case F1: fi.f_fidx = GetIndex(1, (WORD) (grMac - 1)); break; case F2: fi.f_fidx = (WORD) (GetIndex(1, EXTMAX) + QCExtDefDelta); if (fi.f_fidx >= extMac) InvalidObject(); break; case F3: /* Frame number to punt */ WGets(); break; case F4: /* Nothing to get */ case F5: break; default: /* Invalid object */ InvalidObject(); } } i = (WORD) (fixdat & 3); /* Get target info */ if (fixdat & T_BIT) /* If target given by thread */ { fi.f_mtd = mpthdmtd[i]; /* Get method */ fi.f_idx = mpthdidx[i]; /* Get index */ } else /* Else if target explicit */ { fi.f_mtd = (KINDTYPE ) i; /* Save the method */ ASSERT(fi.f_mtd != 3); /* Unimplemented method */ fi.f_idx = GetIndex(1, EXTMAX); /* Get the index */ if (fi.f_mtd == 2) { fi.f_idx += (WORD) QCExtDefDelta; if (fi.f_idx >= extMac) InvalidObject(); } } #if OMF386 if(rect&1) fi.f_disp = (fixdat & P_BIT) ? 0L : LGets(); else #endif fi.f_disp = (DWORD) ((fixdat & P_BIT) ? 0 : WGets()); /* Get displacement, if any */ } /* * GetFixup: * * Read and interpret a fixup record, storing the information in * a buffer. * Returns TRUE if fixup, FALSE if thread definition. */ LOCAL FTYPE NEAR GetFixup() { REGISTER WORD key; /* Key byte */ WORD cbData; /* End point */ key = Gets(); /* Get key byte */ if(!(key & THREAD_BIT)) /* If thread definition */ { fi.f_mtd = (KINDTYPE ) ((key >> 2) & 7); /* Get the thread method */ ASSERT(fi.f_mtd != 3); /* Unimplemented */ /* * If target thread, take modulo 4 of method. Primary/secondary * not specified by thread. */ if(!(key & D_BIT)) fi.f_mtd &= 3; switch(fi.f_mtd) /* Switch on the thread method */ { case 0: /* Thread specifies an index */ fi.f_idx = GetIndex(1, (WORD) (snMac - 1)); break; case 1: fi.f_idx = GetIndex(1, (WORD) (grMac - 1)); break; case 2: fi.f_idx = (WORD) (GetIndex(1, EXTMAX) + QCExtDefDelta); /* Get index */ if (fi.f_idx >= extMac) InvalidObject(); break; case 3: /* Frame number (unimplemented) */ WGets(); /* Skip the frame number */ break; case 4: /* No thread datum */ case 5: break; default: /* Error */ InvalidObject(); /* Die gracefully */ } if(!(key & D_BIT)) /* If we have a target thread */ { key &= 3; /* Get thread number */ mpthdmtd[key] = fi.f_mtd; /* Get method */ mpthdidx[key] = fi.f_idx; /* Get index */ } else /* If we have a frame thread */ { key &= 3; /* Get thread number */ mpthdfmtd[key] = fi.f_mtd;/* Get method */ mpthdfidx[key] = fi.f_idx;/* Get index */ } return((FTYPE) FALSE); /* Not a fixup */ } /* * At this point, we know we have a fixup to perform. */ /* Get fixup location type */ #if EXE386 fi.f_loc = (WORD) ((key >> 2) & NRSTYP); #else #if OMF386 if(rect & 1) fi.f_loc = (key >> 2) & NRSTYP; else #endif fi.f_loc = (key >> 2) & 7; #endif fi.f_self = (FTYPE) ((key & M_BIT)? FALSE: TRUE); /* Get fixup mode */ fi.f_dri = (WORD) (((key & 3) << 8) + Gets()); /* Get data record index */ cbData = vcbData; /* Check if location goes beyond end of data record. */ switch(fi.f_loc) { case LOCOFFSET: case LOCLOADOFFSET: case LOCSEGMENT: --cbData; break; case LOCPTR: #if OMF386 case LOCOFFSET32: case LOCLOADOFFSET32: #endif cbData -= 3; break; #if OMF386 case LOCPTR48: cbData -= 5; break; #endif } if(fi.f_dri >= cbData) Fatal(ER_badobj); GetFixdat(); /* Process FIXDAT byte */ #if TCE if(!vfPass1) #endif fi.f_add = !!*(WORD UNALIGNED *)(rgmi + fi.f_dri); /* Check if fixup is additive */ return((FTYPE ) TRUE); /* This is a fixup */ } /**************************************************************** * * * FixErrSub: * * * * Report a fixup error. * * * ****************************************************************/ void NEAR FixErrSub(msg,ra,gsnFrame,gsnTarget,raTarget,fErr) MSGTYPE msg; /* Error message */ RATYPE ra; /* Relative addr of error */ SNTYPE gsnFrame; SNTYPE gsnTarget; RATYPE raTarget; FTYPE fErr; /* True if increment err cnt */ { BYTE *sb; /* Pointer to name */ #if EXE386 char *kind; #endif if (fDebSeg) return; // Ignore warnings/errors for CV info for(;;) /* Loop to give message */ { sb = 1 + GetFarSb(GetHte(mpgsnrprop[vgsnCur])->cch); #if EXE386 if(fErr) OutError(msg,ra - mpsegraFirst[mpgsnseg[vgsnCur]],sb); else OutWarn(msg,ra - mpsegraFirst[mpgsnseg[vgsnCur]],sb); switch(fi.f_loc) { case LOCSEGMENT: kind = "Selector"; break; case LOCPTR: kind = "16:16 pointer"; break; case LOCPTR48: kind = "16:32 pointer"; break; default: kind = ""; break; } if(fi.f_mtd == KINDEXT && mpextprop && mpextprop[fi.f_idx]) FmtPrint(" %s '%s'\r\n",__NMSG_TEXT(N_tgtexternal), 1 + GetPropName(FetchSym(mpextprop[fi.f_idx],FALSE))); else if (gsnTarget) { /* Output frame, target info */ FmtPrint(" %s: %s %s, %s %lx\r\n", kind, __NMSG_TEXT(N_tgtseg), 1 + GetPropName(FetchSym(mpgsnrprop[gsnTarget],FALSE)), __NMSG_TEXT(N_tgtoff), (RATYPE) raTarget); } #else if(fErr) OutError(msg,ra - mpgsndra[vgsnCur],sb); else OutWarn(msg,ra - mpgsndra[vgsnCur],sb); if(fi.f_mtd == KINDEXT && mpextprop && mpextprop[fi.f_idx]) FmtPrint(" %s '%s'\r\n",__NMSG_TEXT(N_tgtexternal), 1 + GetPropName(FetchSym(mpextprop[fi.f_idx],FALSE))); else if(gsnFrame && gsnTarget) { /* Output frame, target info */ FmtPrint(" %s %s", __NMSG_TEXT(N_frmseg), 1 + GetPropName(FetchSym(mpgsnrprop[gsnFrame], FALSE))); FmtPrint(", %s %s", __NMSG_TEXT(N_tgtseg), 1 + GetPropName(FetchSym(mpgsnrprop[gsnTarget], FALSE))); FmtPrint(", %s %lX\r\n", __NMSG_TEXT(N_tgtoff), (RATYPE) raTarget); } #endif if(!fLstFileOpen || bsErr == bsLst) break; /* Exit loop */ bsErr = bsLst; /* Insure loop exit */ } if (fLstFileOpen && fErr) cErrors--; // We called OutError twice for one error bsErr = stderr; } #if OSEGEXE /* * SaveLiRel : Save an LIDATA relocation record */ LOCAL void NEAR SaveLiRel (pr) RLCPTR pr; /* Generic relocation record */ { #if EXE386 LE_SOFF(*pr) = (WORD) (objraCur - vraCur); #else NR_SOFF(*pr) -= (WORD) vraCur; /* Save offset within LIDATA record */ #endif if((char *) rlcCurLidata > (char *) &rgmi[DATAMAX - sizeof(RELOCATION)]) { /* If too many fixups */ OutError(ER_fixmax); /* Output error message */ return; /* Try next fixup */ } FMEMCPY(rlcCurLidata++, pr, sizeof(RELOCATION)); /* Copy relocation into buffer */ } /* HERE ARE THE RULES USED BY LINKER TO GENERATE ENTRY POINTS: * * +----+-------------+-------------+-------------+-------------+-------------+ * | \ | | | | | * | \ referenced | data | code | code ring 2 | code ring 2 | * |entry \ from | any ring | ring 3 |nonconforming| conforming | * |point \ | | | | | * |target \---------+-------------+-------------+-------------+-------------+ * | | | | | | * |data | no entry | no entry | no entry | no entry | * |nonexported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * | | | | | | * |data | fixed entry | fixed entry | fixed entry | fixed entry | * |exported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * | | | | | | * |code ring 3 | no entry(1)| no entry(1)| invalid | invalid | * |nonexported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * | | | | | | * |code ring 3 | fixed entry | fixed entry | invalid | invalid | * |exported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * |code ring 2 | | | | | * |nonconforming |movable entry|movable entry| no entry(1)|movable entry| * |nonexported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * |code ring 2 | | | | | * |nonconforming |movable entry|movable entry| fixed entry |movable entry| * |exported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * |code ring 2 | | | | | * |conforming | no entry(1)| no entry(1)| no entry(1)| no entry(1)| * |nonexported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * |code ring 2 | | | | | * |conforming | fixed entry | fixed entry | fixed entry | fixed entry | * |exported | | | | | * |------------------+-------------+-------------+-------------+-------------+ * * (1) If the entry point requires windows compatable prolog editing then * this entry point must be defined as a "fixed entry". * * * Forget about the note, (1), for now. I don't think it applies with * PROTMODE. * Ring 2 means IOPL, ring 3 means NOIOPL. * To simplify the code we are taking advantage of segment attributes. * I.e. force all the following segments to FIXED: * data * code ring 3 * code ring 2, conforming * force to MOVABLE: * code ring 2, nonconforming * Then just use the segment attribute to determine what type of entry * to generate. There are clearly two exceptions that you must check * for: * - code ring 2 nonconforming nonexported, referenced by code ring 2 nonconforming * - code ring 2 nonconforming exported, referenced by code ring 2 nonconforming * */ #if NOT QCLINK /*** CallGateRequired - check if call gate required * * Purpose: * Check if call gate is required for given target segment. * * Input: * saTarget - fixup target segment (memory object) * * Output: * Returns TRUE if call gate required, othrewise FALSE. * * Exceptions: * None. * * Notes: * None. * *************************************************************************/ LOCAL WORD NEAR CallGateRequired(SATYPE saTarget) { #if EXE386 return(FALSE); #else register WORD flags; flags = mpsaflags[saTarget]; if ((vFlags & NEPROT) || TargetOs == NE_OS2) { // If the target entry point segment is NONCONFORMING IOPL CODE 16-bit // and current segment is a different type, generate a callgate return(IsCodeFlg(flags) && NonConfIOPL(flags) && mpsaflags[mpsegsa[vsegCur]] != flags); } else { // If target segment is non-absolute and movable, generate // a movable-type fixup and a corresponding entry table entry: return(flags & NSMOVE); } #endif } #endif /* * FinishRlc: * * Finish processing a relocation for a segmented-exe. */ LOCAL RATYPE NEAR FinishRlc(r,sa,ra) RLCPTR r; /* Relocation record to finish */ SATYPE sa; /* Target file segment number */ RATYPE ra; /* Target offset */ { if (!sa || sa >= saMac) return(ra); /* Something is wrong */ #if NOT EXE386 #if NOT QCLINK if (CallGateRequired(sa)) { NR_SEGNO(*r) = BNDMOV; /* Reference is to movable segment */ NR_ENTRY(*r) = MpSaRaEto(sa,ra);/* Save Entry Table ordinal */ } else { NR_SEGNO(*r) = (BYTE) sa; /* Reference is to fixed segment */ if ( #ifdef LEGO #if OSEGEXE !fKeepFixups && #endif #endif /* LEGO */ ((NR_STYPE(*r) & NRSTYP) == NRSSEG)) NR_ENTRY(*r) = (WORD) 0; /* For non call-gate base fixups force offset to zero */ else { #if O68K if (iMacType != MAC_NONE && IsDataFlg(mpsaflags[sa])) NR_ENTRY(*r) = (WORD) (ra - mpsadraDP[sa]); /* Save offset into fixed segment */ else #endif /* O68K */ NR_ENTRY(*r) = (WORD) ra; /* Save offset into fixed segment */ } } #else NR_SEGNO(*r) = (BYTE) sa; /* Reference is to fixed segment */ NR_ENTRY(*r) = (WORD) ra; /* Save offset into fixed segment */ #endif #else if (sa == SANIL) { RelocWarn(ER_badfixflat,objraCur,SNNIL,0,ra); /* Oops ! - Flat relative refernce */ return((RATYPE)0); /* OS doesn't know object number zero */ } LE_OBJNO(*r) = sa; /* Target object number */ if (CallGateRequired(sa)) { NR_FLAGS(*r) |= NRRENT; LE_IATORD(*r) = MpSaRaEto(sa,ra); /* Save Entry Table ordinal */ } else { /* Target is internal reference */ if ((NR_STYPE(*r) & NRSTYP) == NRSSEG) ra = 0L; /* For non call-gate base fixups force offset to zero */ } LE_TOFF(*r) = ra; /* Target offset */ #endif if(TYPEOF(vrectData) == LIDATA) /* If we have an LIDATA record */ { SaveLiRel(r); /* Save LIDATA relocation record */ return(0); /* Nothing to add */ } #if EXE386 return(SaveFixup(mpsegsa[vsegCur],vpageCur,r)); #else return(SaveFixup(mpsegsa[vsegCur],r)); /* Save fixup, return chain */ #endif } #endif /* OSEGEXE */ /* * lastbyte: * * If the last byte before the current byte matches * optest, then replace it with opnew and return TRUE; * otherwise, return FALSE. */ LOCAL FTYPE NEAR lastbyte(pdata,ra,optest,opnew) BYTE *pdata; /* Pointer into data record */ RATYPE ra; /* Offset in current segment */ BYTE optest; /* Op code to test against */ BYTE opnew; /* New op code */ { BYTE FAR *pb; /* Byte pointer */ if(pdata > rgmi) /* If needed byte in buffer */ { if(pdata[-1] != optest) return(FALSE); /* Test fails if bytes differ */ pdata[-1] = opnew; /* Replace the op code */ return((FTYPE) TRUE); /* Test succeeds */ } if(ra == 0) return(FALSE); /* Test fails if no byte to test */ if(fNewExe) pb = mpsaMem[mpsegsa[vsegCur]] + ra - 1; /* Map in the desired byte */ else pb = mpsegMem[vsegCur] + ra - 1; /* Map in the desired byte */ if(*pb != optest) return(FALSE); /* Test fails if bytes differ */ *pb = opnew; /* Replace the op code */ markvp(); /* Page has changed */ return((FTYPE) TRUE); /* Test succeeds */ } #if OSEGEXE /* * DoIteratedFixups: * * Process fixups on an LIDATA record for a segmented-exe. */ void NEAR DoIteratedFixups(cb,pb) WORD cb; /* Byte count */ BYTE *pb; /* Byte pointer */ { RATYPE raChain; /* Fixup chain */ RATYPE raMin; /* Starting record offset */ RATYPE raMax; /* Ending record offset */ RLCPTR r; /* Relocation record */ WORD j; /* Index */ DWORD SrcOff; if(rlcCurLidata == rlcLidata) return; /* Nothing to do if no fixups */ raMin = (RATYPE)(pb - rgmi); /* Offset of start of data in record */ raMax = raMin + cb - 1; /* Offset of end of data in record */ r = rlcLidata; while (r < rlcCurLidata) { /* Do for all fixups in array */ #if EXE386 SrcOff = LE_SOFF(*r); #else SrcOff = (DWORD) NR_SOFF(*r); #endif if(SrcOff >= (DWORD) raMin && SrcOff <= (DWORD) raMax) { /* If fixup lies in range of data */ j = (WORD) (SrcOff - (DWORD) raMin); /* Get index off pb */ /* Calculate offset in segment */ #if EXE386 LE_SOFF(*r)= (WORD) ((vraCur + j) % (1 << pageAlign)); vpageCur = ((vraCur + j) >> pageAlign) + 1; raChain = SaveFixup(mpsegsa[vsegCur], vpageCur, r); /* Save the fixup reference */ #else NR_SOFF(*r) = (WORD) (vraCur + j); raChain = SaveFixup(mpsegsa[vsegCur],r); /* Save the fixup reference */ if(!(NR_FLAGS(*r) & NRADD)) { /* If not additive */ pb[j] = (BYTE) raChain; /* Set low byte of chain */ pb[j + 1] = (BYTE)(raChain >> BYTELN); /* Set high byte of chain */ } #endif /* Restore offset in record */ #if EXE386 LE_SOFF(*r)= (WORD) ((raMin + j) % (1 << pageAlign)); #else NR_SOFF(*r) = (WORD) (raMin + j); #endif } ((RLCPTR ) r)++; } } #endif /* OSEGEXE */ /* * Getgsn: * * Obtain segment number and offset for the given fixup method and index. * Return values are stored in pointers. */ LOCAL void NEAR Getgsn(kind,idx,pgsn,pra) KINDTYPE kind; /* Kind of index */ WORD idx; /* The index */ SEGTYPE *pgsn; /* gsn (ref) */ RATYPE *pra; /* ra (ref) */ { #if O68K SATYPE sa; #endif /* O68K */ switch(kind) /* Decide what to do */ { case KINDSEG: /* Segment index */ #if FALSE if(idx >= snMac) InvalidObject(); /* Make sure index not too big */ #endif *pgsn = mpsngsn[idx]; /* Get gsn */ *pra = mpgsndra[*pgsn]; /* Get ra */ #if O68K if (iMacType != MAC_NONE && IsDataFlg(mpsaflags[sa = mpsegsa[mpgsnseg[*pgsn]]])) *pra += mpsadraDP[sa]; /* Get data ra */ #endif /* O68K */ break; case KINDGROUP: /* Group index */ #if FALSE if(idx >= grMac) InvalidObject(); /* Make sure index not too big */ #endif *pgsn = mpggrgsn[mpgrggr[idx]]; /* Get gsn */ *pra = mpgsndra[*pgsn]; /* Get ra */ #if O68K if (iMacType != MAC_NONE && IsDataFlg(mpsaflags[sa = mpsegsa[mpgsnseg[*pgsn]]])) *pra += mpsadraDP[sa]; /* Get data ra */ #endif /* O68K */ break; case KINDEXT: /* External index */ #if FALSE if(idx >= extMac) InvalidObject(); /* Make sure index not too big */ #endif *pgsn = mpextgsn[idx]; /* Get gsn */ *pra = mpextra[idx]; /* Get ra */ break; default: /* All other kinds */ *pgsn = SEGNIL; /* No gsn */ *pra = 0; /* No ra */ break; } // If this is $$SYMBOLS segment then return logical offset // NOT physical offset if (fDebSeg) { #if O68K if (iMacType == MAC_NONE) #endif *pra -= mpsegraFirst[mpgsnseg[*pgsn]]; } } /* * TransFAR : Possibly translate an intra-segment FAR call or jump * * If the given location looks like a FAR call or jump, * translate it and return TRUE. Otherwise, do nothing and * return FALSE. */ LOCAL FTYPE NEAR TransFAR (pdata, ra, raTarget) BYTE *pdata; /* Pointer to fixup location */ RATYPE ra; /* Offset in current segment */ RATYPE raTarget; /* Target offset */ { #if O68K if (f68k) return FALSE; #else static RATYPE raPrev; static SATYPE saPrev; /* Location of the previous fixup */ if(raPrev + 4 == ra && saPrev == mpsegsa[vsegCur]) { if(!fOverlays) Fatal(ER_badfarcall); /* A far jump and/or ptr table present */ else return(FALSE); /* The user can't turn off /FARC in an overlaid .exe */ } else { raPrev = ra; saPrev = mpsegsa[vsegCur]; } if(lastbyte(pdata,ra,CALLFARDIRECT,NOP)) { /* If fixing up long call direct */ *pdata++ = PUSHCS; /* Push CS */ *pdata++ = CALLNEARDIRECT; /* Short call */ raTarget -= ra + 4; /* Make offset self-relative */ fixword(pdata, raTarget); /* store fixed up value */ return((FTYPE) TRUE); /* All done */ } else if(lastbyte(pdata,ra,JUMPFAR,JUMPNEAR)) { /* If long jump direct */ raTarget -= ra + 2; /* Make offset self-relative */ fixword(pdata, raTarget); /* store fixed up value */ pdata += 2; *pdata++ = NOP; /* Change base to NOPs */ *pdata = NOP; return((FTYPE) TRUE); /* All done */ } return(FALSE); #endif /* !O68K */ } #if EXE386 /* * Fix386: * * Procss a fixup for a linear-format exe. */ LOCAL void NEAR Fix386() { REGISTER BYTE *pdata; /* Pointer into data record */ RATYPE ra; /* Offset of location being fixed up */ SNTYPE gsnTarget; /* Target segment definition number */ SNTYPE gsnFrame; /* Frame segment definition number */ SEGTYPE segTarget; /* Target segment order number */ SATYPE saTarget; /* Target file segment number */ SATYPE saFrame; /* Frame file segment number */ RATYPE raTarget; /* Target offset */ RATYPE vBase; /* Target virtual base address - FLAT relative */ long vDist; /* Virtual distance between objects */ RATYPE raTmp; /* Temporary */ WORD dsa; /* Difference in sa's */ DWORD dummy; RELOCATION r; /* Relocation item */ WORD locType; /* Type of location to be fixed up */ WORD fFlatRelative; /* TRUE if frame of pseudo group FLAT */ APROPSNPTR apropSnSrc; /* Ptr to a segment record */ DWORD srcFlags; /* Source segment flags */ APROPNAMEPTR apropName; /* Ptr to import */ DWORD align; if (vgsnCur < gsnMac) { // Get source flags - only non-debug segments apropSnSrc = (APROPSNPTR ) FetchSym(mpgsnrprop[vgsnCur], FALSE); srcFlags = apropSnSrc->as_flags; } // Check for floating-point fixups here if(fi.f_mtd == T2 && ((mpextflags[fi.f_idx] & FFPMASK) || (mpextflags[fi.f_idx] & FFP2ND))) return; /* Ignore f.p. fixups */ align = (1L << pageAlign) - 1; memset(&r, 0, sizeof(struct le_rlc)); ra = vraCur + fi.f_dri; /* Get offset of fixup */ objraCur = ra; vpageCur = (ra >> pageAlign) + 1; /* Set object page number */ LE_SOFF(r) = (WORD) (ra & align); NR_STYPE(r) = (BYTE) fi.f_loc; /* Save fixup type */ #if FALSE if (vpageCur == 1 && mpsegsa[vsegCur] == 1) fprintf(stdout, "Processing fixup: type %02x; source offset %lx (page %x offset %x)\r\n", fi.f_loc, ra, vpageCur, LE_SOFF(r)); #endif pdata = &rgmi[fi.f_dri]; /* Set pointer to fixup location */ locType = (WORD) (fi.f_loc & NRSRCMASK); /* Get location type */ Getgsn(fi.f_mtd, fi.f_idx, &gsnTarget, &raTarget); // Check if frame of pseudo group FLAT if (ggrFlat) { // FLAT pseudo group defined if (fi.f_fmtd == KINDGROUP) fFlatRelative = (WORD) (mpgrggr[fi.f_fidx] == ggrFlat); else if (fi.f_fmtd == KINDTARGET && fi.f_mtd == KINDGROUP) fFlatRelative = (WORD) (mpgrggr[fi.f_idx] == ggrFlat); else fFlatRelative = FALSE; } else fFlatRelative = FALSE; if (fFlatRelative && fi.f_mtd == KINDGROUP && mpgrggr[fi.f_idx] == ggrFlat) RelocWarn(ER_badfixflat,objraCur,SNNIL, gsnTarget, raTarget); // Pseudo group FLAT is an illegal fixup target segTarget = mpgsnseg[gsnTarget]; // Get target object saTarget = mpsegsa[segTarget]; // Get target object number // Check for imports here. Depending on reference kind or place // of the reference generate the run-time relocation or treat // it as internal reference via thunk. The following cases // generate run-time relocation: // // - 16:16 pointer // - 16:16 gate pointer // // The 0:32 FLAT offset references are threated as internal references // and the thunk address for given import is used as target address // of fixup. Thunk does indirect jump via entry in Import Address // Table which is processed by the loader. if (fi.f_mtd == T2 && (mpextflags[fi.f_idx] & FIMPORT)) { // If target is dynamic link if (fDebSeg) { /* Import in $$SYMBOLS */ if (fi.f_loc == LOCSEGMENT) { fixword(pdata, 0); /* Install fake segment selector */ } return; } else { // Emit run-time relocation if reference to imported symbol is: // // - it is NOT self-relative 32-bit FLAT offset // - it is NOT 32-bit FLAT offset // - there is no thunk allocated for this import (importing DATA) // // The self-relative 32-bit FLAT offset and 32-bit FLAT offset // fixups have their target address redirected to the Thunk Table // entry for a given imported symbol and treated as internal fixup. apropName = (APROPNAMEPTR) FetchSym(mpextprop[fi.f_idx], TRUE); if ((apropName->an_flags & IMPDATA) || (locType != LOCOFFSET32)) { switch (locType) { case LOCLOBYTE: // Lo-byte (8-bit) fixup case LOCSEGMENT: // Segment (16-bit) fixup case LOCPTR: // "Pointer" (32-bit) fixup case LOCLOADOFFSET: // Loader-resolved offset fixup case LOCPTR48: // 48-bit pointer case LOCOFFSET: // Offset (16-bit) fixup OutError(ER_badfixpure32, 1 + GetPropName(mpextprop[fi.f_idx])); break; case LOCOFFSET32: // Offset (32-bit) fixup break; } // Get index to the Import Address Table LE_OBJNO(r) = (WORD) (mpsegsa[mpgsnseg[gsnImport]]); LE_IDTIDX(r) = (WORD) (apropName->an_module - 1); // Get Import Module Directory index LE_IATORD(r) = (WORD) apropName->an_entry; // Use FLAT entry /* If we have an LIDATA record */ if (TYPEOF(vrectData) == LIDATA) SaveLiRel(&r); /* Copy relocation into buffer */ else raTarget = SaveFixup(mpsegsa[vsegCur],vpageCur, &r); /* Record reference */ return; /* Next fixup item */ } } } // Internal reference (non-import) or reference to import thunk // It is assumed that we're always fixing up relative to the // physical segment or group, not the logical segment. So the // offset of the frame segment is not taken into account. if (fi.f_fmtd == KINDLOCAT) { gsnFrame = vgsnCur; } else if (fi.f_fmtd == KINDTARGET) { gsnFrame = gsnTarget; } else { Getgsn((KINDTYPE) fi.f_fmtd, fi.f_fidx, &gsnFrame, &dummy); } // The original LINK4 behavior was to fix up relative // to the physical segment. At one point it was changed // to subtract the displacement of the target segment (from // its physical segment) from the target value, if loc. type = // offset and frame and tgt. method = T0. This was no good // and the change was repealed. The /WARNFIXUP switch warns // about fixups which may be affected. if (fWarnFixup && fi.f_fmtd == KINDSEG && locType == LOCOFFSET && mpsegraFirst[mpgsnseg[gsnFrame]]) RelocWarn(ER_fixsegd,ra,gsnFrame,gsnTarget,raTarget); if (fFlatRelative) { saFrame = 1; // Pseudo-group FLAT has frame of first object gsnFrame = 0; } else saFrame = mpsegsa[mpgsnseg[gsnFrame]]; // Get frame's object number vBase = virtBase + mpsaBase[saTarget]; // Get TARGET object virtual base address if (gsnTarget == SNNIL) // If no target info { if (locType == LOCPTR) // If "pointer" (4 byte) fixup { lastbyte(pdata,ra,CALLFARDIRECT,BREAKPOINT); // Replace long call w/ breakpoint return; } if (locType == LOCSEGMENT) return; // Next fixup if "base" fixup if (locType == LOCLOADOFFSET) locType = LOCOFFSET; // Treat as regular offset } else { if (fi.f_self) // If self-relative fixup { if (saTarget != mpsegsa[vsegCur]) { if (locType == LOCOFFSET) RelocErr(ER_fixinter,ra,gsnFrame,gsnTarget,raTarget); // 16-bit must be in same segment if (fFlatRelative) { // If crossing object boundry include in raTarget // virtual distance between objects. // // mpsaBase[mpsegsa[vsegCur]] --> ---+------------------+ // ^ | | // | | | // ra | mpsegsa[vsegCur] | // | | | // V | | // ---+------------------+--- // | | ^ // . . | // . . | // . . | // | | vDist // +------------------+ | // | // V // masaBase[saTarget] --> ---+------------------+--- // ^ | | // | | | // raTarget | saTarget | // | | | // V | | // ---+------------------+ // | | // . . // . . // . . // | | // +------------------+ // vDist = (long) (mpsaBase[saTarget] - (mpsaBase[mpsegsa[vsegCur]] + ra)); raTarget += vDist; } } else raTarget -= ra; if (locType == LOCOFFSET) raTarget -= sizeof(WORD); else if (locType == LOCOFFSET32 || locType == LOCLOADOFFSET32) raTarget -= sizeof(DWORD); else raTarget -= sizeof(BYTE); } else if (saFrame != saTarget && !fFlatRelative) { /* If frame, target segs differ */ /* and not FLAT frame */ if (mpgsnseg[gsnFrame] <= segLast || segTarget <= segLast) { /* If either is non-absolute */ RelocWarn(ER_fixfrm,ra,gsnFrame,gsnTarget,raTarget); saFrame = saTarget; /* assume target seg */ } else { RelocWarn(ER_fixfrmab,ra,gsnFrame,gsnTarget,raTarget); dsa = (WORD) (saTarget - saFrame); raTmp = raTarget + ((dsa & 0xfff) << 4); if(dsa >= 0x1000 || raTmp < raTarget) { raTarget += fi.f_disp; #if OMF386 if ((rect & 1) && (fi.f_loc >= LOCOFFSET32)) raTarget += getdword(pdata); else #endif raTarget += getword(pdata); FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); } raTarget = raTmp; segTarget = mpgsnseg[gsnFrame]; /* Make target seg that of frame */ saTarget = mpsegsa[segTarget]; } /* Reset saTarget */ } } raTmp = raTarget; raTarget += fi.f_disp; if (locType >= LOCOFFSET32) if (rect & 1) raTarget += getdword(pdata); else { RelocWarn(ER_fixtyp,ra,gsnFrame,gsnTarget,raTarget); return; } else raTarget += getword(pdata); if (saTarget && fFlatRelative && !fi.f_self) raTarget += vBase; LE_FIXDAT(r) = raTarget; if (saTarget && fFlatRelative && !fDebSeg) { // The FLAT-relative offset fixups need to be propagated into // the .EXE file in the following cases: // // - for .EXE's - by user request // - for .DLL's - only FLAT-relative offset fixups if ((fKeepFixups || !IsAPLIPROG(vFlags)) && (locType == LOCOFFSET32 || locType == LOCLOADOFFSET32)) { if (!fi.f_self) { FinishRlc(&r, saTarget, raTarget - vBase); /* Don't pass virtual offsets */ } #if FALSE // Self-relative offset fixups crossing memory object // boudry are not longer propagated to the exe for PE images else if ((mpsegsa[vsegCur] != saTarget) && fKeepFixups) { FinishRlc(&r, saTarget, raTarget - vDist + sizeof(DWORD)); /* Don't pass virtual offsets */ } #endif } else if (locType == LOCOFFSET) { if (!fi.f_self) RelocWarn(ER_badfix16off,ra,gsnFrame,gsnTarget,raTarget); else if (raTarget > LXIVK) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); /* For 16:16 alias raTarget must be <= 64k */ } } switch(locType) /* Switch on fixup type */ { case LOCLOBYTE: /* 8-bit "lobyte" fixup */ raTarget = raTmp + B2W(pdata[0]) + fi.f_disp; pdata[0] = (BYTE) raTarget; if (raTarget >= 0x100 && fi.f_self) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); break; case LOCHIBYTE: /* 8-bit "hibyte" fixup */ raTarget = raTmp + fi.f_disp; pdata[0] = (BYTE) (B2W(pdata[0]) + (raTarget >> 8)); break; case LOCLOADOFFSET: /* Loader-resolved offset fixup */ case LOCOFFSET: /* 16-bit "offset" fixup */ fixword(pdata, raTarget); break; case LOCLOADOFFSET32: /* 32-bit "offset" fixup */ case LOCOFFSET32: /* 32-bit "offset" fixup */ fixword(pdata, raTarget); /* Perform low word fixup */ pdata += 2; raTarget >>= 16; /* Get high word */ fixword(pdata, raTarget); /* Perform fixup */ break; case LOCSEGMENT: /* 16-bit "base" fixup */ #if SYMDEB if(segTarget > segLast || fDebSeg) #else if(segTarget > segLast) /* If target segment absolute */ #endif { if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else saTarget += getword(pdata); /* Calculate base address */ fixword(pdata, saTarget); /* Store base address */ break; /* Done */ } RelocErr(ER_fixbad,ra,gsnFrame,gsnTarget,raTarget); break; case LOCPTR48: /* 48-bit "pointer" fixup */ #if SYMDEB if(segTarget > segLast || fDebSeg) #else if(segTarget > segLast) /* If target segment absolute */ #endif { fixword(pdata, raTarget); /* Store offset portion */ pdata += 2; raTarget >>= WORDLN; /* Get high word */ fixword(pdata, raTarget); /* Store offset portion */ pdata += 2; if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else saTarget += getword(pdata); /* Calculate base address */ fixword(pdata, saTarget); /* Store base address */ break; /* Done */ } RelocErr(ER_fixbad,ra,gsnFrame,gsnTarget,raTarget); break; case LOCPTR: /* 32-bit "pointer" fixup */ #if SYMDEB if(segTarget > segLast || fDebSeg) #else if(segTarget > segLast) /* If target segment absolute */ #endif { fixword(pdata, raTarget); /* Store offset portion */ pdata += 2; saTarget += getword(pdata); /* Calculate base address */ fixword(pdata, saTarget); /* Store base address */ break; /* Done */ } if (fFlatRelative) RelocWarn(ER_badfix16ptr, ra, gsnFrame, gsnTarget, raTarget); else RelocErr(ER_fixbad,ra,gsnFrame,gsnTarget,raTarget); break; default: /* Unsupported fixup type */ RelocErr(ER_fixbad,ra,gsnFrame,gsnTarget,raTarget); break; } } #endif /* EXE386 */ #if OSEGEXE AND NOT EXE386 /* * FixNew: * * Procss a fixup for a new-format exe. */ void NEAR FixNew () { REGISTER BYTE *pdata; /* Pointer into data record */ RATYPE ra; /* Offset of location being fixed up */ SNTYPE gsnTarget; /* Target segment definition number */ SNTYPE gsnFrame; /* Frame segment definition number */ SEGTYPE segTarget; /* Target segment order number */ SATYPE saTarget; /* Target file segment number */ SEGTYPE segFrame; /* Frame segment order number */ SATYPE saFrame; /* Frame file segment number */ RATYPE raTarget; /* Target offset */ RATYPE raTmp; /* Temporary */ WORD dsa; /* Difference in sa's */ RATYPE dummy; RELOCATION r; /* Relocation item */ memset(&r, 0, sizeof(RELOCATION)); ra = vraCur + (RATYPE) fi.f_dri; /* Get offset of fixup */ /* Save location in record */ NR_SOFF(r) = (WORD) ra; NR_STYPE(r) = (BYTE) fi.f_loc; /* Save fixup type */ NR_FLAGS(r) = (BYTE) (fi.f_add? NRADD: 0); if(fi.f_mtd == T2 && (mpextflags[fi.f_idx] & FFPMASK) #if ILINK && !fQCIncremental // For real-mode incremental // floating-point fixups are // treated as normal symbol fixups #endif ) { /* If floating-point fixup */ if (vFlags & NEPROT && TargetOs == NE_OS2) return; /* If protected mode only, ignore */ NR_FLAGS(r) = NRROSF | NRADD; NR_STYPE(r) = LOCLOADOFFSET;/* No 3-byte type, so we lie */ NR_OSTYPE(r) = (mpextflags[fi.f_idx] >> FFPSHIFT) & 7; /* Type # = ordinal in table */ NR_OSRES(r) = 0; /* Clear reserved word */ SaveFixup(mpsegsa[vsegCur],&r); return; } if(fi.f_mtd == T2 && (mpextflags[fi.f_idx] & FFP2ND)) return; /* Ignore secondary f.p. fixups */ pdata = &rgmi[fi.f_dri]; /* Set pointer to fixup location */ /* * Check for imports here. */ if(fi.f_mtd == T2 && (mpextflags[fi.f_idx] & FIMPORT)) { /* If target is dynamic link */ if (fDebSeg) { /* Import in $$SYMBOLS */ if (fi.f_loc == LOCSEGMENT) { fixword(pdata, 0); /* Install fake segment selector */ } return; } /* * Check for invalid import fixup types: self-rel, HIBYTE. */ if(fi.f_self) { RelocErr(ER_fixinter,ra,SNNIL,SNNIL,0L); return; } else if(fi.f_loc == LOCHIBYTE) { RelocErr(ER_fixbad,ra,SNNIL,SNNIL,0L); return; } else if(fi.f_loc == LOCOFFSET)/* Convert offset to runtime offset */ NR_STYPE(r) = LOCLOADOFFSET; NR_FLAGS(r) |= (mpextflags[fi.f_idx] & FIMPORD)? NRRORD: NRRNAM; /* Set flag */ if(fi.f_disp || fi.f_loc == LOCLOBYTE) NR_FLAGS(r) |= NRADD; /* Additive if non-zero displacement or lobyte */ #if M_BYTESWAP NR_SEGNO(r) = (BYTE) mpextgsn[fi.f_idx]; NR_RES(r) = (BYTE)(mpextgsn[fi.f_idx] >> BYTELN); #else NR_MOD(r) = mpextgsn[fi.f_idx]; #endif /* Get module specification */ NR_PROC(r) = (WORD) mpextra[fi.f_idx]; /* Get entry specification */ if(TYPEOF(vrectData) == LIDATA) /* If we have an LIDATA record */ { SaveLiRel(&r); /* Copy relocation into buffer */ raTarget = 0; /* Not chained yet */ } else raTarget = SaveFixup(mpsegsa[vsegCur],&r); /* Record reference */ if(NR_FLAGS(r) & NRADD) raTarget = fi.f_disp; /* If additive, install displacement */ if(fi.f_loc == LOCLOBYTE) { *pdata++ += (BYTE)(raTarget & 0xFF); } #if O68K else if (fTBigEndian) { *pdata++ += (BYTE)((raTarget >> BYTELN) & 0xFF); *pdata += (BYTE)(raTarget & 0xFF); } #endif /* O68K */ else { addword((BYTE *)pdata, (WORD)raTarget); } return; /* Next fixup item */ } NR_FLAGS(r) |= NRRINT; /* Internal reference (non-import) */ Getgsn(fi.f_mtd, fi.f_idx, &gsnTarget, &raTarget); /* * It is assumed that we're always fixing up relative to the * physical segment or group, not the logical segment. So the * offset of the frame segment is not taken into account. */ if (fi.f_fmtd == KINDLOCAT) { gsnFrame = vgsnCur; } else if (fi.f_fmtd == KINDTARGET) { gsnFrame = gsnTarget; } else { Getgsn(fi.f_fmtd, fi.f_fidx, &gsnFrame, &dummy); } segTarget = mpgsnseg[gsnTarget]; /* Get target segment */ saTarget = mpsegsa[segTarget]; /* Get target file segment number */ segFrame = mpgsnseg[gsnFrame]; /* Get frame segment */ saFrame = mpsegsa[segFrame]; /* Get frame's file segment number */ /* * The original LINK4 behavior was to fix up relative * to the physical segment. At one point it was changed * to subtract the displacement of the target segment (from * its physical segment) from the target value, if loc. type = * offset and frame and tgt. method = T0. This was no good * and the change was repealed. The /WARNFIXUP switch warns * about fixups which may be affected. */ if(fWarnFixup && fi.f_fmtd == KINDSEG && fi.f_loc == LOCOFFSET && mpsegraFirst[segFrame]) RelocWarn(ER_fixsegd,ra,gsnFrame,gsnTarget,raTarget); #if O68K /* 68k code does not permit segment fixups of any kind. */ if (f68k && !fDebSeg && ((1 << fi.f_loc) & ((1 << LOCSEGMENT) | (1 << LOCPTR) | (1 << LOCPTR48))) != 0) { RelocErr(ER_fixbad, ra, gsnFrame, gsnTarget, raTarget + fi.f_disp); return; } #endif /* O68K */ if(gsnTarget == SNNIL) /* If no target info */ { if(fi.f_loc == LOCPTR) /* If "pointer" (4 byte) fixup */ { lastbyte(pdata,ra,CALLFARDIRECT,BREAKPOINT); /* Replace long call w/ breakpoint */ return; } if(fi.f_loc == LOCSEGMENT) return; /* Next fixup if "base" fixup */ if(fi.f_loc == LOCLOADOFFSET) fi.f_loc = LOCOFFSET; /* Treat as regular offset */ } else { if(fi.f_self) /* If self-relative fixup */ { #if O68K if (iMacType != MAC_NONE) { switch (fi.f_loc) { case LOCOFFSET: if (saTarget != mpsegsa[vsegCur]) { NR_STYPE(r) = (BYTE)((NR_STYPE(r) & ~NRSTYP) | NRSOFF); fi.f_loc = LOCLOADOFFSET; } else raTarget -= ra; break; case LOCOFFSET32: if (saTarget != mpsegsa[vsegCur]) fi.f_loc = LOCLOADOFFSET32; else raTarget -= ra - 2; break; } } else #endif /* O68K */ { if (saTarget != mpsegsa[vsegCur]) RelocErr(ER_fixinter,ra,gsnFrame,gsnTarget,raTarget); /* Must be in same segment */ if(fi.f_loc == LOCOFFSET) raTarget = raTarget - ra - 2; #if OMF386 else if(fi.f_loc == LOCOFFSET32) raTarget = raTarget - ra - 4; #endif else raTarget = raTarget - ra - 1; } } else if (saFrame != saTarget) { /* If frame, target segs differ */ if (segFrame <= segLast || segTarget <= segLast) { /* If either is non-absolute */ RelocWarn(ER_fixfrm, ra, gsnFrame, gsnTarget, raTarget); } else { RelocWarn(ER_fixfrmab,ra,gsnFrame,gsnTarget,raTarget); dsa = saTarget - saFrame; raTmp = raTarget + ((dsa & 0xfff) << 4); if(dsa >= 0x1000 || raTmp < raTarget) { raTarget += fi.f_disp; #if OMF386 if ((rect & 1) && (fi.f_loc >= LOCOFFSET32)) raTarget += GetFixupDword(pdata); else #endif raTarget += GetFixupWord(pdata); FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); } raTarget = raTmp; } segTarget = segFrame; /* Make target seg that of frame */ saTarget = saFrame; /* Reset saTarget */ } } raTmp = raTarget; raTarget += fi.f_disp; #if OMF386 if ((rect & 1) && (fi.f_loc >= LOCOFFSET32)) raTarget += GetFixupDword(pdata); else #endif raTarget += GetFixupWord(pdata); switch(fi.f_loc) /* Switch on fixup type */ { case LOCLOBYTE: /* 8-bit "lobyte" fixup */ raTarget = raTmp + B2W(pdata[0]) + fi.f_disp; pdata[0] = (BYTE) raTarget; if(raTarget >= 0x100 && fi.f_self) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); break; case LOCHIBYTE: /* 8-bit "hibyte" fixup */ raTarget = raTmp + fi.f_disp; pdata[0] = (BYTE) (B2W(pdata[0]) + (raTarget >> 8)); break; case LOCLOADOFFSET: /* Loader-resolved offset fixup */ NR_FLAGS(r) &= ~NRADD; /* Not additive */ if ((TargetOs == NE_WINDOWS && !(vFlags & NEPROT)) #if O68K || iMacType != MAC_NONE #endif /* O68K */ ) raTarget = FinishRlc(&r, saTarget, raTarget); /* Finish relocation record */ #if O68K if (fTBigEndian) { *pdata++ = (BYTE)((raTarget >> BYTELN) & 0xFF); *pdata = (BYTE)(raTarget & 0xFF); } else #endif /* O68K */ { fixword(pdata, raTarget); } /* Install old head of chain */ break; case LOCOFFSET: /* 16-bit "offset" fixup */ #if O68K /* For 68K, LOCOFFSET is a signed 16-bit offset fixup. */ if (f68k && (raTarget & ~0x7FFF) != 0 && (raTarget & ~0x7FFF) != ~0x7FFF) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); #endif /* O68K */ #if O68K if (fTBigEndian) { *pdata++ = (BYTE)((raTarget >> BYTELN) & 0xFF); *pdata = (BYTE)(raTarget & 0xFF); } else #endif /* O68K */ { fixword(pdata, raTarget); } /* Install old head of chain */ break; #if OMF386 case LOCLOADOFFSET32: /* 32-bit "offset" fixup */ if(!(rect & 1)) break; /* Not 386 extension */ NR_FLAGS(r) &= ~NRADD; /* Not additive */ NR_STYPE(r) = (BYTE) ((NR_STYPE(r) & ~NRSTYP) | NROFF32); raTarget = FinishRlc(&r,saTarget,raTarget); /* Finish relocation record */ case LOCOFFSET32: /* 32-bit "offset" fixup */ #if O68K if (fTBigEndian) { *pdata++ = (BYTE)((raTarget >> (BYTELN + WORDLN)) & 0xFF); *pdata++ = (BYTE)((raTarget >> WORDLN) & 0xFF); *pdata++ = (BYTE)((raTarget >> BYTELN) & 0xFF); *pdata = (BYTE)(raTarget & 0xFF); } else #endif /* O68K */ { fixdword(pdata, raTarget); } /* Perform fixup */ break; #endif /* OMF386 */ case LOCSEGMENT: /* 16-bit "base" fixup */ #if SYMDEB if(segTarget > segLast || fDebSeg) #else if(segTarget > segLast) /* If target segment absolute */ #endif { if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else saTarget += getword(pdata); /* Calculate base address */ fixword(pdata, saTarget); /* Store base address */ break; /* Done */ } /* * Treat the displacment as an ordinal increment to saTarget, * for huge model. It would seem logical to include the primary * displacment, f_disp, but MASM has a quirk: an instruction of * the form "mov ax,ASEGMENT" generates a fixup with f_disp equal * to the length of the segment even though "mov ax,seg * ASEGMENT" causes f_disp to be 0! So for compatibility we * ignore f_disp. * Then force the fixup to non-additive since the secondary * displacement has been added to saTarget. */ if((saTarget += getword(pdata)) >= saMac) FixupOverflow(ra,gsnFrame,gsnTarget,0L); NR_FLAGS(r) &= ~NRADD; #if FALSE /* * Too early to decide here. We don't know if a * base fixup will require call-gate and if it * does then we need the actual offset in call-gate. * * Forcing the offset to zero for base fixups: * PRO's * 1. Fewer fixup records in the .EXE. * 2. No more than n dummy entries in the * Entry Table for a program of n segments * in the WORST case. * CON's * 1. Approximately n dummy entries in the * Entry Table for a program of n segments * in the AVERAGE case. */ raTarget = FinishRlc(&r,saTarget,0L); /* Finish relocation record */ #else /* * Leaving the offset alone for base fixups: * PRO's * 1. No more than 1 or 2 dummy entries in the * Entry Table for a program of n segments * in the AVERAGE case. * CON's * 1. More fixup records in the .EXE. * 2. Number of dummy entries in the Entry Table * only bounded by the maximum allowable size * of the Entry Table in the WORST CASE. */ raTarget = FinishRlc(&r,saTarget,raTarget); /* Finish relocation record */ #endif fixword(pdata, raTarget); /* Install old head of chain */ break; #if OMF386 case LOCPTR48: /* 48-bit "pointer" fixup */ if(!(rect & 1)) break; /* Not 386 extension */ NR_STYPE(r) = (BYTE) ((NR_STYPE(r) & ~NRSTYP) | NRPTR48); fixword(pdata, raTarget); pdata += 2; raTarget >>= 16; /* Get high word, fall through ... */ #endif case LOCPTR: /* 32-bit "pointer" fixup */ #if SYMDEB if(segTarget > segLast || fDebSeg) #else if(segTarget > segLast) /* If target segment absolute */ #endif { fixword(pdata, raTarget); pdata += 2; /* Store offset portion */ if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else saTarget += getword(pdata); /* Calculate base address */ fixword(pdata, saTarget); /* Store base address */ break; /* Done */ } if(fFarCallTrans && saTarget == mpsegsa[vsegCur] && (mpsaflags[saTarget] & NSTYPE) == NSCODE) { /* If intrasegment fixup */ if(TransFAR(pdata,ra,raTarget)) break; } /* * Treat the high word at the location as an increment to the * target segment index. Check for overflow and clear the high * word at the location. Force fixup to be non-additive because * the secondary displacement has already been added to raTarget. */ if((saTarget += getword(pdata + 2)) >= saMac) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); pdata[2] = pdata[3] = 0; NR_FLAGS(r) &= ~NRADD; #if NOT QCLINK if (fOptimizeFixups) { // Check if pointer fixup (16:16 or 16:32) can be split into // linker resolved offset fixup (16 or 32 bit) and loader // resolved base (selector) fixup. if (!CallGateRequired(saTarget)) { fixword(pdata, raTarget); /* Store offset portion */ pdata += 2; NR_STYPE(r) = (BYTE) LOCSEGMENT; if (fi.f_loc == LOCPTR48) NR_SOFF(r) += 4; else NR_SOFF(r) += 2; raTarget = 0L; } } #endif raTarget = FinishRlc(&r,saTarget,raTarget); /* Finish relocation record */ fixword(pdata, raTarget); /* Install old head of chain */ break; default: /* Unsupported fixup type */ RelocErr(ER_fixbad,ra,gsnFrame,gsnTarget,raTarget); break; } } #ifdef LEGO /* * FixNewKeep: * * Process a fixup for a new-format exe. */ void NEAR FixNewKeep() { BYTE *pdata; /* Pointer into data record */ RATYPE ra; /* Offset of location being fixed up */ SNTYPE gsnTarget; /* Target segment definition number */ SNTYPE gsnFrame; /* Frame segment definition number */ SEGTYPE segTarget; /* Target segment order number */ SATYPE saTarget; /* Target file segment number */ SEGTYPE segFrame; /* Frame segment order number */ SATYPE saFrame; /* Frame file segment number */ RATYPE raTarget; /* Target offset */ RATYPE raTmp; /* Temporary */ WORD dsa; /* Difference in sa's */ RATYPE dummy; RELOCATION r; /* Relocation item */ memset(&r, 0, sizeof(RELOCATION)); ra = vraCur + (RATYPE) fi.f_dri; /* Get offset of fixup */ /* Save location in record */ NR_SOFF(r) = (WORD) ra; NR_STYPE(r) = (BYTE) fi.f_loc; /* Save fixup type */ NR_FLAGS(r) = (BYTE) (fi.f_add ? NRADD : 0); pdata = &rgmi[fi.f_dri]; /* Set pointer to fixup location */ if (fi.f_mtd == T2) { /* The target is an external symbol */ if (mpextflags[fi.f_idx] & FFPMASK) { /* This is a floating point fixup */ if (TargetOs == NE_OS2) { /* Floating point fixups are ignored in prot mode OS/2 */ return; } /* Emit an OS fixup. The loader will deal with these. */ NR_STYPE(r) = LOCLOADOFFSET; NR_FLAGS(r) = NRROSF | NRADD; NR_OSTYPE(r) = (mpextflags[fi.f_idx] >> FFPSHIFT) & 7; NR_OSRES(r) = 0; SaveFixup(mpsegsa[vsegCur], &r); return; } if (mpextflags[fi.f_idx] & FFP2ND) { /* This is a secondary floating point fixup. */ /* These are always ignored. */ return; } /* * Check for imports here. */ if (mpextflags[fi.f_idx] & FIMPORT) { /* If target is dynamic link */ if (fDebSeg) { /* Import in $$SYMBOLS */ if (fi.f_loc == LOCSEGMENT) { *pdata++ = 0; /* Install fake segment selector */ *pdata++ = 0; } return; } /* * Check for invalid import fixup types: self-rel, HIBYTE. */ if (fi.f_self) { RelocErr(ER_fixinter, ra, SNNIL, SNNIL, 0L); return; } if (fi.f_loc == LOCHIBYTE) { RelocErr(ER_fixbad, ra, SNNIL, SNNIL, 0L); return; } /* Convert offset to runtime offset */ if (fi.f_loc == LOCOFFSET) NR_STYPE(r) = LOCLOADOFFSET; NR_FLAGS(r) |= (mpextflags[fi.f_idx] & FIMPORD) ? NRRORD : NRRNAM; if (fi.f_disp || fi.f_loc == LOCLOBYTE) NR_FLAGS(r) |= NRADD; /* Additive if non-zero displacement or lobyte */ #if M_BYTESWAP NR_SEGNO(r) = (BYTE) mpextgsn[fi.f_idx]; NR_RES(r) = (BYTE)(mpextgsn[fi.f_idx] >> BYTELN); #else NR_MOD(r) = mpextgsn[fi.f_idx]; #endif /* Get module specification */ NR_PROC(r) = (WORD) mpextra[fi.f_idx]; /* Get entry specification */ if (TYPEOF(vrectData) == LIDATA)/* If we have an LIDATA record */ { SaveLiRel(&r); /* Copy relocation into buffer */ raTarget = 0; /* Not chained yet */ } else { raTarget = SaveFixup(mpsegsa[vsegCur], &r); } /* Record reference */ if (NR_FLAGS(r) & NRADD) /* If additive, install displacement */ raTarget = fi.f_disp; if (fi.f_loc == LOCLOBYTE) { *pdata++ += (BYTE)(raTarget & 0xFF); } else { addword((BYTE *)pdata, (WORD)raTarget); } return; /* Next fixup item */ } } NR_FLAGS(r) |= NRRINT; /* Internal reference (non-import) */ Getgsn(fi.f_mtd, fi.f_idx, &gsnTarget, &raTarget); /* * It is assumed that we're always fixing up relative to the * physical segment or group, not the logical segment. So the * offset of the frame segment is not taken into account. */ if (fi.f_fmtd == KINDLOCAT) { gsnFrame = vgsnCur; } else if (fi.f_fmtd == KINDTARGET) { gsnFrame = gsnTarget; } else { Getgsn(fi.f_fmtd, fi.f_fidx, &gsnFrame, &dummy); } segTarget = mpgsnseg[gsnTarget]; /* Get target segment */ saTarget = mpsegsa[segTarget]; /* Get target file segment number */ segFrame = mpgsnseg[gsnFrame]; /* Get frame segment */ saFrame = mpsegsa[segFrame]; /* Get frame's file segment number */ /* * The original LINK4 behavior was to fix up relative * to the physical segment. At one point it was changed * to subtract the displacement of the target segment (from * its physical segment) from the target value, if loc. type = * offset and frame and tgt. method = T0. This was no good * and the change was repealed. The /WARNFIXUP switch warns * about fixups which may be affected. */ if (fWarnFixup && (fi.f_fmtd == KINDSEG) && (fi.f_loc == LOCOFFSET) && mpsegraFirst[segFrame]) RelocWarn(ER_fixsegd, ra, gsnFrame, gsnTarget, raTarget); if (gsnTarget == SNNIL) /* If no target info */ { if (fi.f_loc == LOCPTR) /* If "pointer" (4 byte) fixup */ { lastbyte(pdata, ra, CALLFARDIRECT, BREAKPOINT); /* Replace long call w/ breakpoint */ return; } if (fi.f_loc == LOCSEGMENT) /* Next fixup if "base" fixup */ return; if (fi.f_loc == LOCLOADOFFSET) fi.f_loc = LOCOFFSET; /* Treat as regular offset */ } else { if (fi.f_self) /* If self-relative fixup */ { if (saTarget != mpsegsa[vsegCur]) { RelocErr(ER_fixinter, ra, gsnFrame, gsnTarget, raTarget); return; } /* Must be in same segment */ if (fi.f_loc == LOCOFFSET) raTarget -= ra + sizeof(WORD); #if OMF386 else if (fi.f_loc == LOCOFFSET32) raTarget -= ra + sizeof(DWORD); #endif /* OMF386 */ else raTarget -= ra + sizeof(BYTE); } else if (saFrame != saTarget) { /* If frame, target segs differ */ if (segFrame <= segLast || segTarget <= segLast) { /* If either is non-absolute */ RelocWarn(ER_fixfrm, ra, gsnFrame, gsnTarget, raTarget); } else { RelocWarn(ER_fixfrmab, ra, gsnFrame, gsnTarget, raTarget); dsa = saTarget - saFrame; raTmp = raTarget + ((dsa & 0xfff) << 4); if (dsa >= 0x1000 || raTmp < raTarget) { raTarget += fi.f_disp; #if OMF386 if ((rect & 1) && (fi.f_loc >= LOCOFFSET32)) raTarget += GetFixupDword(pdata); else #endif /* OMF386 */ raTarget += GetFixupWord(pdata); FixupOverflow(ra, gsnFrame, gsnTarget, raTarget); } raTarget = raTmp; } segTarget = segFrame; /* Make target seg that of frame */ saTarget = saFrame; /* Reset saTarget */ } } raTmp = raTarget; raTarget += fi.f_disp; if (fDebSeg || fi.f_self) { /* If fKeepFixups is TRUE, the value stored at the fixed up */ /* location is not added to the target address. The fixup will */ /* be emitted as an additive fixup and the loader will add in */ /* the bias. /* If the fixup is being applied to a debug segment, the offset is */ /* added because these fixups aren't handled by the loader. In */ /* other words, they can not be kept. */ /* If the fixup is being applied is self-relative, the offset is */ /* added because the loaded doesn't handle self-relative fixups. */ /* While the fixed up word would have the correct value, the target */ /* of the fixup would be artifical. */ #if OMF386 if ((rect & 1) && (fi.f_loc >= LOCOFFSET32)) raTarget += GetFixupDword(pdata); else #endif /* OMF386 */ raTarget += GetFixupWord(pdata); } switch (fi.f_loc) /* Switch on fixup type */ { case LOCLOBYTE: /* 8-bit "lobyte" fixup */ raTarget = raTmp + B2W(pdata[0]) + fi.f_disp; pdata[0] = (BYTE) raTarget; if (raTarget >= 0x100 && fi.f_self) FixupOverflow(ra, gsnFrame, gsnTarget, raTarget); break; case LOCHIBYTE: /* 8-bit "hibyte" fixup */ raTarget = raTmp + fi.f_disp; pdata[0] = (BYTE) (B2W(pdata[0]) + (raTarget >> 8)); break; case LOCLOADOFFSET: /* Loader-resolved offset fixup */ /* There are no LOCLOADOFFSET fixups that are */ /* self-relative or applied to debug segments. */ /* Force non-external fixups to be additive. The C */ /* compiler may emit a BAKPAT to a fixed up word. If the */ /* fixup is chained the BAKPAT will corrupt the chain. */ /* This does not occur when the target is external. We */ /* special case this so that the number of fixups is */ /* reduced. */ if (fi.f_mtd != T2) NR_FLAGS(r) |= NRADD; raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; fixword(pdata, raTarget); break; case LOCOFFSET: /* 16-bit "offset" fixup */ if (!fDebSeg && !fi.f_self) { /* Force non-external fixups to be additive. The C */ /* compiler may emit a BAKPAT to a fixed up word. If the */ /* fixup is chained the BAKPAT will corrupt the chain. */ /* This does not occur when the target is external. We */ /* special case this so that the number of fixups is */ /* reduced. */ if (fi.f_mtd != T2) NR_FLAGS(r) |= NRADD; NR_STYPE(r) = LOCLOADOFFSET; raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; } fixword(pdata, raTarget); break; case LOCSEGMENT: /* 16-bit "base" fixup */ #if SYMDEB if (segTarget > segLast || fDebSeg) #else if (segTarget > segLast) /* If target segment absolute */ #endif { if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else { saTarget += getword(pdata); } /* Store base address */ fixword(pdata, saTarget); break; } raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; fixword(pdata, raTarget); break; case LOCPTR: /* 32-bit "pointer" fixup */ #if SYMDEB if (segTarget > segLast || fDebSeg) #else if (segTarget > segLast) /* If target segment absolute */ #endif { /* Store offset portion */ fixword(pdata, raTarget); pdata += 2; if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else { saTarget += getword(pdata); } /* Store base address */ fixword(pdata, saTarget); break; } /* Force non-external fixups to be additive. The C */ /* compiler may emit a BAKPAT to a fixed up word. If the */ /* fixup is chained the BAKPAT will corrupt the chain. */ /* This does not occur when the target is external. We */ /* special case this so that the number of fixups is */ /* reduced. */ if (fi.f_mtd != T2) NR_FLAGS(r) |= NRADD; /* Check segment to see if fixup must be additive */ else if (getword(pdata + 2) != 0) NR_FLAGS(r) |= NRADD; raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; fixword(pdata, raTarget); break; #if OMF386 /* NOTE: Support for 32 bit fixups in 16 bit images is a joke. */ /* NOTE: The Windows loader doesn't understand these. We fake */ /* NOTE: out Windows by converting these fixups to NRSOFF type. */ /* NOTE: The Chicago loader now understands NROFF32 fixups so */ /* NOTE: we now use this type. This will generate an executable */ /* NOTE: that doesn't work under Windows 3.x. Oh Well! */ case LOCLOADOFFSET32: /* 32-bit Loader-resolved offset fixup */ /* There are no LOCLOADOFFSET32 fixups that are */ /* self-relative or applied to debug segments. */ /* Force non-external fixups to be additive. The C */ /* compiler may emit a BAKPAT to a fixed up word. If the */ /* fixup is chained the BAKPAT will corrupt the chain. */ /* This does not occur when the target is external. We */ /* special case this so that the number of fixups is */ /* reduced. */ if (fi.f_mtd != T2) NR_FLAGS(r) |= NRADD; if (raTarget > 0xffff) RelocErr(ER_fixbad, ra, gsnFrame, gsnTarget, raTarget); NR_STYPE(r) = NROFF32; raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; fixdword(pdata, raTarget); break; case LOCOFFSET32: /* 32-bit "offset" fixup */ if (!fDebSeg && !fi.f_self) { /* Force non-external fixups to be additive. The C */ /* compiler may emit a BAKPAT to a fixed up word. If the */ /* fixup is chained the BAKPAT will corrupt the chain. */ /* This does not occur when the target is external. We */ /* special case this so that the number of fixups is */ /* reduced. */ if (fi.f_mtd != T2) NR_FLAGS(r) |= NRADD; if (raTarget > 0xffff) RelocErr(ER_fixbad, ra, gsnFrame, gsnTarget, raTarget); NR_STYPE(r) = NROFF32; raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; } fixdword(pdata, raTarget); break; case LOCPTR48: /* 48-bit "pointer" fixup */ #if SYMDEB if (segTarget > segLast || fDebSeg) #else if (segTarget > segLast) /* If target segment absolute */ #endif { /* Store offset portion */ fixdword(pdata, raTarget); pdata += 4; if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTarget = segTarget; } else { saTarget += getword(pdata); } /* Store base address */ fixword(pdata, saTarget); break; } /* Force non-external fixups to be additive. The C */ /* compiler may emit a BAKPAT to a fixed up word. If the */ /* fixup is chained the BAKPAT will corrupt the chain. */ /* This does not occur when the target is external. We */ /* special case this so that the number of fixups is */ /* reduced. */ if (fi.f_mtd != T2) NR_FLAGS(r) |= NRADD; /* Check segment to see if fixup must be additive */ else if (getword(pdata + 4) != 0) NR_FLAGS(r) |= NRADD; NR_STYPE(r) = NRPTR48; raTarget = FinishRlc(&r, saTarget, raTarget); if (NR_FLAGS(r) & NRADD) break; fixdword(pdata, raTarget); break; #endif /* OMF386 */ default: /* Unsupported fixup type */ RelocErr(ER_fixbad, ra, gsnFrame, gsnTarget, raTarget); break; } } #endif /* LEGO */ #if O68K /* * GetFixupWord: * * Gets a word depending of the value of fTBigEndian and fDebSeg */ LOCAL WORD NEAR GetFixupWord (pdata) BYTE *pdata; { if (fTBigEndian && !fDebSeg) { return (WORD)((B2W(pdata[0]) << BYTELN) + B2W(pdata[1])); } else { return getword(pdata); } } /* * GetFixupDword: * * Gets a dword depending of the value of fTBigEndian and fDebSeg */ LOCAL DWORD NEAR GetFixupDword (pdata) BYTE *pdata; { if (fTBigEndian && !fDebSeg) { return (DWORD)((((((B2L(pdata[0]) << BYTELN) + B2L(pdata[1])) << BYTELN) + B2L(pdata[2])) << BYTELN) + B2L(pdata[3])); } else { return getdword(pdata); } } #endif /* O68K */ #endif /* OSEGEXE AND NOT EXE386 */ #if ODOS3EXE OR OIAPX286 /* * StartAddrOld: * * Process a MODEND record with a start address for an old-format exe. */ LOCAL void NEAR StartAddrOld () { SEGTYPE gsnTarget; SEGTYPE gsnFrame; RATYPE raTarget; /* Fixup target offset */ RATYPE ra; SATYPE dsa; SEGTYPE segTarget; /* Target segment */ SEGTYPE segFrame; GetFrameTarget(&gsnFrame,&gsnTarget,&raTarget); /* Get fixup information */ if(gsnFrame == SEGNIL) gsnFrame = gsnTarget; /* Use target val. if none given */ segFrame = mpgsnseg[gsnFrame]; /* Get frame segment */ segTarget = mpgsnseg[gsnTarget];/* Get target segment */ dsa = mpsegsa[segTarget] - mpsegsa[segFrame]; /* Calculate base delta */ #if NOT OIAPX286 if(dsa > 0x1000) FixupOverflow(raTarget + fi.f_disp,gsnFrame,gsnTarget,raTarget); /* Delta > 64Kbytes */ ra = dsa << 4; if(0xFFFF - ra < raTarget) /* If addition would overflow */ { ra = ra - 0xFFFF + raTarget; /* Fix up addition */ --ra; FixupOverflow(raTarget + fi.f_disp,gsnFrame,gsnTarget,raTarget); } else ra = ra + raTarget; /* Else perform addition */ #endif #if OIAPX286 if(dsa) FixupOverflow(raTarget + fi.f_disp,gsnFrame,gsnTarget,raTarget); /* No intersegment fixups */ ra = raTarget; /* Use target offset */ #endif #if EXE386 if((rect & 1) && ra + fi.f_disp < ra) { ra = ra - 0xFFFFFFFF + fi.f_disp; --ra; FixupOverflow(raTarget + fi.f_disp,gsnFrame,gsnTarget,raTarget); } else if (!(rect & 1) && 0xFFFF - ra < fi.f_disp) #else if(0xFFFF - ra < fi.f_disp) /* If addition would overflow */ #endif { ra = ra - 0xFFFF + fi.f_disp; /* Fix up addition */ --ra; FixupOverflow(raTarget + fi.f_disp,gsnFrame,gsnTarget,raTarget); } else ra = ra + fi.f_disp; /* Else perform addition */ if(segStart == SEGNIL) { segStart = segFrame; raStart = ra; if(fLstFileOpen) /* If there is a listing file */ { if(vcln) /* If writing line numbers */ { NEWLINE(bsLst); /* End of line */ vcln = 0; /* Start on new line */ } fprintf(bsLst,GetMsg(MAP_entry), mpsegsa[segStart],raStart);/* Print entry point */ } } } #endif /* ODOS3EXE OR OIAPX286 */ /**************************************************************** * * * EndRec: * * * * This function is called to process the information * * contained in a MODEND (type 8AH) record concerning the * * program starting address. The function does not return a * * meaningful value. * * See pp. 80-81 in "8086 Object Module Formats EPS." * * * ****************************************************************/ void NEAR EndRec(void) { WORD modtyp; /* MODEND record modtyp byte */ SEGTYPE gsnTarget; RATYPE ra; modtyp = Gets(); /* Read modtyp byte */ if(modtyp & FSTARTADDRESS) /* If execution start address given */ { ASSERT(modtyp & 1); /* Must have logical start address */ GetFixdat(); /* Get target information */ #if ODOS3EXE OR OIAPX286 /* Start address processed differently for DOS 3.x exes */ if(!fNewExe) { StartAddrOld(); return; } #endif #if OSEGEXE switch(fi.f_mtd) /* Switch on target method */ { case T0: /* Segment index */ gsnTarget = mpsngsn[fi.f_idx]; ra = mpgsndra[gsnTarget]; break; case T1: /* Group index */ gsnTarget = mpggrgsn[mpgrggr[fi.f_idx]]; ra = mpgsndra[gsnTarget]; break; case T2: /* External index */ if(mpextflags[fi.f_idx] & FIMPORT) { OutError(ER_impent); return; } gsnTarget = mpextgsn[fi.f_idx]; ra = mpextra[fi.f_idx]; break; } if(segStart == SEGNIL) /* If no entry point specified */ { segStart = mpgsnseg[gsnTarget]; /* Get starting file segment number */ raStart = ra + fi.f_disp; /* Get starting offset */ if(fLstFileOpen) /* If there is a listing file */ { if(vcln) /* If writing line numbers */ { NEWLINE(bsLst); /* End of line */ vcln = 0; /* Start on new line */ } #if NOT QCLINK /* Check if segStart is code */ #if EXE386 if (!IsEXECUTABLE(mpsaflags[mpsegsa[segStart]])) #else if((mpsaflags[mpsegsa[segStart]] & NSTYPE) != NSCODE && !fRealMode && (TargetOs == NE_OS2 || TargetOs == NE_WINDOWS)) #endif OutError(ER_startaddr); #endif fprintf(bsLst,"\r\nProgram entry point at %04x:%04x\r\n", mpsegsa[segStart],raStart); /* Print entry point */ } } #endif /* OSEGEXE */ } } #if ODOS3EXE OR OXOUT /**************************************************************** * * * RecordSegmentReference: * * * * Generate a loadtime relocation for a DOS3 exe. * * * ****************************************************************/ void NEAR RecordSegmentReference(seg,ra,segDst) SEGTYPE seg; RATYPE ra; SEGTYPE segDst; { SEGTYPE segAbsLast; /* Last absolute segemnt */ DOSRLC rlc; // Relocation address long xxaddr; /* Twenty bit address */ void FAR *pTmp; RUNRLC FAR *pRunRlc; #if OVERLAYS WORD iov; /* Overlay number */ #endif #if FEXEPACK WORD frame; /* Frame part of 20-bit address */ FRAMERLC FAR *pFrameRlc; #endif #if SYMDEB if(fSymdeb && seg >= segDebFirst) /* Skip if debug segment */ return; #endif #if ODOS3EXE segAbsLast = segLast + csegsAbs; /* Calc. last absolute seg no. */ if(vfDSAlloc) --segAbsLast; if(segDst > segLast && segDst <= segAbsLast) return; /* Don't bother if absolute segment */ #endif if (TYPEOF(vrectData) == LIDATA) ompimisegDstIdata[ra - vraCur] = (char) segDst; else /* Else if not iterated data */ { #if OVERLAYS iov = mpsegiov[seg]; /* Get overlay number */ ASSERT(fOverlays || iov == IOVROOT); /* If no overlays then iov = IOVROOT */ #endif #if FEXEPACK #if OVERLAYS if (iov == 0) /* If root */ #endif if (fExePack) { /* * Optimize this reloc: form the 20-bit address, the * frame is the high-order 4 bits, forming an index * into mpframcRle (count of relocs by frame), which * then forms an index into the packed relocation area, * where the low-order 16 bits are stored. Finally, * increment the frame's reloc count and return. */ xxaddr = ((RATYPE) mpsegsa[seg] << 4) + (RATYPE) ra; frame = (WORD) ((xxaddr >> 16) & 0xf); pFrameRlc = &mpframeRlc[frame]; if (pFrameRlc->count > 0x7fff) Fatal(ER_relovf); ra = (RATYPE) (xxaddr & 0xffffL); if (pFrameRlc->count >= pFrameRlc->count) { // We need more memory to store this relocation if (pFrameRlc->rgRlc == NULL) { pFrameRlc->rgRlc = (WORD FAR *) GetMem(DEF_FRAMERLC*sizeof(WORD)); pFrameRlc->size = DEF_FRAMERLC; } else if (pFrameRlc->count >= pFrameRlc->size) { // Reallocate array of packed relocation offsets pTmp = GetMem((pFrameRlc->size << 1)*sizeof(WORD)); FMEMCPY(pTmp, pFrameRlc->rgRlc, pFrameRlc->count*sizeof(WORD)); FFREE(pFrameRlc->rgRlc); pFrameRlc->rgRlc = pTmp; pFrameRlc->size <<= 1; } } pFrameRlc->rgRlc[pFrameRlc->count] = (WORD) ra; pFrameRlc->count++; return; } #endif /* FEXEPACK */ rlc.sa = (WORD) mpsegsa[seg]; /* Get segment address */ rlc.ra = (WORD) ra; /* Save relative address */ #if OVERLAYS pRunRlc = &mpiovRlc[iov]; if (pRunRlc->count >= pRunRlc->count) { // We need more memory to store this relocation if (pRunRlc->rgRlc == NULL) { pRunRlc->rgRlc = (DOSRLC FAR *) GetMem(DEF_RUNRLC * CBRLC); pRunRlc->size = DEF_RUNRLC; } else if (pRunRlc->count >= pRunRlc->size) { // Reallocate array of packed relocation offsets pTmp = GetMem((pRunRlc->size << 1) * CBRLC); FMEMCPY(pTmp, pRunRlc->rgRlc, pRunRlc->count * CBRLC); FFREE(pRunRlc->rgRlc); pRunRlc->rgRlc = pTmp; pRunRlc->size <<= 1; } } pRunRlc->rgRlc[pRunRlc->count] = rlc; pRunRlc->count++; #endif } } #endif /* ODOS3EXE OR OXOUT */ #if OVERLAYS /**************************************************************** * * * Mpgsnosn: * * * * Map global segment number to overlay segment number. * * * ****************************************************************/ LOCAL SNTYPE NEAR Mpgsnosn(gsn) SNTYPE gsn; /* Global SEGDEF number */ { SNTYPE hgsn; /* Gsn hash value */ hgsn = (SNTYPE)(gsn & ((1 << LG2OSN) - 1)); /* Take the low-order bits */ while(mposngsn[htgsnosn[hgsn]] != gsn) { /* While match not found */ if((hgsn += HTDELTA) >= OSNMAX) hgsn -= OSNMAX; /* Calculate next hash value */ } return(htgsnosn[hgsn]); /* Return overlay segment number */ } #endif #if ODOS3EXE OR OIAPX286 LOCAL void NEAR GetFrameTarget(pgsnFrame,pgsnTarget,praTarget) SEGTYPE *pgsnFrame; /* Frame index */ SEGTYPE *pgsnTarget; /* Target index */ RATYPE *praTarget; /* Target offset */ { RATYPE dummy; WORD i; /* Method no: Frame specification: * 0 segment index * 1 group index * 2 external index * 3 frame number * 4 implicit (location) * 5 implicit (target) * 6 none * 7 invalid */ if(fi.f_fmtd == KINDTARGET) /* If frame is target's frame */ { fi.f_fmtd = fi.f_mtd; /* Use target frame kind */ fi.f_fidx = fi.f_idx; /* Use target index */ } if (fi.f_fmtd == KINDEXT && !fNoGrpAssoc) { /* If frame given by pub sym */ if(fi.f_fidx >= extMac) InvalidObject(); /* Make sure index not too big */ if((i = mpextggr[fi.f_fidx]) != GRNIL) /* If symbol has group association */ *pgsnFrame = mpggrgsn[i]; /* Get gsn for group */ else *pgsnFrame = mpextgsn[fi.f_fidx]; /* Else return target gsn */ } else if (fi.f_fmtd == KINDLOCAT && !fNoGrpAssoc) { /* If frame current segment */ *pgsnFrame = vgsnCur; /* Frame is location's segment */ } else { Getgsn(fi.f_fmtd, fi.f_fidx, pgsnFrame, &dummy); } Getgsn(fi.f_mtd, fi.f_idx, pgsnTarget, praTarget); /* Get gsn and ra, if any */ } LOCAL WORD NEAR InOneGroup(WORD gsnTarget, WORD gsnFrame) { WORD ggrFrame; /* Fixup frame group */ WORD ggrTarget; /* Fixup frame group */ APROPSNPTR apropSn; /* Ptr to a segment record */ if (gsnFrame != SNNIL) { apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnFrame], FALSE); ggrFrame = apropSn->as_ggr; } else ggrFrame = GRNIL; if (gsnTarget != SNNIL) { apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnTarget], FALSE); ggrTarget = apropSn->as_ggr; } else ggrFrame = GRNIL; return(ggrFrame != GRNIL && ggrTarget != GRNIL && ggrFrame == ggrTarget); } LOCAL void NEAR AddThunk(SEGTYPE gsnTarget, SEGTYPE *psegTarget, RATYPE *praTarget) { #pragma pack(1) /* This data must be packed */ struct _thunk { BYTE thunkInt; BYTE ovlInt; WORD osnTgt; WORD osnOff; } thunk; #pragma pack() /* Stop packing */ // We need a new thunk if (ovlThunkMac < (WORD) (ovlThunkMax - 1)) { thunk.thunkInt = INTERRUPT; thunk.ovlInt = (BYTE) vintno; thunk.osnTgt = Mpgsnosn(gsnTarget); thunk.osnOff = (WORD) *praTarget; *praTarget = ovlThunkMac * OVLTHUNKSIZE; *psegTarget = mpgsnseg[gsnOverlay]; MoveToVm(sizeof(struct _thunk), (BYTE *) &thunk, mpgsnseg[gsnOverlay], *praTarget); /* Store thunk */ #if FALSE fprintf(stdout, "%d. Thunk at %x:%04lx; Target osn = %x:%x\r\n", ovlThunkMac , mpgsnseg[gsnOverlay], *praTarget, thunk.osnTgt, thunk.osnOff); #endif ovlThunkMac++; } else { Fatal(ER_ovlthunk, ovlThunkMax); } } /*** DoThunking - generate thunk for inter-overlay calls * * Purpose: * When the dynamic overlays are requested redirect all FAR calls or * references to aproppriate thunks. If this is first call/reference * to given symbol then add its thunk to the OVERLAY_THUNKS segment. * * Input: * gsnTarget - global segment number of the fixup target * psegTarget - poiter to logical segment number of the fixup target * praTarget - pointer offset of the fixup target inside gsnTarget * * Output: * The gsn and offset of the target are replaced by the gsn and offset * of the thunk for target. For first references to a given symbol * the thunk is created in OVERLAY_THUNKS segment (referenced via * gsnOverlay global) and the current position in thunk segment is * updated (ovlThunkMac). * * Exceptions: * No space in OVERLAY_THUNKS for new thunk - fatal error - display message * suggesting use of /DYNAMIC: with greater then current value. * * Notes: * None. * *************************************************************************/ LOCAL void NEAR DoThunking(SEGTYPE gsnTarget, SEGTYPE *psegTarget, RATYPE *praTarget) { APROPNAMEPTR apropName; /* Public symbol property */ switch(fi.f_mtd) { case KINDEXT: // Target is external apropName = (APROPNAMEPTR) FetchSym(mpextprop[fi.f_idx], FALSE); if (apropName->an_thunk != THUNKNIL) { // We already allocated thunk for this target *praTarget = apropName->an_thunk; *psegTarget = mpgsnseg[gsnOverlay]; #if FALSE fprintf(stdout, "Using thunk for '%s' at %x:%04lx\r\n", 1 + GetPropName(apropName), mpgsnseg[gsnOverlay], *praTarget); #endif } else { // We need new thunk for new target AddThunk(gsnTarget, psegTarget, praTarget); apropName = (APROPNAMEPTR) FetchSym(mpextprop[fi.f_idx], TRUE); apropName->an_thunk = *praTarget; #if FALSE fprintf(stdout, "%d. Thunk for '%s' at %x:%04lx; Target osn = %x:%x\r\n", ovlThunkMac, 1 + GetPropName(apropName), mpgsnseg[gsnOverlay], *praTarget, thunk.osnTgt, thunk.osnOff); #endif } break; case KINDSEG: AddThunk(gsnTarget, psegTarget, praTarget); break; default: InvalidObject(); } } /* * FixOld: * * Process a fixup for an old-format exe. */ void NEAR FixOld () { REGISTER BYTE *pdata; /* Pointer into data record */ SEGTYPE segTarget; /* Fixup target segment */ SEGTYPE segFrame; /* Fixup frame segment */ SEGTYPE gsnTarget; SEGTYPE gsnFrame; RATYPE raTarget; /* Fixup target rel. addr. */ RATYPE raTmp; RATYPE ra; /* Current location offset */ long dra; WORD dsa; WORD saTmp; /* Temporary base variable */ #if OVERLAYS WORD fFallThrough; WORD fThunk; fFallThrough = FALSE; fThunk = FALSE; #endif ra = vraCur + fi.f_dri; /* Get rel. addr. of fixup */ pdata = &rgmi[fi.f_dri]; /* Set pointer to fixup location */ GetFrameTarget(&gsnFrame,&gsnTarget,&raTarget); /* Process the FIXDAT byte */ segTarget = mpgsnseg[gsnTarget]; /* Get target segment */ if(gsnFrame != SNNIL) segFrame = mpgsnseg[gsnFrame]; else segFrame = SEGNIL; if(vsegCur == SEGNIL) return; if(gsnTarget == SNNIL) { if(fi.f_loc == LOCPTR) /* If "pointer" (4 byte) fixup */ { if(mpsegFlags[vsegCur] & FCODE) lastbyte(pdata,ra,CALLFARDIRECT,BREAKPOINT); /* Replace long call w/ breakpoint */ return; } /* Return if "base" (2 byte) fixup */ if(fi.f_loc == LOCSEGMENT) return; } else { if (!fDebSeg && segFrame != SEGNIL) { dsa = mpsegsa[segTarget] - mpsegsa[segFrame]; #if NOT OIAPX286 dra = dsa << 4; raTmp = raTarget + dra; if(dsa >= 0x1000 || raTmp < raTarget) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); raTarget = raTmp; segTarget = segFrame; #else if(dsa) /* No intersegment fixups */ FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); #endif } else segFrame = segTarget; /* Else use target's seg as frame */ if(fi.f_self) /* If self-relative fixup */ { /* Here we process intersegment self-relative fixups. * We assume that the only way this can work is if the * both the target segment and the current segment assume * the same CS, and that CS is the frame segment of the * fixup. A common example is if vsegCur and segTarget * are in the same group represented by segFrame. * If this is true, vsegCur must be >= segFrame, so we * use this assumption in checking for fixup overflow and * adjusting the target offset. */ if (vsegCur != segTarget && !InOneGroup(gsnTarget, gsnFrame)) RelocWarn(ER_fixovfw,ra,gsnFrame,vgsnCur,raTarget); /* * First, determine the distance from segFrame to vsegCur in * paragraphs and bytes. */ dsa = mpsegsa[vsegCur] - mpsegsa[segFrame]; /* dra is the adjustment to make ra relative to segFrame */ dra = (dsa & 0xFFF) << 4; #if NOT OIAPX286 /* If the distance is >= 64K, or if the current offset ra plus * plus the adjustment dra is >= 64K, or if vsegCur is above * segFrame (see above), then we have fixup overflow. */ if (dsa >= 0x1000 || (WORD) (0xFFFF - ra) < (WORD) dra) FixupOverflow(ra,gsnFrame,vgsnCur,raTarget); #else /* In protected mode, intersegment self-relative fixups won't * work. */ if(dsa) FixupOverflow(ra,gsnFrame,vgsnCur,raTarget); #endif /* Determine the fixup value which is raTarget minus the current * location, ra. Adjust ra upward by dra to make it relative * to segFrame, then adjust by the length of the location type * (assume LOCOFFSET as the most common). This reduces to the * expression below. */ raTarget = raTarget - dra - ra - 2; /* Adjust for less likely LOCtypes */ if(fi.f_loc == LOCLOBYTE) raTarget += 1; #if OMF386 else if(fi.f_loc >= LOCOFFSET32) raTarget -= 2; #endif } } raTmp = raTarget; raTarget += fi.f_disp; #if OMF386 if ((rect & 1) && (fi.f_loc >= LOCOFFSET32)) raTarget += getdword(pdata); else #endif raTarget += getword(pdata); switch(fi.f_loc) /* Switch on fixup type */ { case LOCLOBYTE: /* 8-bit "lobyte" fixup */ raTarget = raTmp + B2W(pdata[0]) + fi.f_disp; pdata[0] = (BYTE) raTarget; if(raTarget >= 0x100 && fi.f_self) FixupOverflow(ra,gsnFrame,gsnTarget,raTarget); break; case LOCHIBYTE: /* 8-bit "hibyte" fixup */ raTarget = raTmp + fi.f_disp; pdata[0] = (BYTE) (B2W(pdata[0]) + (raTarget >> 8)); break; #if OMF386 case LOCOFFSET32: /* 32-bit "offset" fixup */ case LOCLOADOFFSET32: if(!(rect & 1)) break; /* Not 386 extension */ fixword(pdata, raTarget); pdata += 2; raTarget >>= 16; /* Get high word, fall through ... */ #if OVERLAYS fFallThrough = TRUE; #endif #endif case LOCOFFSET: /* 16-bit "offset" fixup */ case LOCLOADOFFSET: #if OVERLAYS if (fDynamic && !fFallThrough && !fDebSeg && (fi.f_loc == LOCLOADOFFSET) && (mpsegFlags[vsegCur] & FCODE) && mpsegiov[segTarget]) DoThunking(gsnTarget, &segTarget, &raTarget); #endif fixword(pdata, raTarget); /* Perform fixup */ break; #if OMF386 case LOCPTR48: /* 48-bit "pointer" fixup */ if(!(rect & 1)) break; /* Not 386 extension */ fixword(pdata, raTarget); pdata += 2; raTarget >>= 16; /* Get high word, fall through ... */ #endif case LOCPTR: /* 32-bit "pointer" fixup */ #if OVERLAYS if (!fDebSeg) { /* If root-overlay or interoverlay */ if (fDynamic) { // Gererate thunk if: // // - target is in overlay and // - current position is in different overlay or // - current position is in the same overlay but // in a different segment (assuming initialization // of a far pointer to the function) if (mpsegiov[segTarget] && ((mpsegiov[vsegCur] != mpsegiov[segTarget]) || (mpsegiov[vsegCur] != IOVROOT && vsegCur != segTarget))) { DoThunking(gsnTarget, &segTarget, &raTarget); fThunk = (FTYPE) TRUE; } } else if (mpsegiov[segTarget] && (mpsegiov[vsegCur] != mpsegiov[segTarget])) { if ((mpsegFlags[vsegCur] & FCODE) && lastbyte(pdata,ra,CALLFARDIRECT,INTERRUPT)) { /* If fixing up long call direct */ *pdata++ = vintno; /* Interrupt number */ *pdata++ = (BYTE) Mpgsnosn(gsnTarget); /* Target overlay segment number */ *pdata++ = (BYTE) (raTarget & 0xFF); /* Lo word of offset */ *pdata = (BYTE)((raTarget >> BYTELN) & 0xFF); /* Hi word of target */ break; /* All done */ } } } #endif if (!fDebSeg && fFarCallTrans && mpsegsa[segTarget] == mpsegsa[vsegCur] && (mpsegFlags[segTarget] & FCODE) #if OVERLAYS && mpsegiov[vsegCur] == mpsegiov[segTarget] && !fThunk #endif ) { /* If intrasegment fixup in the same overlay */ if(TransFAR(pdata,ra,raTarget)) break; } /* Root-root, overlay-root, and intraoverlay are normal calls */ fixword(pdata, raTarget); /* Fix up offset */ pdata += 2; /* Advance to segment part and fall through . . . */ ra += 2; #if OVERLAYS fFallThrough = TRUE; #endif case LOCSEGMENT: /* 16-bit "base" fixup */ #if OVERLAYS if (fDynamic && !fDebSeg && (mpsegFlags[vsegCur] & FCODE) && mpsegiov[segTarget]) { if(!fFallThrough) { OutWarn(ER_farovl, 1+GetPropName(FetchSym(mpgsnrprop[gsnTarget],FALSE)), 1+GetPropName(FetchSym(mpgsnrprop[gsnOverlay],FALSE))); segTarget = mpgsnseg[gsnOverlay]; } else { /* intra-overlay pointer fixups not supported - caviar:6806 */ OutError(ER_farovldptr); } } #endif if (fDebSeg) { // For debug segments use logical segment number (seg) // instead of physical segment number (sa) saTmp = segTarget; } else { saTmp = mpsegsa[segTarget]; // If MS OMF, high word is a segment ordinal, for huge model // Shift left by appropriate amount to get selector #if OEXE if (vfNewOMF && !fDynamic) saTmp += (B2W(pdata[0]) + (B2W(pdata[1]) << BYTELN)) << 12; else saTmp += B2W(pdata[0]) + (B2W(pdata[1]) << BYTELN); /* Note fixup is ADDITIVE */ #endif #if OIAPX286 OR OXOUT if(vfNewOMF) saTmp += (B2W(pdata[0]) + (B2W(pdata[1]) << BYTELN)) << 3; #endif /* Note that base fixups are NOT ADDITIVE for Xenix. This is * to get around a bug in "as" which generates meaningless * nonzero values at base fixup locations. */ #if OIAPX286 /* Hack for impure model: code and data are packed into * one physical segment which at runtime is accessed via 2 * selectors. The code selector is 8 below the data selector. */ if(!fIandD && (mpsegFlags[segTarget] & FCODE)) saTmp -= 8; #endif } fixword(pdata, saTmp); /* Perform fixup */ #if NOT OIAPX286 if (!fDebSeg) RecordSegmentReference(vsegCur,ra,segTarget); /* Record reference */ #endif break; default: /* Unsupported fixup type */ RelocErr(ER_fixbad,ra,gsnFrame,gsnTarget,raTarget); break; } } #endif /* ODOS3EXE OR OIAPX286 */ /* * FixRc2: * * Process a FIXUPP record. This is a top-level routine which passes * work out to various subroutines. */ void NEAR FixRc2(void) /* Process a fixup record */ { #if 0 #if SYMDEB // this code is dead -- fDebSeg && !fSymdeb is never true [rm] if (fDebSeg && !fSymdeb) { // If no /CodeView - skip fixups for debug segments SkipBytes((WORD) (cbRec - 1)); return; } #endif #endif if (fSkipFixups) { fSkipFixups = (FTYPE) FALSE; // Only one FIXUP record can be skipped SkipBytes((WORD) (cbRec - 1)); return; } while (cbRec > 1) { // While fixups or threads remain // Get information on fixup if (!GetFixup()) continue; // Fixup thread - keep registering them // If absolute segment skip fixup if (vgsnCur == 0xffff) { SkipBytes((WORD) (cbRec - 1)); return; } #if SYMDEB if (fDebSeg) { if (fi.f_loc == LOCLOADOFFSET) fi.f_loc = LOCOFFSET; /* Save Cmerge's butts */ #if OMF386 if (fi.f_loc == LOCOFFSET32 || fi.f_loc == LOCPTR48) fi.f_fmtd = F5; /* Temp fix until compiler is fixed */ #endif } #endif DoFixup(); } } // BAKPAT record bookeeping typedef struct bphdr // BAKPAT bucket { struct bphdr FAR *next; // Next bucket SNTYPE gsn; // Segment index WORD cnt; // # of BAKPAT entries BYTE loctyp; // Location type BYTE fComdat; // TRUE if NBAKPAT struct bpentry FAR *patch; // Table of BAKPAT entries } BPHDR; struct bpentry // BAKPAT entry { RATYPE ra; // Offset to location to patch #if OMF386 long value; // Value to add to patch location #else int value; // Value to add to patch location #endif }; LOCAL BPHDR FAR *pbpFirst; // List of BAKPAT buckets LOCAL BPHDR FAR *pbpLast; // Tail of BAKPAT list /* * BakPat : Process a BAKPAT record (0xb2) * * Just accumulate the record information in virtual memory; * we will do the backpatching later. */ void NEAR BakPat() { BPHDR FAR *pHdr; // BAKPAT bucket WORD cEntry; WORD comdatIdx; // COMDAT symbol index DWORD comdatRa; // Starting COMDAT offset APROPCOMDATPTR comdat; // Pointer to symbol table entry #if POOL_BAKPAT if (!poolBakpat) poolBakpat = PInit(); #endif /* Get the segment index and location type */ #if POOL_BAKPAT pHdr = (BPHDR FAR *) PAlloc(poolBakpat, sizeof(BPHDR)); #else pHdr = (BPHDR FAR *) GetMem(sizeof(BPHDR)); #endif if (TYPEOF(rect) == BAKPAT) { pHdr->fComdat = (FTYPE) FALSE; pHdr->gsn = mpsngsn[GetIndex(1, (WORD) (snMac - 1))]; pHdr->loctyp = (BYTE) Gets(); comdatRa = 0L; } else { pHdr->fComdat = (BYTE) TRUE; pHdr->loctyp = (BYTE) Gets(); comdatIdx = GetIndex(1, (WORD) (lnameMac - 1)); comdat = (APROPCOMDATPTR ) PropRhteLookup(mplnamerhte[comdatIdx], ATTRCOMDAT, FALSE); if ((comdat->ac_obj != vrpropFile) || !IsSELECTED (comdat->ac_flags)) { // Skip the nbakpat if it concerns an unselected comdat // or a comdat from other .obj SkipBytes((WORD) (cbRec - 1)); return; } else { if (comdat != NULL) { pHdr->gsn = comdat->ac_gsn; comdatRa = comdat->ac_ra; } else InvalidObject(); // Invalid module } } /* If BAKPAT record for CV info and /CO not used - skip record */ #if SYMDEB if (pHdr->gsn == 0xffff) { SkipBytes((WORD) (cbRec - 1)); return; /* Good-bye! */ } #endif switch(pHdr->loctyp) { case LOCLOBYTE: case LOCOFFSET: #if OMF386 case LOCOFFSET32: #endif break; default: InvalidObject(); } /* Determine # of entries */ #if OMF386 if (rect & 1) pHdr->cnt = (WORD) ((cbRec - 1) >> 3); else #endif pHdr->cnt = (WORD) ((cbRec - 1) >> 2); if (pHdr->cnt == 0) { #if NOT POOL_BAKPAT FFREE(pHdr); #endif return; } #if DEBUG sbModule[sbModule[0]+1] = '\0'; fprintf(stdout, "\r\nBakPat in module %s, at %x, entries : %x", sbModule+1, lfaLast,pHdr->cnt); fprintf(stdout, " pHdr %x, pbpLast %x ", pHdr, pbpLast); fprintf(stdout, "\r\n gsn %d ", pHdr->gsn); fflush(stdout); #endif // Store all the BAKPAT entries #if POOL_BAKPAT pHdr->patch = (struct bpentry FAR *) PAlloc(poolBakpat, pHdr->cnt * sizeof(struct bpentry)); #else pHdr->patch = (struct bpentry FAR *) GetMem(pHdr->cnt * sizeof(struct bpentry)); #endif cbBakpat = 1; // only need to show backpatches are present [rm] cEntry = 0; while (cbRec > 1) { #if OMF386 if (rect & 1) { pHdr->patch[cEntry].ra = LGets() + comdatRa; pHdr->patch[cEntry].value = LGets(); } else #endif { pHdr->patch[cEntry].ra = (WORD) (WGets() + comdatRa); pHdr->patch[cEntry].value = WGets(); } cEntry++; } // Add bucket to the list if (pbpFirst == NULL) pbpFirst = pHdr; else pbpLast->next = pHdr; pbpLast = pHdr; } /* * FixBakpat : Fix up backpatches * Called at the end of processing a module in Pass 2. */ void NEAR FixBakpat(void) { BPHDR FAR *pHdr; BPHDR FAR *pHdrNext=NULL; WORD n; BYTE FAR *pSegImage; /* Segment memory image */ SEGTYPE seg; /* Logical segment index */ #if DEBUG int i,iTotal=0,j=1; char *ibase; fprintf(stdout, "\r\nFixBakpat, pbpFirst : %x ", pbpFirst); #endif // Go through the backpatch list and do the backpatches for (pHdr = pbpFirst; pHdr != NULL; pHdr = pHdrNext) { // While there are backpatches remaining, do them #if DEBUG fprintf(stdout, "\r\nBAKPAT at %x, entries : %x ",pHdr,pHdr->cnt); #endif for (n = 0; n < pHdr->cnt; n++) { // Determine the address of the patch location #if SYMDEB if (pHdr->gsn & 0x8000) pSegImage = ((APROPFILEPTR) vrpropFile)->af_cvInfo->cv_sym + pHdr->patch[n].ra; /* In debug segment */ else { #endif seg = mpgsnseg[pHdr->gsn]; if(fNewExe) pSegImage = mpsaMem[mpsegsa[seg]]; else pSegImage = mpsegMem[seg]; /* In other segment */ pSegImage += pHdr->patch[n].ra; if (!pHdr->fComdat) pSegImage += mpgsndra[pHdr->gsn]; else pSegImage += mpsegraFirst[seg]; #if SYMDEB } #endif #if DEBUG fprintf(stdout, "\r\nseg %d, mpsegsa[seg] sa %d ", seg, mpsegsa[seg]); fprintf(stdout, "mpsaMem[seg] %x, mpsegraFirst[seg] %x, pHdr->patch[n].ra %x\r\n", mpsaMem[seg], (int)mpsegraFirst[seg], (int)pHdr->patch[n].ra); fprintf(stdout, " gsn %x, mpgsndra[gsn] %x ",pHdr->gsn,mpgsndra[pHdr->gsn]); ibase = pSegImage - pHdr->patch[n].ra; iTotal = (int) ibase; for(i=0; i<50; i++) { if(j==1) { fprintf( stdout,"\r\n\t%04X\t",iTotal); } fprintf( stdout,"%02X ",*((char*)ibase+i)); iTotal++; if(++j > 16) j=1; } fprintf(stdout, "\r\nseg:ra %x:%x, value : %x",seg,pHdr->patch[n].ra,pHdr->patch[n].value); fflush(stdout); #endif /* Do the fixup according to the location type */ switch(pHdr->loctyp) { case LOCLOBYTE: pSegImage[0] += (BYTE) pHdr->patch[n].value; break; case LOCOFFSET: ((WORD FAR *) pSegImage)[0] += (WORD) pHdr->patch[n].value; break; #if OMF386 case LOCOFFSET32: ((DWORD FAR *) pSegImage)[0]+= (DWORD) pHdr->patch[n].value; break; #endif } } pHdrNext = pHdr->next; #if NOT POOL_BAKPAT FFREE(pHdr); #endif } #if POOL_BAKPAT PReinit(poolBakpat); // reuse same memory again... #endif pbpFirst = NULL; cbBakpat = 0; } #if TCE void NEAR FixRc1(void) /* Process a fixup record */ { if (fSkipFixups) { fSkipFixups = (FTYPE) FALSE; // Only one FIXUP record can be skipped SkipBytes((WORD) (cbRec - 1)); pActiveComdat = NULL; return; } while (cbRec > 1) { // While fixups or threads remain // Get information on fixup if (!GetFixup()) continue; // Fixup thread - keep registering them if(fi.f_mtd == KINDEXT) { RBTYPE rhte; APROPCOMDAT *pUsedComdat; if( mpextprop && mpextprop[fi.f_idx]) // Is there a COMDAT with this name? { rhte = RhteFromProp(mpextprop[fi.f_idx]); ASSERT(rhte); pUsedComdat = PropRhteLookup(rhte, ATTRCOMDAT, FALSE); if(pActiveComdat) { if(pUsedComdat) { AddComdatUses(pActiveComdat, pUsedComdat); #if TCE_DEBUG fprintf(stdout, "\r\nCOMDAT %s uses COMDAT %s ", 1 + GetPropName(pActiveComdat) ,1+ GetPropName(mpextprop[fi.f_idx])); #endif } else { AddComdatUses(pActiveComdat, mpextprop[fi.f_idx]); #if TCE_DEBUG fprintf(stdout, "\r\nCOMDAT %s uses EXTDEF %s ", 1 + GetPropName(pActiveComdat) ,1+ GetPropName(mpextprop[fi.f_idx])); #endif } } else // no COMDAT of this name { if(pUsedComdat) { pUsedComdat->ac_fAlive = TRUE; if(!fDebSeg) { AddTceEntryPoint(pUsedComdat); #if TCE_DEBUG fprintf(stdout, "\r\nLEDATA uses COMDAT %s ", 1 + GetPropName(mpextprop[fi.f_idx])); sbModule[sbModule[0]+1] = '\0'; fprintf(stdout, " module %s, offset %x ", sbModule+1, lfaLast); #endif } } else { if(((APROPUNDEFPTR)mpextprop[fi.f_idx])->au_attr == ATTRUND) { #if TCE_DEBUG fprintf(stdout, "\r\nLEDATA uses EXTDEF %s ", 1 + GetPropName(mpextprop[fi.f_idx])); #endif ((APROPUNDEFPTR)mpextprop[fi.f_idx])->au_fAlive = TRUE; } } } } } } pActiveComdat = NULL; } #endif