Mark Wielaard 54ca77
commit 2be719921e700a9ac9b85f470ed87cb8adf8151b
Mark Wielaard 54ca77
Author: Julian Seward <jseward@acm.org>
Mark Wielaard 54ca77
Date:   Sat Nov 13 09:27:01 2021 +0100
Mark Wielaard 54ca77
Mark Wielaard 54ca77
    Bug 445415 - arm64 front end: alignment checks missing for atomic instructions.
Mark Wielaard 54ca77
    
Mark Wielaard 54ca77
    For the arm64 front end, none of the atomic instructions have address
Mark Wielaard 54ca77
    alignment checks included in their IR.  They all should.  The effect of
Mark Wielaard 54ca77
    missing alignment checks in the IR is that, since this IR will in most cases
Mark Wielaard 54ca77
    be translated back to atomic instructions in the back end, we will get
Mark Wielaard 54ca77
    alignment traps (SIGBUS) on the host side and not on the guest side, which is
Mark Wielaard 54ca77
    (very) incorrect behaviour of the simulation.
Mark Wielaard 54ca77
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c
Mark Wielaard 54ca77
index ee018c6a9..16a7e075f 100644
Mark Wielaard 54ca77
--- a/VEX/priv/guest_arm64_toIR.c
Mark Wielaard 54ca77
+++ b/VEX/priv/guest_arm64_toIR.c
Mark Wielaard 54ca77
@@ -4833,6 +4833,34 @@ static IRTemp gen_zwidening_load ( UInt szB, IRTemp addr )
Mark Wielaard 54ca77
 }
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
+/* Generate a SIGBUS followed by a restart of the current instruction if
Mark Wielaard 54ca77
+   `effective_addr` is `align`-aligned.  This is required behaviour for atomic
Mark Wielaard 54ca77
+   instructions.  This assumes that guest_RIP_curr_instr is set correctly!
Mark Wielaard 54ca77
+
Mark Wielaard 54ca77
+   This is hardwired to generate SIGBUS because so far the only supported arm64
Mark Wielaard 54ca77
+   (arm64-linux) does that.  Should we need to later extend it to generate some
Mark Wielaard 54ca77
+   other signal, use the same scheme as with gen_SIGNAL_if_not_XX_aligned in
Mark Wielaard 54ca77
+   guest_amd64_toIR.c. */
Mark Wielaard 54ca77
+static
Mark Wielaard 54ca77
+void gen_SIGBUS_if_not_XX_aligned ( IRTemp effective_addr, ULong align )
Mark Wielaard 54ca77
+{
Mark Wielaard 54ca77
+   if (align == 1) {
Mark Wielaard 54ca77
+      return;
Mark Wielaard 54ca77
+   }
Mark Wielaard 54ca77
+   vassert(align == 16 || align == 8 || align == 4 || align == 2);
Mark Wielaard 54ca77
+   stmt(
Mark Wielaard 54ca77
+      IRStmt_Exit(
Mark Wielaard 54ca77
+         binop(Iop_CmpNE64,
Mark Wielaard 54ca77
+               binop(Iop_And64,mkexpr(effective_addr),mkU64(align-1)),
Mark Wielaard 54ca77
+               mkU64(0)),
Mark Wielaard 54ca77
+         Ijk_SigBUS,
Mark Wielaard 54ca77
+         IRConst_U64(guest_PC_curr_instr),
Mark Wielaard 54ca77
+         OFFB_PC
Mark Wielaard 54ca77
+      )
Mark Wielaard 54ca77
+   );
Mark Wielaard 54ca77
+}
Mark Wielaard 54ca77
+
Mark Wielaard 54ca77
+
Mark Wielaard 54ca77
 /* Generate a "standard 7" name, from bitQ and size.  But also
Mark Wielaard 54ca77
    allow ".1d" since that's occasionally useful. */
Mark Wielaard 54ca77
 static
Mark Wielaard 54ca77
@@ -6670,7 +6698,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       IRTemp ea = newTemp(Ity_I64);
Mark Wielaard 54ca77
       assign(ea, getIReg64orSP(nn));
Mark Wielaard 54ca77
-      /* FIXME generate check that ea is szB-aligned */
Mark Wielaard 54ca77
+      gen_SIGBUS_if_not_XX_aligned(ea, szB);
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       if (isLD && ss == BITS5(1,1,1,1,1)) {
Mark Wielaard 54ca77
          IRTemp res = newTemp(ty);
Mark Wielaard 54ca77
@@ -6803,7 +6831,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       IRTemp ea = newTemp(Ity_I64);
Mark Wielaard 54ca77
       assign(ea, getIReg64orSP(nn));
Mark Wielaard 54ca77
-      /* FIXME generate check that ea is 2*elemSzB-aligned */
Mark Wielaard 54ca77
+      gen_SIGBUS_if_not_XX_aligned(ea, fullSzB);
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       if (isLD && ss == BITS5(1,1,1,1,1)) {
Mark Wielaard 54ca77
          if (abiinfo->guest__use_fallback_LLSC) {
Mark Wielaard 54ca77
@@ -7044,7 +7072,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       IRTemp ea = newTemp(Ity_I64);
Mark Wielaard 54ca77
       assign(ea, getIReg64orSP(nn));
Mark Wielaard 54ca77
-      /* FIXME generate check that ea is szB-aligned */
Mark Wielaard 54ca77
+      gen_SIGBUS_if_not_XX_aligned(ea, szB);
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       if (isLD) {
Mark Wielaard 54ca77
          IRTemp res = newTemp(ty);
Mark Wielaard 54ca77
@@ -7159,6 +7187,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       IRTemp ea = newTemp(Ity_I64);
Mark Wielaard 54ca77
       assign(ea, getIReg64orSP(nn));
Mark Wielaard 54ca77
+      gen_SIGBUS_if_not_XX_aligned(ea, szB);
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
       // Insert barrier before loading for acquire and acquire-release variants:
Mark Wielaard 54ca77
       // A and AL.
Mark Wielaard 54ca77
@@ -7266,6 +7295,10 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
       IRType ty = integerIRTypeOfSize(szB);
Mark Wielaard 54ca77
       Bool is64 = szB == 8;
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
+      IRTemp ea = newTemp(Ity_I64);
Mark Wielaard 54ca77
+      assign(ea, getIReg64orSP(nn));
Mark Wielaard 54ca77
+      gen_SIGBUS_if_not_XX_aligned(ea, szB);
Mark Wielaard 54ca77
+
Mark Wielaard 54ca77
       IRExpr *exp = narrowFrom64(ty, getIReg64orZR(ss));
Mark Wielaard 54ca77
       IRExpr *new = narrowFrom64(ty, getIReg64orZR(tt));
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
@@ -7275,7 +7308,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
       // Store the result back if LHS remains unchanged in memory.
Mark Wielaard 54ca77
       IRTemp old = newTemp(ty);
Mark Wielaard 54ca77
       stmt( IRStmt_CAS(mkIRCAS(/*oldHi*/IRTemp_INVALID, old,
Mark Wielaard 54ca77
-                               Iend_LE, getIReg64orSP(nn),
Mark Wielaard 54ca77
+                               Iend_LE, mkexpr(ea),
Mark Wielaard 54ca77
                                /*expdHi*/NULL, exp,
Mark Wielaard 54ca77
                                /*dataHi*/NULL, new)) );
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
@@ -7307,6 +7340,10 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
       if ((ss & 0x1) || (tt & 0x1)) {
Mark Wielaard 54ca77
          /* undefined; fall through */
Mark Wielaard 54ca77
       } else {
Mark Wielaard 54ca77
+         IRTemp ea = newTemp(Ity_I64);
Mark Wielaard 54ca77
+         assign(ea, getIReg64orSP(nn));
Mark Wielaard 54ca77
+         gen_SIGBUS_if_not_XX_aligned(ea, is64 ? 16 : 8);
Mark Wielaard 54ca77
+
Mark Wielaard 54ca77
          IRExpr *expLo = getIRegOrZR(is64, ss);
Mark Wielaard 54ca77
          IRExpr *expHi = getIRegOrZR(is64, ss + 1);
Mark Wielaard 54ca77
          IRExpr *newLo = getIRegOrZR(is64, tt);
Mark Wielaard 54ca77
@@ -7318,7 +7355,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
Mark Wielaard 54ca77
             stmt(IRStmt_MBE(Imbe_Fence));
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
          stmt( IRStmt_CAS(mkIRCAS(oldHi, oldLo,
Mark Wielaard 54ca77
-                                  Iend_LE, getIReg64orSP(nn),
Mark Wielaard 54ca77
+                                  Iend_LE, mkexpr(ea),
Mark Wielaard 54ca77
                                   expHi, expLo,
Mark Wielaard 54ca77
                                   newHi, newLo)) );
Mark Wielaard 54ca77
 
Mark Wielaard 54ca77
diff --git a/VEX/priv/host_arm64_defs.c b/VEX/priv/host_arm64_defs.c
Mark Wielaard 54ca77
index b65e27db4..39c6aaa46 100644
Mark Wielaard 54ca77
--- a/VEX/priv/host_arm64_defs.c
Mark Wielaard 54ca77
+++ b/VEX/priv/host_arm64_defs.c
Mark Wielaard 54ca77
@@ -4033,6 +4033,7 @@ Int emit_ARM64Instr ( /*MB_MOD*/Bool* is_profInc,
Mark Wielaard 54ca77
             case Ijk_FlushDCache: trcval = VEX_TRC_JMP_FLUSHDCACHE; break;
Mark Wielaard 54ca77
             case Ijk_NoRedir:     trcval = VEX_TRC_JMP_NOREDIR;     break;
Mark Wielaard 54ca77
             case Ijk_SigTRAP:     trcval = VEX_TRC_JMP_SIGTRAP;     break;
Mark Wielaard 54ca77
+            case Ijk_SigBUS:      trcval = VEX_TRC_JMP_SIGBUS;      break;
Mark Wielaard 54ca77
             //case Ijk_SigSEGV:     trcval = VEX_TRC_JMP_SIGSEGV;     break;
Mark Wielaard 54ca77
             case Ijk_Boring:      trcval = VEX_TRC_JMP_BORING;      break;
Mark Wielaard 54ca77
             /* We don't expect to see the following being assisted. */
Mark Wielaard 54ca77
diff --git a/VEX/priv/host_arm64_isel.c b/VEX/priv/host_arm64_isel.c
Mark Wielaard 54ca77
index 094e7e74b..82cb2d78c 100644
Mark Wielaard 54ca77
--- a/VEX/priv/host_arm64_isel.c
Mark Wielaard 54ca77
+++ b/VEX/priv/host_arm64_isel.c
Mark Wielaard 54ca77
@@ -4483,6 +4483,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
Mark Wielaard 54ca77
          case Ijk_InvalICache:
Mark Wielaard 54ca77
          case Ijk_FlushDCache:
Mark Wielaard 54ca77
          case Ijk_SigTRAP:
Mark Wielaard 54ca77
+         case Ijk_SigBUS:
Mark Wielaard 54ca77
          case Ijk_Yield: {
Mark Wielaard 54ca77
             HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
Mark Wielaard 54ca77
             addInstr(env, ARM64Instr_XAssisted(r, amPC, cc,
Mark Wielaard 54ca77
@@ -4576,8 +4577,8 @@ static void iselNext ( ISelEnv* env,
Mark Wielaard 54ca77
       case Ijk_InvalICache:
Mark Wielaard 54ca77
       case Ijk_FlushDCache:
Mark Wielaard 54ca77
       case Ijk_SigTRAP:
Mark Wielaard 54ca77
-      case Ijk_Yield:
Mark Wielaard 54ca77
-      {
Mark Wielaard 54ca77
+      case Ijk_SigBUS:
Mark Wielaard 54ca77
+      case Ijk_Yield: {
Mark Wielaard 54ca77
          HReg        r    = iselIntExpr_R(env, next);
Mark Wielaard 54ca77
          ARM64AMode* amPC = mk_baseblock_64bit_access_amode(offsIP);
Mark Wielaard 54ca77
          addInstr(env, ARM64Instr_XAssisted(r, amPC, ARM64cc_AL, jk));