Logo Search packages:      
Sourcecode: virtualbox-ose version File versions  Download package

static int kldrModLXRelocateBits ( PKLDRMOD  pMod,
void *  pvBits,
KLDRADDR  NewBaseAddress,
KLDRADDR  OldBaseAddress,
PFNKLDRMODGETIMPORT  pfnGetImport,
void *  pvUser 
) [static]

Relocates the module bits previously obtained by kLdrModGetBits().

Returns:
0 on succes, non-zero OS or kLdr status code on failure.
Parameters:
pMod The module.
pvBits Where to put the bits.
NewBaseAddress The new base address.
OldBaseAddress The old base address (i.e. the one specified to kLdrModGetBits() or as NewBaseAddressto the previous kLdrModRelocateBits() call).
pfnGetImport The callback ufor resolving external (imported) symbols.
pvUser The callback user argument.

Definition at line 2191 of file kLdrModLX.c.

References KLDRMOD::aSegments, e32_exe::e32_impmodcnt, e32_exe::e32_objcnt, KLDRSEG::fFlags, KLDRMODLX::Hdr, KLDR_ERR_BAD_FIXUP, KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED, KLDRMODLX_ASSERT, kldrModLXDoLoadFixupSection(), kldrModLXDoReloc(), KLDRSEG_FLAG_16BIT, NIL_KLDRMOD_SYM_ORDINAL, NULL, o32_obj::o32_base, o32_obj::o32_mapsize, o32_obj::o32_pagemap, OBJPAGELEN, KLDRMODLX::paObjs, KLDRMODLX::paoffPageFixups, KLDRMODLX::pbFixupRecs, KLDRMODLX::pbFixupSection, KLDRMODLX::pbFixupSectionLast, KLDRMODLX::pbImportProcs, KLDRMODLX::pMod, KLDRMOD::pvData, KLDRSEG::RVA, KLDRSEG::Sel16bit, and KLDRSEG::SelFlat.

Referenced by kldrModLXFixupMapping(), and kldrModLXGetBits().

{
    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
    KU32 iSeg;
    int rc;

    /*
     * Do we need to to *anything*?
     */
    if (    NewBaseAddress == OldBaseAddress
        &&  NewBaseAddress == pModLX->paObjs[0].o32_base
        &&  !pModLX->Hdr.e32_impmodcnt)
        return 0;

    /*
     * Load the fixup section.
     */
    if (!pModLX->pbFixupSection)
    {
        rc = kldrModLXDoLoadFixupSection(pModLX);
        if (rc)
            return rc;
    }

    /*
     * Iterate the segments.
     */
    for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++)
    {
        const struct o32_obj * const pObj = &pModLX->paObjs[iSeg];
        KLDRADDR        PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA;
        KU32            iPage;
        KU8            *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[iSeg].RVA;

        /*
         * Iterate the page map pages.
         */
        for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN)
        {
            const KU8 * const   pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap];
            const KU8          *pb            = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1];
            KLDRADDR            uValue;
            int                 iSelector;
            KU32                fKind;

            /* sanity */
            if (pbFixupRecEnd < pb)
                return KLDR_ERR_BAD_FIXUP;
            if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast)
                return KLDR_ERR_BAD_FIXUP;
            if (pb < pModLX->pbFixupSection)
                return KLDR_ERR_BAD_FIXUP;

            /*
             * Iterate the fixup record.
             */
            while (pb < pbFixupRecEnd)
            {
                union _rel
                {
                    const KU8 *             pb;
                    const struct r32_rlc   *prlc;
                } u;

                u.pb = pb;
                pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */

                /*
                 * Figure out the target.
                 */
                switch (u.prlc->nr_flags & NRRTYP)
                {
                    /*
                     * Internal fixup.
                     */
                    case NRRINT:
                    {
                        KU16 iTrgObject;
                        KU32 offTrgObject;

                        /* the object */
                        if (u.prlc->nr_flags & NR16OBJMOD)
                        {
                            iTrgObject = *(const KU16 *)pb;
                            pb += 2;
                        }
                        else
                            iTrgObject = *pb++;
                        iTrgObject--;
                        if (iTrgObject >= pModLX->Hdr.e32_objcnt)
                            return KLDR_ERR_BAD_FIXUP;

                        /* the target */
                        if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG)
                        {
                            if (u.prlc->nr_flags & NR32BITOFF)
                            {
                                offTrgObject = *(const KU32 *)pb;
                                pb += 4;
                            }
                            else
                            {
                                offTrgObject = *(const KU16 *)pb;
                                pb += 2;
                            }

                            /* calculate the symbol info. */
                            uValue = offTrgObject + NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
                        }
                        else
                            uValue = NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
                        if (    (u.prlc->nr_stype & NRALIAS)
                            ||  (pMod->aSegments[iTrgObject].fFlags & KLDRSEG_FLAG_16BIT))
                            iSelector = pMod->aSegments[iTrgObject].Sel16bit;
                        else
                            iSelector = pMod->aSegments[iTrgObject].SelFlat;
                        fKind = 0;
                        break;
                    }

                    /*
                     * Import by symbol ordinal.
                     */
                    case NRRORD:
                    {
                        KU16 iModule;
                        KU32 iSymbol;

                        /* the module ordinal */
                        if (u.prlc->nr_flags & NR16OBJMOD)
                        {
                            iModule = *(const KU16 *)pb;
                            pb += 2;
                        }
                        else
                            iModule = *pb++;
                        iModule--;
                        if (iModule >= pModLX->Hdr.e32_impmodcnt)
                            return KLDR_ERR_BAD_FIXUP;
#if 1
                        if (u.prlc->nr_flags & NRICHAIN)
                            return KLDR_ERR_BAD_FIXUP;
#endif

                        /* . */
                        if (u.prlc->nr_flags & NR32BITOFF)
                        {
                            iSymbol = *(const KU32 *)pb;
                            pb += 4;
                        }
                        else if (!(u.prlc->nr_flags & NR8BITORD))
                        {
                            iSymbol = *(const KU16 *)pb;
                            pb += 2;
                        }
                        else
                            iSymbol = *pb++;

                        /* resolve it. */
                        rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser);
                        if (rc)
                            return rc;
                        iSelector = -1;
                        break;
                    }

                    /*
                     * Import by symbol name.
                     */
                    case NRRNAM:
                    {
                        KU32 iModule;
                        KU16 offSymbol;
                        const KU8 *pbSymbol;

                        /* the module ordinal */
                        if (u.prlc->nr_flags & NR16OBJMOD)
                        {
                            iModule = *(const KU16 *)pb;
                            pb += 2;
                        }
                        else
                            iModule = *pb++;
                        iModule--;
                        if (iModule >= pModLX->Hdr.e32_impmodcnt)
                            return KLDR_ERR_BAD_FIXUP;
#if 1
                        if (u.prlc->nr_flags & NRICHAIN)
                            return KLDR_ERR_BAD_FIXUP;
#endif

                        /* . */
                        if (u.prlc->nr_flags & NR32BITOFF)
                        {
                            offSymbol = *(const KU32 *)pb;
                            pb += 4;
                        }
                        else if (!(u.prlc->nr_flags & NR8BITORD))
                        {
                            offSymbol = *(const KU16 *)pb;
                            pb += 2;
                        }
                        else
                            offSymbol = *pb++;
                        pbSymbol = pModLX->pbImportProcs + offSymbol;
                        if (    pbSymbol < pModLX->pbImportProcs
                            ||  pbSymbol > pModLX->pbFixupSectionLast)
                            return KLDR_ERR_BAD_FIXUP;

                        /* resolve it. */
                        rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL,
                                          &uValue, &fKind, pvUser);
                        if (rc)
                            return rc;
                        iSelector = -1;
                        break;
                    }

                    case NRRENT:
                        KLDRMODLX_ASSERT(!"NRRENT");
                    default:
                        iSelector = -1;
                        break;
                }

                /* addend */
                if (u.prlc->nr_flags & NRADD)
                {
                    if (u.prlc->nr_flags & NR32BITADD)
                    {
                        uValue += *(const KU32 *)pb;
                        pb += 4;
                    }
                    else
                    {
                        uValue += *(const KU16 *)pb;
                        pb += 2;
                    }
                }


                /*
                 * Deal with the 'source' (i.e. the place that should be modified - very logical).
                 */
                if (!(u.prlc->nr_stype & NRCHAIN))
                {
                    int off = u.prlc->r32_soff;

                    /* common / simple */
                    if (    (u.prlc->nr_stype & NRSRCMASK) == NROFF32
                        &&  off >= 0
                        &&  off <= OBJPAGELEN - 4)
                        *(KU32 *)&pbPage[off] = uValue;
                    else if (    (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32
                            &&  off >= 0
                            &&  off <= OBJPAGELEN - 4)
                        *(KU32 *)&pbPage[off] = uValue - (PageAddress + off + 4);
                    else
                    {
                        /* generic */
                        rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
                        if (rc)
                            return rc;
                    }
                }
                else if (!(u.prlc->nr_flags & NRICHAIN))
                {
                    const KI16 *poffSrc = (const KI16 *)pb;
                    KU8 c = u.pb[2];

                    /* common / simple */
                    if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32)
                    {
                        while (c-- > 0)
                        {
                            int off = *poffSrc++;
                            if (off >= 0 && off <= OBJPAGELEN - 4)
                                *(KU32 *)&pbPage[off] = uValue;
                            else
                            {
                                rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
                                if (rc)
                                    return rc;
                            }
                        }
                    }
                    else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32)
                    {
                        while (c-- > 0)
                        {
                            int off = *poffSrc++;
                            if (off >= 0 && off <= OBJPAGELEN - 4)
                                *(KU32 *)&pbPage[off] = uValue - (PageAddress + off + 4);
                            else
                            {
                                rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
                                if (rc)
                                    return rc;
                            }
                        }
                    }
                    else
                    {
                        while (c-- > 0)
                        {
                            rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind);
                            if (rc)
                                return rc;
                        }
                    }
                    pb = (const KU8 *)poffSrc;
                }
                else
                {
                    /* This is a pain because it will require virgin pages on a relocation. */
                    KLDRMODLX_ASSERT(!"NRICHAIN");
                    return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED;
                }
            }
        }
    }

    return 0;
}


Generated by  Doxygen 1.6.0   Back to index