Bug 1495574 - Support copying ip-relative xchg instructions, r=froydnj.
authorBrian Hackett <bhackett1024@gmail.com>
Sun, 14 Oct 2018 09:48:34 -0600
changeset 500199 a64b17b18dae852bae1de933d840b823f8f1b643
parent 500168 02d89c011037d8407576ec58e307f632a8f64b0f
child 500200 24c9f26fc9924fb895e9884ebb19738210440247
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1495574
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1495574 - Support copying ip-relative xchg instructions, r=froydnj.
toolkit/recordreplay/Assembler.cpp
toolkit/recordreplay/Assembler.h
toolkit/recordreplay/ProcessRedirect.cpp
--- a/toolkit/recordreplay/Assembler.cpp
+++ b/toolkit/recordreplay/Assembler.cpp
@@ -242,45 +242,51 @@ Assembler::MoveImmediateToRax(void* aVal
   Advance(MoveImmediateBytes);
 }
 
 void
 Assembler::MoveRaxToRegister(/*ud_type*/ int aRegister)
 {
   MOZ_RELEASE_ASSERT(aRegister == NormalizeRegister(aRegister));
 
-  uint8_t* ip = Current();
   if (aRegister <= UD_R_RDI) {
-    ip[0] = 0x48;
-    ip[1] = 0x89;
-    ip[2] = 0xC0 + aRegister - UD_R_RAX;
+    NewInstruction(0x48, 0x89, 0xC0 + aRegister - UD_R_RAX);
   } else {
-    ip[0] = 0x49;
-    ip[1] = 0x89;
-    ip[2] = 0xC0 + aRegister - UD_R_R8;
+    NewInstruction(0x49, 0x89, 0xC0 + aRegister - UD_R_R8);
   }
-  Advance(3);
 }
 
 void
 Assembler::MoveRegisterToRax(/*ud_type*/ int aRegister)
 {
   MOZ_RELEASE_ASSERT(aRegister == NormalizeRegister(aRegister));
 
-  uint8_t* ip = Current();
   if (aRegister <= UD_R_RDI) {
-    ip[0] = 0x48;
-    ip[1] = 0x89;
-    ip[2] = 0xC0 + (aRegister - UD_R_RAX) * 8;
+    NewInstruction(0x48, 0x89, 0xC0 + (aRegister - UD_R_RAX) * 8);
   } else {
-    ip[0] = 0x4C;
-    ip[1] = 0x89;
-    ip[2] = 0xC0 + (aRegister - UD_R_R8) * 8;
+    NewInstruction(0x4C, 0x89, 0xC0 + (aRegister - UD_R_R8) * 8);
   }
-  Advance(3);
+}
+
+void
+Assembler::ExchangeByteRegisterWithAddressAtRbx(/*ud_type*/ int aRegister)
+{
+  MOZ_RELEASE_ASSERT(aRegister == NormalizeRegister(aRegister));
+
+  if (aRegister <= UD_R_RDI) {
+    NewInstruction(0x86, 0x03 + (aRegister - UD_R_RAX) * 8);
+  } else {
+    NewInstruction(0x44, 0x86, 0x03 + (aRegister - UD_R_R8) * 8);
+  }
+}
+
+void
+Assembler::ExchangeByteRbxWithAddressAtRax()
+{
+  NewInstruction(0x86, 0x18);
 }
 
 /* static */ /*ud_type*/ int
 Assembler::NormalizeRegister(/*ud_type*/ int aRegister)
 {
   if (aRegister >= UD_R_AL && aRegister <= UD_R_R15B) {
     return aRegister - UD_R_AL + UD_R_RAX;
   }
--- a/toolkit/recordreplay/Assembler.h
+++ b/toolkit/recordreplay/Assembler.h
@@ -83,16 +83,22 @@ public:
   void MoveImmediateToRax(void* aValue);
 
   // movq %rax, register
   void MoveRaxToRegister(/*ud_type*/ int aRegister);
 
   // movq register, %rax
   void MoveRegisterToRax(/*ud_type*/ int aRegister);
 
+  // xchgb register, 0(%rbx)
+  void ExchangeByteRegisterWithAddressAtRbx(/*ud_type*/ int aRegister);
+
+  // xchgb $bl, 0(%rax)
+  void ExchangeByteRbxWithAddressAtRax();
+
   // Normalize a Udis86 register to its 8 byte version, returning UD_NONE/zero
   // for unexpected registers.
   static /*ud_type*/ int NormalizeRegister(/*ud_type*/ int aRegister);
 
 ///////////////////////////////////////////////////////////////////////////////
 // Routines for assembling instructions at arbitrary locations
 ///////////////////////////////////////////////////////////////////////////////
 
--- a/toolkit/recordreplay/ProcessRedirect.cpp
+++ b/toolkit/recordreplay/ProcessRedirect.cpp
@@ -531,16 +531,45 @@ CopySpecialInstruction(uint8_t* aIp, ud_
       aAssembler.LoadRax(8);
       aAssembler.CompareRaxWithTopOfStack();
       aAssembler.PopRax();
       aAssembler.PopRax();
       return true;
     }
   }
 
+  if (mnemonic == UD_Ixchg) {
+    const ud_operand* dst = ud_insn_opr(aUd, 0);
+    const ud_operand* src = ud_insn_opr(aUd, 1);
+    if (src->type == UD_OP_REG && src->size == 8 &&
+        dst->type == UD_OP_MEM && dst->base == UD_R_RIP && !dst->index && dst->offset == 32) {
+      // xchgb reg, $offset32(%rip)
+      int reg = Assembler::NormalizeRegister(src->base);
+      if (!reg) {
+        return false;
+      }
+      uint8_t* addr = aIp + aNbytes + dst->lval.sdword;
+      if (reg == UD_R_RBX) {
+        aAssembler.PushRax();
+        aAssembler.MoveImmediateToRax(addr);
+        aAssembler.ExchangeByteRbxWithAddressAtRax();
+        aAssembler.PopRax();
+      } else {
+        aAssembler.PushRbx();
+        aAssembler.PushRax();
+        aAssembler.MoveImmediateToRax(addr);
+        aAssembler.MoveRaxToRegister(UD_R_RBX);
+        aAssembler.PopRax();
+        aAssembler.ExchangeByteRegisterWithAddressAtRbx(reg);
+        aAssembler.PopRbx();
+      }
+      return true;
+    }
+  }
+
   return false;
 }
 
 // Copy an instruction to aAssembler, returning the number of bytes used by the
 // instruction.
 static size_t
 CopyInstruction(const char* aName, uint8_t* aIp, Assembler& aAssembler)
 {