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

3716 lines
128 KiB
C
Raw Blame History

This file contains invisible Unicode characters

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

/*
* 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 <minlit.h> /* Types and constants */
#include <bndtrn.h> /* Basic types and constants */
#include <bndrel.h> /* Relocation definitions */
#include <lnkio.h> /* Linker I/O definitions */
#include <newexe.h> /* DOS & 286 .EXE format structure def.s */
#if EXE386
#include <exe386.h> /* 386 .EXE format structure def.s */
#include <fixup386.h> /* Linker internal fixup representation */
#endif
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External declarations */
#include <nmsg.h> /* 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);
pdata[0] = (BYTE)w;
pdata[1] = (BYTE)(w>>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:<nnn> with <nnn> 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