diff --git a/coregrind/vg_helpers.S b/coregrind/vg_helpers.S index 270caac3b..ea7614eb9 100644 --- a/coregrind/vg_helpers.S +++ b/coregrind/vg_helpers.S @@ -94,6 +94,7 @@ VG_(tramp_syscall_offset): * integer multiplication * setting and getting obscure eflags * double-length shifts + * eight byte compare and exchange All routines use a standard calling convention designed for calling from translations, in which the incoming args are @@ -630,6 +631,29 @@ VG_(helper_idiv_16_8): ret +/* Eight byte compare and exchange. */ +.globl VG_(helper_cmpxchg8b) +VG_(helper_cmpxchg8b): + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + movl 20(%esp), %eax + movl 24(%esp), %edx + movl 28(%esp), %ebx + movl 32(%esp), %ecx + cmpxchg8b 36(%esp) + movl %eax, 20(%esp) + movl %edx, 24(%esp) + movl %ebx, 28(%esp) + movl %ecx, 32(%esp) + popl %edx + popl %ecx + popl %ebx + popl %eax + ret + + /* Undefined instruction (generates SIGILL) */ .globl VG_(helper_undefined_instruction) VG_(helper_undefined_instruction): diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index a7f5f60f1..1e79e56b3 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -1745,6 +1745,8 @@ extern void VG_(helper_LAHF); extern void VG_(helper_DAS); extern void VG_(helper_DAA); +extern void VG_(helper_cmpxchg8b); + extern void VG_(helper_undefined_instruction); /* Information about trampoline code (for signal return and syscalls) */ diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index d91f48729..db93c7c49 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -102,6 +102,7 @@ Int VGOFF_(helper_SAHF) = INVALID_OFFSET; Int VGOFF_(helper_LAHF) = INVALID_OFFSET; Int VGOFF_(helper_DAS) = INVALID_OFFSET; Int VGOFF_(helper_DAA) = INVALID_OFFSET; +Int VGOFF_(helper_cmpxchg8b) = INVALID_OFFSET; Int VGOFF_(helper_undefined_instruction) = INVALID_OFFSET; /* MAX_NONCOMPACT_HELPERS can be increased easily. If MAX_COMPACT_HELPERS is @@ -422,6 +423,8 @@ static void vg_init_baseBlock ( void ) = alloc_BaB_1_set( (Addr) & VG_(helper_IN)); VGOFF_(helper_OUT) = alloc_BaB_1_set( (Addr) & VG_(helper_OUT)); + VGOFF_(helper_cmpxchg8b) + = alloc_BaB_1_set( (Addr) & VG_(helper_cmpxchg8b)); VGOFF_(helper_undefined_instruction) = alloc_BaB_1_set( (Addr) & VG_(helper_undefined_instruction)); diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c index e05c44980..0240cebab 100644 --- a/coregrind/vg_to_ucode.c +++ b/coregrind/vg_to_ucode.c @@ -2754,7 +2754,7 @@ Addr dis_cmpxchg_G_E ( UCodeBlock* cb, uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src); uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc); - uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk); + uInstr2(cb, MOV, 4, TempReg, acc, TempReg, junk); uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk); setFlagsFromUOpcode(cb, SUB); @@ -2776,6 +2776,74 @@ Addr dis_cmpxchg_G_E ( UCodeBlock* cb, } +static +Addr dis_cmpxchg8b ( UCodeBlock* cb, + UChar sorb, + Addr eip0 ) +{ + Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch; + UChar dis_buf[50]; + UChar rm; + UInt pair; + + rm = getUChar(eip0); + accl = newTemp(cb); + acch = newTemp(cb); + srcl = newTemp(cb); + srch = newTemp(cb); + destl = newTemp(cb); + desth = newTemp(cb); + junkl = newTemp(cb); + junkh = newTemp(cb); + + vg_assert(!epartIsReg(rm)); + + pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL ); + tal = LOW24(pair); + tah = newTemp(cb); + uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah); + uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah); + uLiteral(cb, 4); + eip0 += HI8(pair); + if (dis) VG_(printf)("cmpxchg8b %s\n", dis_buf); + + uInstr0(cb, CALLM_S, 0); + + uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth); + uInstr1(cb, PUSH, 4, TempReg, desth); + uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl); + uInstr1(cb, PUSH, 4, TempReg, destl); + uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch); + uInstr1(cb, PUSH, 4, TempReg, srch); + uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl); + uInstr1(cb, PUSH, 4, TempReg, srcl); + uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch); + uInstr1(cb, PUSH, 4, TempReg, acch); + uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl); + uInstr1(cb, PUSH, 4, TempReg, accl); + + uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b)); + uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty); + + uInstr1(cb, POP, 4, TempReg, accl); + uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX); + uInstr1(cb, POP, 4, TempReg, acch); + uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX); + uInstr1(cb, POP, 4, TempReg, srcl); + uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX); + uInstr1(cb, POP, 4, TempReg, srch); + uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX); + uInstr1(cb, POP, 4, TempReg, destl); + uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal); + uInstr1(cb, POP, 4, TempReg, desth); + uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah); + + uInstr0(cb, CALLM_E, 0); + + return eip0; +} + + /* Handle conditional move instructions of the form cmovcc E(reg-or-mem), G(reg) @@ -5886,9 +5954,15 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */ + case 0xB0: /* CMPXCHG Gv,Ev */ + eip = dis_cmpxchg_G_E ( cb, sorb, 1, eip ); + break; case 0xB1: /* CMPXCHG Gv,Ev */ eip = dis_cmpxchg_G_E ( cb, sorb, sz, eip ); break; + case 0xC7: /* CMPXCHG8B Gv */ + eip = dis_cmpxchg8b ( cb, sorb, eip ); + break; /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */ diff --git a/include/vg_skin.h.base b/include/vg_skin.h.base index cff8a22df..25a42ee38 100644 --- a/include/vg_skin.h.base +++ b/include/vg_skin.h.base @@ -1183,6 +1183,8 @@ extern Int VGOFF_(helper_LAHF); extern Int VGOFF_(helper_DAS); extern Int VGOFF_(helper_DAA); +extern Int VGOFF_(helper_cmpxchg8b); + /*====================================================================*/ /*=== Generating x86 code from UCode ===*/