Optimize gadget fixups for MOV instructions.
authormortimer <mortimer@openbsd.org>
Sun, 11 Jul 2021 20:32:00 +0000 (20:32 +0000)
committermortimer <mortimer@openbsd.org>
Sun, 11 Jul 2021 20:32:00 +0000 (20:32 +0000)
Instead of swapping registers around, we can just use the REV version of
the same instruction, which has the same effect but encodes differently and
does not result in return bytes in the binary. This reduces the number
of xchg instructions resulting from gadget fixing.

Prompted by ratchov@, with input from millert@ and sthen@.

ok sthen@

gnu/llvm/llvm/lib/Target/X86/X86FixupGadgets.cpp

index ea050ae..6610d42 100644 (file)
@@ -90,6 +90,7 @@ private:
   unsigned getEquivalentRegForReg(unsigned oreg, unsigned nreg) const;
   bool hasImplicitUseOrDef(const MachineInstr &MI, unsigned Reg1,
                            unsigned Reg2) const;
+  bool fixupWithoutExchange(MachineInstr &MI);
 
   bool fixupInstruction(MachineFunction &MF, MachineBasicBlock &MBB,
                         MachineInstr &MI, struct FixupInfo Info);
@@ -563,6 +564,38 @@ bool FixupGadgetsPass::hasImplicitUseOrDef(const MachineInstr &MI,
   return false;
 }
 
+bool FixupGadgetsPass::fixupWithoutExchange(MachineInstr &MI) {
+  switch (MI.getOpcode()) {
+    case X86::MOV8rr_REV:
+      MI.setDesc(TII->get(X86::MOV8rr));
+      break;
+    case X86::MOV16rr_REV:
+      MI.setDesc(TII->get(X86::MOV16rr));
+      break;
+    case X86::MOV32rr_REV:
+      MI.setDesc(TII->get(X86::MOV32rr));
+      break;
+    case X86::MOV64rr_REV:
+      MI.setDesc(TII->get(X86::MOV64rr));
+      break;
+    case X86::MOV8rr:
+      MI.setDesc(TII->get(X86::MOV8rr_REV));
+      break;
+    case X86::MOV16rr:
+      MI.setDesc(TII->get(X86::MOV16rr_REV));
+      break;
+    case X86::MOV32rr:
+      MI.setDesc(TII->get(X86::MOV32rr_REV));
+      break;
+    case X86::MOV64rr:
+      MI.setDesc(TII->get(X86::MOV64rr_REV));
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
 bool FixupGadgetsPass::fixupInstruction(MachineFunction &MF,
                                         MachineBasicBlock &MBB,
                                         MachineInstr &MI, FixupInfo Info) {
@@ -610,6 +643,11 @@ bool FixupGadgetsPass::fixupInstruction(MachineFunction &MF,
     SwapReg2 = treg;
   }
 
+  // Check for specific instructions we can fix without the xchg dance
+  if (fixupWithoutExchange(MI)) {
+      return true;
+  }
+
   // Swap the two registers to start
   BuildMI(MBB, MI, DL, TII->get(XCHG))
       .addReg(SwapReg1, RegState::Define)