Implement repe scas. coregrind/vg_to_ucode.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 64 insertions(+), 1 deletion(-) diff -puN coregrind/vg_to_ucode.c~76-repe-scas coregrind/vg_to_ucode.c --- local/coregrind/vg_to_ucode.c~76-repe-scas 2003-10-13 21:26:18.781838784 -0700 +++ local-jeremy/coregrind/vg_to_ucode.c 2003-10-13 21:26:18.797836352 -0700 @@ -1900,7 +1900,7 @@ void codegen_REPNE_SCAS ( UCodeBlock* cb uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty); uInstr1(cb, POP, 4, TempReg, tv); - uInstr0(cb, CALLM_E, 0); + uInstr0(cb, CALLM_E, 0); if (sz == 4 || sz == 2) { uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv); @@ -1917,6 +1917,56 @@ void codegen_REPNE_SCAS ( UCodeBlock* cb uCond(cb, CondAlways); } +/* Template for REPE SCAS. Assumes this insn is the last one in + the basic block, and so emits a jump to the next insn. */ +static +void codegen_REPE_SCAS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next ) +{ + Int ta /* EAX */, tc /* ECX */, td /* EDI */, tv; + ta = newTemp(cb); + tc = newTemp(cb); + tv = newTemp(cb); + td = newTemp(cb); + + uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc); + uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0); + uLiteral(cb, eip_next); + uInstr1(cb, DEC, 4, TempReg, tc); + uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX); + + uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta); + uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td); + uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv); + /* next uinstr kills ta, but that's ok -- don't need it again */ + uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta); + setFlagsFromUOpcode(cb, SUB); + + uInstr0(cb, CALLM_S, 0); + uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv); + uLiteral(cb, 0); + uInstr1(cb, PUSH, 4, TempReg, tv); + + uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag)); + uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty); + + uInstr1(cb, POP, 4, TempReg, tv); + uInstr0(cb, CALLM_E, 0); + + if (sz == 4 || sz == 2) { + uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv); + uLiteral(cb, sz/2); + } + uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td); + uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI); + uInstr1(cb, JMP, 0, Literal, 0); + uLiteral(cb, eip); + uCond(cb, CondZ); + uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty); + uInstr1(cb, JMP, 0, Literal, 0); + uLiteral(cb, eip_next); + uCond(cb, CondAlways); +} + /* Template for REPE MOVS. Assumes this insn is the last one in the basic block, and so emits a jump to the next insn. */ @@ -5483,6 +5533,12 @@ static Addr disInstr ( UCodeBlock* cb, A if (dis) VG_(printf)("scasb\n"); break; + case 0xAF: /* SCASl, no REP prefix */ + vg_assert(sorb == 0); + codegen_SCAS ( cb, sz ); + if (dis) VG_(printf)("scas;\n"); + break; + case 0xFC: /* CLD */ uInstr0(cb, CALLM_S, 0); uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD)); @@ -5560,6 +5616,13 @@ static Addr disInstr ( UCodeBlock* cb, A if (dis) VG_(printf)("repe stos%c\n", nameISize(sz)); } else + if (abyte == 0xAE || abyte == 0xAF) { /* REPE SCAS */ + if (abyte == 0xAE) sz = 1; + codegen_REPE_SCAS ( cb, sz, eip_orig, eip ); + *isEnd = True; + if (dis) VG_(printf)("repe scas%c\n", nameISize(sz)); + } + else if (abyte == 0x90) { /* REPE NOP (PAUSE) */ if (dis) VG_(printf)("repe nop (P4 pause)\n"); /* do nothing; apparently a hint to the P4 re spin-wait loop */ _