bool DETOUR_IA64_BUNDLE::RelocateInstruction()

in src/disasm.cpp [1952:2052]


bool DETOUR_IA64_BUNDLE::RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst,
                                             _In_ BYTE slot,
                                             _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const
/*
    If pBundleExtra is provided and instruction is IP-relative,
    this function relocates instruction to target pBundleExtra,
    pBundleExtra is set to brl the original target, and return true.

    [Not used] If pBundleExtra is not provided and instruction is IP-relative, return true.

    Else return false.

    The following IP-relative forms are recognized:
        br and br.call
        chk.s.m integer and float
        chk.a.nc integer and float
        chk.a.clr integer and float
        chk.s.i
        fchkf

    Brl is handled elsewhere, because the code was previously written.

    Branch prediction hints are not relocated.
*/
{
    UINT64 const instruction = GetInstruction(slot);
    UINT64 const opcode = GetOpcode(instruction);
    size_t const dest = (size_t)pDst;
    size_t const extra = (size_t)pBundleExtra;

    switch (GetUnit(slot)) {
    case F_UNIT:
        // F14 fchkf
        if (opcode == 0 && GetX(instruction) == 0 && GetX6(instruction) == 8) {
            goto imm20a;
        }
        return false;

    case M_UNIT:
        // M20 x3 == 1 integer chk.s.m
        // M21 x3 == 3 floating point chk.s
        if (opcode == 1) {
            UINT64 const x3 = GetX3(instruction);
            if (x3 == 1 || x3 == 3) {
                goto imm13_7;
            }
        }

        // M22 x3 == 4 integer chk.a.nc
        // M22 x3 == 5 integer chk.a.clr
        // M23 x3 == 6 floating point chk.a.nc
        // M23 x3 == 7 floating point chk.a.clr
        if (opcode == 0) {
            UINT64 const x3 = GetX3(instruction);
            if (x3 == 4 || x3 == 5 || x3 == 6 || x3 == 7) {
                goto imm20b;
            }
        }
        return false;
    case I_UNIT:
        // I20
        if (opcode == 0 && GetX3(instruction) == 1) { // chk.s.i
            goto imm13_7;
        }
        return false;
    case B_UNIT:
        // B1 B2 B3
        // 4 br
        // 5 br.call
        if (opcode == 4 || opcode == 5) {
            goto imm20b;
        }
        return false;
    }
    return false;

    UINT64 imm;
    UINT64 new_instruction;

imm13_7:
    imm = SignExtend((GetSignBit(instruction) << 20) | (GetImm13c(instruction) << 7) | GetImm7a(instruction), 21) << 4;
    new_instruction = SetSignBit(SetImm13c(SetImm7a(instruction, (extra - dest) >> 4), (extra - dest) >> 11), extra < dest);
    goto set_brl;

imm20a:
    imm = SignExtend((GetSignBit(instruction) << 20) | GetImm20a(instruction), 21) << 4;
    new_instruction = SetSignBit(SetImm20a(instruction, (extra - dest) >> 4), extra < dest);
    goto set_brl;

imm20b:
    imm = SignExtend((GetSignBit(instruction) << 20) | GetImm20b(instruction), 21) << 4;
    new_instruction = SetSignBit(SetImm20b(instruction, (extra - dest) >> 4), extra < dest);
    goto set_brl;

set_brl:
    if (pBundleExtra != NULL) {
        pDst->SetInstruction(slot, new_instruction);
        pBundleExtra->SetBrl((size_t)this + imm);
    }
    return true;
}