mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3715 lines
128 KiB
3715 lines
128 KiB
/*
|
|
* 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
|