Skip to content

Commit

Permalink
amd64: Fix 32b cmpxchg unmodified register writeback (#63)
Browse files Browse the repository at this point in the history
32b register writes are zero-extended. In case a register should not be
modified by cmpxchg, preserve the entire 64b value.  Discovered via QEMU
differential tests.
  • Loading branch information
mborgerson authored Sep 10, 2024
1 parent 54fca3e commit 0b97b66
Showing 1 changed file with 19 additions and 4 deletions.
23 changes: 19 additions & 4 deletions priv/guest_amd64_toIR.c
Original file line number Diff line number Diff line change
Expand Up @@ -8677,10 +8677,25 @@ ULong dis_cmpxchg_G_E ( /*OUT*/Bool* ok,
assign( acc, getIRegRAX(size) );
setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
assign( cond, mk_amd64g_calculate_condition(AMD64CondZ) );
assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
putIRegRAX(size, mkexpr(acc2));
putIRegE(size, pfx, rm, mkexpr(dest2));

if (size == 4) {
/* Preserve upper 32b when register should be unmodified. */
IRTemp acc64 = newTemp(Ity_I64);
IRTemp dest64 = newTemp(Ity_I64);
assign( dest64, IRExpr_ITE(mkexpr(cond),
unop(Iop_32Uto64, mkexpr(src)),
getIRegE(8, pfx, rm)) );
assign( acc64, IRExpr_ITE(mkexpr(cond),
getIRegRAX(8),
unop(Iop_32Uto64, mkexpr(dest))) );
putIRegRAX(8, mkexpr(acc64));
putIRegE(8, pfx, rm, mkexpr(dest64));
} else {
assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
putIRegRAX(size, mkexpr(acc2));
putIRegE(size, pfx, rm, mkexpr(dest2));
}
DIP("cmpxchg%c %s,%s\n", nameISize(size),
nameIRegG(size,pfx,rm),
nameIRegE(size,pfx,rm) );
Expand Down

0 comments on commit 0b97b66

Please sign in to comment.