⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unwind.c

📁 windows ce 3.00 嵌入式操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
            // We know that as of this instruction, r11 is a valid frame
            // pointer.  Therefore, it contains the stack value immediately
            // before the STM that set up the stack frame.  So, we scan
            // backward to find the STM, pretend it was a STM using r11 as the
            // base register with no update, and reverse-execute it.

            j = i - 1;
            while (j >= 0 && (Prolog[j].instruction & STM_MASK) != STM_INSTR)
                j--;

            if ( j >= 0 ){

                // Tweak the instruction so it will be reverse-executed
                // correctly.  A convenient side-effect of this is that it
                // prevents it from being recognized as a STM when we continue
                // reverse-executing, which is good because we don't want to do it
                // again.

                Prolog[j].ldm.l = TRUE;
                Prolog[j].ldm.rn = 11;
                Prolog[j].ldm.w = FALSE;
                if (!UnwindLoadMultiple(Prolog[j], Register))
                    return ControlPc;
            }

        }
    }
    
    // The continuation address is contained in the link register.
    
    *EstablisherFrame = Register[13];
    if (!HaveExceptionPc)
        NextPc = Register[14] - 4;
    return NextPc;
}


VOID
UnwindDataProcess(ARMI instr, PULONG Register)
/*++
Routine Description:
    This function executes an ARM data processing instruction using the
    current register set. It automatically updates the destination register.

Arguments:
    instr      The ARM 32-bit instruction

    Register   Pointer to the ARM integer registers.

Return Value:
    None.
--*/
{
    ULONG Op1, Op2;
    ULONG Cflag = (Register[16] & 0x20000000L) == 0x20000000L; // CPSR
    ULONG shift;

    // We are checking for all addressing modes and op codes, even though
    // the prolog and epilog don't use them all right now.  In the future,
    // more instructions and addressing modes may be added.
    //
    // Figure out the addressing mode (there are 11 of them), and get the
    // operands.
    Op1 = Register[instr.dataproc.rn];
    if (instr.dataproc.bits == 0x1) {
        // Immediate addressing - Type 1
        Op2 = _lrotr(instr.dpi.immediate, instr.dpi.rotate * 2);

    } else {
        // Register addressing - start by getting the value of Rm.
        Op2 = Register[instr.dpshi.rm];
        if (instr.dprre.bits == 0x6) {
            // Rotate right with extended - Type 11
            Op2 = (Cflag << 31) | (Op2 >> 1);

        } else if (instr.dataproc.operand2 & 0x10) {
            // Register shifts. Types 4, 6, 8, and 10
            //
            // Get the shift value from the least-significant byte of the
            // shift register.
            shift = Register[instr.dpshr.rs] & 0xFF;
            switch(instr.dpshr.bits) {
            case 0x1: //  4 Logical shift left by register
                if (shift >= 32)
                    Op2 = 0;
                else
                    Op2 = Op2 << shift;
                break;

            case 0x3: //  6 Logical shift right by register
                if (shift >= 32)
                    Op2 = 0;
                else
                    Op2 = Op2 >> shift;
                break;

            case 0x5: //  8 Arithmetic shift right by register
                if (shift >= 32) {
                    if (Op2 & 0x80000000)
                        Op2 = 0xffffffff;
                    else
                        Op2 = 0;
                } else
                    Op2 = (LONG)Op2 >> shift;
                break;

            case 0x7: // 10 Rotate right by register
                if ((shift & 0xf) != 0)
                    Op2 = _lrotl(Op2, shift);
            default:
                break;
            }

        } else {
            // Immediate shifts. Types 2, 3, 5, 7, and 9
            //
            // Get the shift value from the instruction.
            shift = instr.dpshi.shift;
            switch(instr.dpshi.bits) {
            case 0x0: // 2,3 Register, Logical shift left by immediate
                if (shift != 0)
                    Op2 = Op2 << shift;
                break;

            case 0x2: // 5 Logical shift right by immediate
                if (shift == 0)
                    Op2 = 0;
                else
                    Op2 = Op2 >> shift;
                break;

            case 0x4: // 7 Arithmetic shift right by immediate
                if (shift == 0)
                    Op2 = 0;
                else
                    Op2 = (LONG)Op2 >> shift;
                break;

            case 0x6: // 9 Rotate right by immediate
                Op2 = _lrotl(Op2, shift);
                break;

            default:
                break;
            }
        }
    }

    // Determine the result (the new PC), based on the opcode.
    switch(instr.dataproc.opcode) {
    case OP_AND:
        Register[instr.dataproc.rd] = Op1 & Op2;
        break;

    case OP_EOR:
        Register[instr.dataproc.rd] = Op1 ^ Op2;
        break;

    case OP_SUB:
        Register[instr.dataproc.rd] = Op1 - Op2;
        break;

    case OP_RSB:
        Register[instr.dataproc.rd] = Op2 - Op1;
        break;

    case OP_ADD:
        Register[instr.dataproc.rd] = Op1 + Op2;
        break;

    case OP_ADC:
        Register[instr.dataproc.rd] = (Op1 + Op2) + Cflag;
        break;

    case OP_SBC:
        Register[instr.dataproc.rd] = (Op1 - Op2) - ~Cflag;
        break;

    case OP_RSC:
        Register[instr.dataproc.rd] = (Op2 - Op1) - ~Cflag;
        break;

    case OP_ORR:
        Register[instr.dataproc.rd] = Op1 | Op2;
        break;

    case OP_MOV:
        Register[instr.dataproc.rd] = Op2;
        break;

    case OP_BIC:
        Register[instr.dataproc.rd] = Op1 & ~Op2;
        break;

    case OP_MVN:
        Register[instr.dataproc.rd] = ~Op2;
        break;

    case OP_TST:
    case OP_TEQ:
    case OP_CMP:
    case OP_CMN:
    default:
        // These instructions do not have a destination register.
        // There is nothing to do.
        break;
    }
}

BOOL
UnwindLoadMultiple(ARMI instr, PULONG Register)
/*++
Routine Description:
    This function executes an ARM load multiple instruction.

Arguments:
    instr           The ARM 32-bit instruction

    Register        Pointer to the ARM integer registers.

Return Value:
    TRUE if successful, FALSE otherwise.
--*/
{
    LONG i;
    ULONG RegList;
    PULONG Rn;

    // Load multiple with the PC bit set.  We are currently checking for all
    // four addressing modes, even though decrement before and increment
    // after are the only modes currently used in the epilog and prolog.
    //
    // Rn is the address at which to begin, and RegList is the bit map of which
    // registers to read.
    Rn = (PULONG)Register[instr.ldm.rn];
    RegList = instr.ldm.reglist;
    if (instr.ldm.p) {
        if (instr.ldm.u) {
            // Increment before
            for(i = 0; i <= 15; i++) {
                if (RegList & 0x1) {
                    Rn++;
                    if (!ReadMemory(Rn, &Register[i], 4))
                        return FALSE;
                }
                RegList = RegList >> 1;
            }
        } else {
            // Decrement before
            for(i = 15; i >= 0; i--) {
                if (RegList & 0x8000) {
                    Rn--;
                    if (!ReadMemory(Rn, &Register[i], 4))
                        return FALSE;
                }
                RegList = RegList << 1;
            }
        }
    } else {
        if (instr.ldm.u) {
            // Increment after
            for(i = 0; i <= 15; i++) {
                if (RegList & 0x1) {
                    if (!ReadMemory(Rn, &Register[i], 4))
                        return FALSE;
                    Rn++;
                }
                RegList = RegList >> 1;
            }
        } else {
            // Decrement after
            for(i = 15; i >= 0; i--) {
                if (RegList & 0x8000) {
                    if (!ReadMemory(Rn, &Register[i], 4))
                        return FALSE;
                    Rn--;
                }
                RegList = RegList << 1;
            }
        }
    }

    if (instr.ldm.w)
        Register[instr.ldm.rn] = (ULONG)Rn; // Update the base register.
    return TRUE;
}

BOOL
UnwindLoadI(ARMI instr, PULONG Register)
/*++
Routine Description:
    This function executes an ARM load instruction with an immediat offset.

Arguments:
    instr           The ARM 32-bit instruction

    Register        Pointer to the ARM integer registers.

Return Value:
    TRUE if successful, FALSE otherwise.
--*/
{
    LONG offset;
    LONG size;
    PULONG Rn;

    Rn = (PULONG)Register[instr.ldr.rn];
    offset = instr.ldr.offset;
    if (instr.ldr.u == 0)
        offset = -offset;
    if (instr.ldr.b == 0)
        size = 4;
    else
        size = 1;

    if (instr.ldm.p) { // add offset before transfer
        if (!ReadMemory(Rn + offset, &Register[instr.ldr.rd], size))
            return FALSE;
        if (instr.ldr.w)
            Register[instr.ldr.rn] += offset;
    } else {
        if (!ReadMemory(Rn, &Register[instr.ldr.rd], size))
            return FALSE;
        if (instr.ldr.w)
            Register[instr.ldr.rn] += offset;
    }

    return TRUE;
}

BOOL
CheckConditionCodes(ULONG CPSR, DWORD instr)
/*++
Routine Description:
    Checks the condition codes of the instruction and the values of the
    condition flags in the current program status register, and determines
    whether or not the instruction will be executed.

Arguments:
    CPSR    -   The value of the Current Program Status Register.
    instr   -   The instruction to analyze.

Return Value:
    TRUE if the instruction will be executed, FALSE otherwise.
--*/
{
    BOOL Execute = FALSE;
    BOOL Nset = (CPSR & 0x80000000L) == 0x80000000L;
    BOOL Zset = (CPSR & 0x40000000L) == 0x40000000L;
    BOOL Cset = (CPSR & 0x20000000L) == 0x20000000L;
    BOOL Vset = (CPSR & 0x10000000L) == 0x10000000L;

    switch(instr & COND_MASK) {
    case COND_EQ:   // Z set
        if (Zset) Execute = TRUE;
        break;

    case COND_NE:   // Z clear
        if (!Zset) Execute = TRUE;
        break;

    case COND_CS:   // C set
        if (Cset) Execute = TRUE;
        break;

    case COND_CC:   // C clear
        if (!Cset) Execute = TRUE;
        break;

    case COND_MI:   // N set
        if (Nset) Execute = TRUE;
        break;

    case COND_PL:   // N clear
        if (!Nset) Execute = TRUE;
        break;

    case COND_VS:   // V set
        if (Vset) Execute = TRUE;
        break;

    case COND_VC:   // V clear
        if (!Vset) Execute = TRUE;
        break;

    case COND_HI:   // C set and Z clear
        if (Cset && !Zset) Execute = TRUE;
        break;

    case COND_LS:   // C clear or Z set
        if (!Cset || Zset) Execute = TRUE;
        break;

    case COND_GE:   // N == V
        if ((Nset && Vset) || (!Nset && !Vset)) Execute = TRUE;
        break;

    case COND_LT:   // N != V
        if ((Nset && !Vset) || (!Nset && Vset)) Execute = TRUE;
        break;

    case COND_GT:   // Z clear, and N == V
        if (!Zset &&
          ((Nset && Vset) || (!Nset && !Vset))) Execute = TRUE;
        break;

    case COND_LE:   // Z set, and N != V
        if (Zset &&
          ((Nset && !Vset) || (!Nset && Vset))) Execute = TRUE;
        break;

    case COND_AL:   // Always execute
        Execute = TRUE;
        break;

    default:
    case COND_NV:   // Never - undefined.
        Execute = FALSE;
        break;
    }
    return Execute;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -