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

static int kldrModPEDoFixups ( PKLDRMODPE  pModPE,
void *  pvMapping,
KLDRADDR  NewBaseAddress,
KLDRADDR  OldBaseAddress 
) [static]

Applies base relocations to a (unprotected) image mapping.

Returns:
0 on success, non-zero kLdr status code on failure.
Parameters:
pModPE The PE module interpreter instance.
pvMapping The mapping to fixup.
NewBaseAddress The address to fixup the mapping to.
OldBaseAddress The address the mapping is currently fixed up to.

Definition at line 1386 of file kLdrModPE.c.

References KLDRMODPE::Hdrs, K_MIN, KLDR_ERR_PE_BAD_FIXUP, KLDRMODPE_ASSERT, and KLDRMODPE_RVA2TYPE.

Referenced by kldrModPEFixupMapping(), and kldrModPERelocateBits().

{
    const KLDRADDR                  Delta = NewBaseAddress - OldBaseAddress;
    KU32                            cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    const IMAGE_BASE_RELOCATION    *pBR, *pFirstBR;

    /*
     * Don't don anything if the delta is 0 or there aren't any relocations.
     */
    if (    !Delta
        ||  !cbLeft
        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
        return 0;

    /*
     * Process the fixups block by block.
     * (These blocks appears to be 4KB on all archs despite the native page size.)
     */
    pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping,
                                        pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
                                        const IMAGE_BASE_RELOCATION *);
    while (     cbLeft > sizeof(IMAGE_BASE_RELOCATION)
           &&   pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */)
    {
        union
        {
            KU8        *pu8;
            KU16       *pu16;
            KU32       *pu32;
            KU64       *pu64;
        }               uChunk,
                        u;
        const KU16 *poffFixup = (const KU16 *)(pBR + 1);
        const KU32  cbBlock = K_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */
        KU32        cFixups = cbBlock / sizeof(poffFixup[0]);
        uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, KU8 *);

        /*
         * Loop thru the fixups in this chunk.
         */
        while (cFixups > 0)
        {
            u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff);
            switch (*poffFixup >> 12) /* ordered by value. */
            {
                /* 0 - Alignment placeholder. */
                case IMAGE_REL_BASED_ABSOLUTE:
                    break;

                /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */
                case IMAGE_REL_BASED_HIGH:
                    *u.pu16 += (KU16)(Delta >> 16);
                    break;

                /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */
                case IMAGE_REL_BASED_LOW:
                    *u.pu16 += (KU16)Delta;
                    break;

                /* 3 - 32-bit, add delta. (frequent in 32-bit images) */
                case IMAGE_REL_BASED_HIGHLOW:
                    *u.pu32 += (KU32)Delta;
                    break;

                /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare)  */
                case IMAGE_REL_BASED_HIGHADJ:
                {
                    KI32 i32;
                    if (cFixups <= 1)
                        return KLDR_ERR_PE_BAD_FIXUP;

                    i32 = (KU32)*u.pu16 << 16;
                    i32 |= *++poffFixup; cFixups--; /* the addend argument */
                    i32 += (KU32)Delta;
                    i32 += 0x8000;
                    *u.pu16 = (KU16)(i32 >> 16);
                    break;
                }

                /* 5 - 32-bit MIPS JMPADDR, no implemented. */
                case IMAGE_REL_BASED_MIPS_JMPADDR:
                    *u.pu32 = (*u.pu32 & 0xc0000000)
                            | ((KU32)((*u.pu32 << 2) + (KU32)Delta) >> 2);
                    break;

                /* 6 - Intra section? Reserved value in later specs. Not implemented. */
                case IMAGE_REL_BASED_SECTION:
                    KLDRMODPE_ASSERT(!"SECTION");
                    return KLDR_ERR_PE_BAD_FIXUP;

                /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */
                case IMAGE_REL_BASED_REL32:
                    KLDRMODPE_ASSERT(!"SECTION");
                    return KLDR_ERR_PE_BAD_FIXUP;

                /* 8 - reserved according to binutils... */
                case 8:
                    KLDRMODPE_ASSERT(!"RESERVERED8");
                    return KLDR_ERR_PE_BAD_FIXUP;

                /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet.
                 * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */
                case IMAGE_REL_BASED_IA64_IMM64:
                    KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16");
                    return KLDR_ERR_PE_BAD_FIXUP;

                /* 10 - 64-bit, add delta. (frequently in 64-bit images) */
                case IMAGE_REL_BASED_DIR64:
                    *u.pu64 += (KU64)Delta;
                    break;

                /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */
                case IMAGE_REL_BASED_HIGH3ADJ:
                {
                    KI64 i64;
                    if (cFixups <= 2)
                        return KLDR_ERR_PE_BAD_FIXUP;

                    i64 = (KU64)*u.pu16 << 32
                        | ((KU32)poffFixup[2] << 16)
                        | poffFixup[1];
                    i64 += Delta;
                    i64 += 0x80008000UL;
                    *u.pu16 = (KU16)(i64 >> 32);
                    /* skip the addends arguments */
                    poffFixup += 2;
                    cFixups -= 2;
                    break;
                }

                /* the rest are yet to be defined.*/
                default:
                    return KLDR_ERR_PE_BAD_FIXUP;
            }

            /*
             * Next relocation.
             */
            poffFixup++;
            cFixups--;
        }


        /*
         * Next block.
         */
        cbLeft -= pBR->SizeOfBlock;
        pBR = (PIMAGE_BASE_RELOCATION)((KUPTR)pBR + pBR->SizeOfBlock);
    }

    return 0;
}


Generated by  Doxygen 1.6.0   Back to index