unsigned OptShift2(CodeSeg* S) /* A call to the asrax1 routines may get replaced by something simpler, if * X is not used later: * * cmp #$80 * ror a * */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { unsigned Shift; unsigned Count; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_JSR && (Shift = GetShift (E->Arg)) != SHIFT_NONE && SHIFT_TYPE (Shift) == SHIFT_TYPE_ASR && (Count = SHIFT_COUNT (Shift)) > 0 && Count * 100 <= S->CodeSizeFactor && !RegXUsed (S, I+1)) { CodeEntry* X; unsigned J = I+1; /* Generate the replacement sequence */ while (Count--) { /* cmp #$80 */ X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, E->LI); CS_InsertEntry (S, X, J++); /* ror a */ X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, J++); } /* Delete the call to asrax */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) { union offset_union offset; unsigned long instr, instrptr; int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); unsigned int type; instrptr = instruction_pointer(regs); instr = *(unsigned long *)instrptr; if (user_mode(regs)) goto user; ai_sys += 1; fixup: regs->ARM_pc += 4; switch (CODING_BITS(instr)) { case 0x00000000: /* ldrh or strh */ if (LDSTH_I_BIT(instr)) offset.un = (instr & 0xf00) >> 4 | (instr & 15); else offset.un = regs->uregs[RM_BITS(instr)]; handler = do_alignment_ldrhstrh; break; case 0x04000000: /* ldr or str immediate */ offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; case 0x06000000: /* ldr or str register */ offset.un = regs->uregs[RM_BITS(instr)]; if (IS_SHIFT(instr)) { unsigned int shiftval = SHIFT_BITS(instr); switch(SHIFT_TYPE(instr)) { case SHIFT_LSL: offset.un <<= shiftval; break; case SHIFT_LSR: offset.un >>= shiftval; break; case SHIFT_ASR: offset.sn >>= shiftval; break; case SHIFT_RORRRX: if (shiftval == 0) { offset.un >>= 1; if (regs->ARM_cpsr & PSR_C_BIT) offset.un |= 1 << 31; } else offset.un = offset.un >> shiftval | offset.un << (32 - shiftval); break; }
static int do_alignment(unsigned long addr, unsigned int error_code, struct pt_regs *regs) { union offset_union offset; unsigned long instr, instrptr; int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); unsigned int type; if (user_mode(regs)) ai_user += 1; else ai_sys += 1; instrptr = instruction_pointer(regs); if (instrptr >= SVC_SPACE) instr = *(unsigned long *)instrptr; else { __asm__ __volatile__( "ldw.u %0, [%1]\n" :"=&r"(instr) :"r"(instrptr)); } regs->UCreg_pc += 4; switch (CODING_BITS(instr)) { case 0x40000120: /* ldrh or strh */ if (LDSTH_I_BIT(instr)) offset.un = (instr & 0x3e00) >> 4 | (instr & 31); else offset.un = regs->uregs[RM_BITS(instr)]; handler = do_alignment_ldrhstrh; break; case 0x60000000: /* ldr or str immediate */ case 0x60000100: /* ldr or str immediate */ case 0x60000020: /* ldr or str immediate */ case 0x60000120: /* ldr or str immediate */ offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; case 0x40000000: /* ldr or str register */ offset.un = regs->uregs[RM_BITS(instr)]; { unsigned int shiftval = SHIFT_BITS(instr); switch(SHIFT_TYPE(instr)) { case SHIFT_LSL: offset.un <<= shiftval; break; case SHIFT_LSR: offset.un >>= shiftval; break; case SHIFT_ASR: offset.sn >>= shiftval; break; case SHIFT_RORRRX: if (shiftval == 0) { offset.un >>= 1; if (regs->UCreg_csr & PSR_C_BIT) offset.un |= 1 << 31; } else offset.un = offset.un >> shiftval | offset.un << (32 - shiftval); break; }