/*
 *  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