Merge in a diff from base:

Improve the X86FixupGadgets pass

Merge in a bug fix from upstream:

[MC] Make symbol version errors non-fatal



Index: Makefile
===================================================================
RCS file: /home/cvs/ports/devel/llvm/Makefile,v
retrieving revision 1.213
diff -u -p -u -p -r1.213 Makefile
--- Makefile    20 Feb 2019 00:24:11 -0000      1.213
+++ Makefile    22 Feb 2019 14:33:44 -0000
@@ -20,7 +20,7 @@ PKGSPEC-main =        llvm-=${LLVM_V}
 PKGNAME-main = llvm-${LLVM_V}
 PKGNAME-python =       py-llvm-${LLVM_V}
 PKGNAME-lldb = lldb-${LLVM_V}
-REVISION-main =        6
+REVISION-main =        7
 REVISION-lldb =        0
 CATEGORIES =   devel
 DISTFILES =    llvm-${LLVM_V}.src${EXTRACT_SUFX} \
Index: patches/patch-lib_MC_ELFObjectWriter_cpp
===================================================================
RCS file: patches/patch-lib_MC_ELFObjectWriter_cpp
diff -N patches/patch-lib_MC_ELFObjectWriter_cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_MC_ELFObjectWriter_cpp    22 Feb 2019 14:36:33 -0000
@@ -0,0 +1,34 @@
+$OpenBSD$
+
+[MC] Make symbol version errors non-fatal
+
+Index: lib/MC/ELFObjectWriter.cpp
+--- lib/MC/ELFObjectWriter.cpp.orig
++++ lib/MC/ELFObjectWriter.cpp
+@@ -1258,14 +1258,20 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssem
+     if (!Symbol.isUndefined() && !Rest.startswith("@@@"))
+       continue;
+ 
+-    // FIXME: produce a better error message.
++    // FIXME: Get source locations for these errors or diagnose them earlier.
+     if (Symbol.isUndefined() && Rest.startswith("@@") &&
+-        !Rest.startswith("@@@"))
+-      report_fatal_error("A @@ version cannot be undefined");
++        !Rest.startswith("@@@")) {
++      Asm.getContext().reportError(SMLoc(), "versioned symbol " + AliasName +
++                                                " must be defined");
++      continue;
++    }
+ 
+-    if (Renames.count(&Symbol) && Renames[&Symbol] != Alias)
+-      report_fatal_error(llvm::Twine("Multiple symbol versions defined for ") 
+
+-                         Symbol.getName());
++    if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) {
++      Asm.getContext().reportError(
++          SMLoc(), llvm::Twine("multiple symbol versions defined for ") +
++                       Symbol.getName());
++      continue;
++    }
+ 
+     Renames.insert(std::make_pair(&Symbol, Alias));
+   }
Index: patches/patch-lib_Target_X86_X86FixupGadgets_cpp
===================================================================
RCS file: 
/home/cvs/ports/devel/llvm/patches/patch-lib_Target_X86_X86FixupGadgets_cpp,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 patch-lib_Target_X86_X86FixupGadgets_cpp
--- patches/patch-lib_Target_X86_X86FixupGadgets_cpp    28 Jan 2019 06:27:28 
-0000      1.2
+++ patches/patch-lib_Target_X86_X86FixupGadgets_cpp    22 Feb 2019 19:20:40 
-0000
@@ -1,15 +1,16 @@
 $OpenBSD: patch-lib_Target_X86_X86FixupGadgets_cpp,v 1.2 2019/01/28 06:27:28 
jca Exp $
 
-Add a clang pass that identifies potential ROP gadgets and replaces ROP
-friendly instructions with safe alternatives. This initial commit fixes
-3 instruction forms that will lower to include a c3 (return) byte.
-Additional problematic instructions can be fixed incrementally using
-this framework.
+- Add a clang pass that identifies potential ROP gadgets and replaces ROP
+  friendly instructions with safe alternatives. This initial commit fixes
+  3 instruction forms that will lower to include a c3 (return) byte.
+  Additional problematic instructions can be fixed incrementally using
+  this framework.
+- Improve the X86FixupGadgets pass
 
 Index: lib/Target/X86/X86FixupGadgets.cpp
 --- lib/Target/X86/X86FixupGadgets.cpp.orig
 +++ lib/Target/X86/X86FixupGadgets.cpp
-@@ -0,0 +1,273 @@
+@@ -0,0 +1,720 @@
 +//===-- X86FixupGadgets.cpp - Fixup Instructions that make ROP Gadgets 
----===//
 +//
 +//                     The LLVM Compiler Infrastructure
@@ -47,10 +48,10 @@ Index: lib/Target/X86/X86FixupGadgets.cp
 +
 +#define DEBUG_TYPE FIXUPGADGETS_NAME
 +
-+// Toggle with cc1 option: -backend-option -x86-fixup-gadgets=<true|false>
++// Toggle with cc1 option: -mllvm -x86-fixup-gadgets=<true|false>
 +static cl::opt<bool> FixupGadgets(
-+    "x86-fixup-gadgets",
-+    cl::desc("Replace ROP friendly instructions with alternatives"),
++    "x86-fixup-gadgets", cl::Hidden,
++    cl::desc("Replace ROP friendly instructions with safe alternatives"),
 +    cl::init(true));
 +
 +namespace {
@@ -78,24 +79,33 @@ Index: lib/Target/X86/X86FixupGadgets.cp
 +  const X86InstrInfo *TII;
 +  const X86RegisterInfo *TRI;
 +  bool Is64Bit;
-+  enum InstrType {
-+    NoType = 0,
-+    OneGPRegC3,
-+    TwoGPRegC3,
-+    ThreeGPRegC3,
-+  };
 +
-+  /// If an Instr has a ROP friendly construct, return it
-+  InstrType isROPFriendly(MachineInstr &MI) const;
++  struct FixupInfo {
++    unsigned op1;
++    unsigned op2;
++    bool fixup;
++    bool align;
++  };
 +
-+  /// Helper functions for various kinds of instructions
-+  bool isOneGPRegC3(MachineInstr &MI) const;
-+  bool isTwoGPRegC3(MachineInstr &MI) const;
-+  bool isThreeGPRegC3(MachineInstr &MI) const;
++  uint8_t getRegNum(const MachineOperand &MO) const;
++  uint8_t getRegNum(unsigned reg) const;
++  struct FixupInfo isROPFriendly(MachineInstr &MI) const;
++  bool isROPFriendlyImm(const MachineOperand &MO) const;
++  bool isROPFriendlyRegPair(const MachineOperand &Dst,
++                            const MachineOperand &Src) const;
++  bool isROPFriendlyReg(const MachineOperand &Dst, uint8_t RegOpcode) const;
++  bool badModRM(uint8_t Mod, uint8_t RegOpcode, uint8_t RM) const;
++  void checkSIB(const MachineInstr &MI, unsigned CurOp,
++                struct FixupInfo &info) const;
++  bool needsFixup(struct FixupInfo &fi) const;
++  bool needsAlign(struct FixupInfo &fi) const;
++  unsigned getWidestRegForReg(unsigned reg) const;
++  unsigned getEquivalentRegForReg(unsigned oreg, unsigned nreg) const;
++  bool hasImplicitUseOrDef(const MachineInstr &MI, unsigned Reg1,
++                           unsigned Reg2) const;
 +
-+  /// Replace ROP friendly instructions with safe alternatives
 +  bool fixupInstruction(MachineFunction &MF, MachineBasicBlock &MBB,
-+                        MachineInstr &MI, InstrType type);
++                        MachineInstr &MI, struct FixupInfo Info);
 +};
 +char FixupGadgetsPass::ID = 0;
 +} // namespace
@@ -104,155 +114,593 @@ Index: lib/Target/X86/X86FixupGadgets.cp
 +  return new FixupGadgetsPass();
 +}
 +
-+bool FixupGadgetsPass::isOneGPRegC3(MachineInstr &MI) const {
-+  MachineOperand &MO = MI.getOperand(0);
-+  return MO.isReg() && MO.getReg() == X86::EBX &&
-+         (MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg;
++uint8_t FixupGadgetsPass::getRegNum(const MachineOperand &MO) const {
++  return TRI->getEncodingValue(MO.getReg()) & 0x7;
 +}
 +
-+bool FixupGadgetsPass::isTwoGPRegC3(MachineInstr &MI) const {
-+  bool DestSet = false;
-+  bool SrcSet = false;
-+  bool OpcodeSet = false;
-+  MachineOperand &MO0 = MI.getOperand(0);
-+  MachineOperand &MO1 = MI.getOperand(1);
-+  if (!(MO0.isReg() && MO1.isReg()))
-+    return false;
++uint8_t FixupGadgetsPass::getRegNum(unsigned reg) const {
++  return TRI->getEncodingValue(reg) & 0x7;
++}
++
++bool FixupGadgetsPass::isROPFriendlyImm(const MachineOperand &MO) const {
++  int64_t imm = MO.getImm();
++  for (int i = 0; i < 8; ++i) {
++    uint8_t byte = (imm & 0xff);
++    if (byte == 0xc2 || byte == 0xc3 || byte == 0xca || byte == 0xcb) {
++      return true;
++    }
++    imm = imm >> 8;
++  }
++  return false;
++}
 +
-+  unsigned dstReg = MO0.getReg();
-+  if (dstReg == X86::RBX || dstReg == X86::EBX || dstReg == X86::BX ||
-+      dstReg == X86::BL)
-+    DestSet = true;
++bool FixupGadgetsPass::isROPFriendlyRegPair(const MachineOperand &Dst,
++                                            const MachineOperand &Src) const {
 +
-+  if (!DestSet)
-+    return false;
++  if (!Dst.isReg() || !Src.isReg())
++    llvm_unreachable("Testing non registers for bad reg pair!");
 +
-+  unsigned srcReg = MO1.getReg();
-+  if (srcReg == X86::RAX || srcReg == X86::EAX || srcReg == X86::AX ||
-+      srcReg == X86::AL)
-+    SrcSet = true;
++  uint8_t Mod = 3;
++  uint8_t RegOpcode = getRegNum(Src);
++  uint8_t RM = getRegNum(Dst);
++  return badModRM(Mod, RegOpcode, RM);
++}
 +
-+  if (!SrcSet)
-+    return false;
++bool FixupGadgetsPass::isROPFriendlyReg(const MachineOperand &Dst, uint8_t 
RegOpcode) const {
 +
-+  if ((MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg)
-+    OpcodeSet = true;
++  if (!Dst.isReg())
++    llvm_unreachable("Testing non register for bad reg!");
 +
-+  return DestSet && SrcSet && OpcodeSet;
++  uint8_t Mod = 3;
++  uint8_t RM = getRegNum(Dst);
++  return badModRM(Mod, RegOpcode, RM);
 +}
 +
-+bool FixupGadgetsPass::isThreeGPRegC3(MachineInstr &MI) const {
-+  bool DestSet = false;
-+  bool SrcSet = false;
-+  bool OpcodeSet = false;
-+
-+  MachineOperand &MO0 = MI.getOperand(0);
-+  MachineOperand &MO1 = MI.getOperand(1);
-+  MachineOperand &MO2 = MI.getOperand(2);
-+  if (!(MO0.isReg() && MO1.isReg() && MO2.isReg() &&
-+        MO0.getReg() == MO1.getReg()))
-+    return false;
++bool FixupGadgetsPass::badModRM(uint8_t Mod, uint8_t RegOpcode,
++                                uint8_t RM) const {
++  uint8_t ModRM = ((Mod << 6) | (RegOpcode << 3) | RM);
++  if (ModRM == 0xc2 || ModRM == 0xc3 || ModRM == 0xca || ModRM == 0xcb)
++    return true;
++  return false;
++}
 +
-+  unsigned dstReg = MO0.getReg();
-+  if (dstReg == X86::RBX || dstReg == X86::EBX || dstReg == X86::BX ||
-+      dstReg == X86::BL)
-+    DestSet = true;
++void FixupGadgetsPass::checkSIB(const MachineInstr &MI, unsigned CurOp,
++                                struct FixupInfo &info) const {
 +
-+  if (!DestSet)
-+    return false;
++  const MachineOperand &Base = MI.getOperand(CurOp + X86::AddrBaseReg);
++  const MachineOperand &Scale = MI.getOperand(CurOp + X86::AddrScaleAmt);
++  const MachineOperand &Index = MI.getOperand(CurOp + X86::AddrIndexReg);
++
++  if (!Scale.isImm() || !Base.isReg() || !Index.isReg())
++    llvm_unreachable("Wrong type operands");
++
++  if (Scale.getImm() != 8 || Base.getReg() == 0 || Index.getReg() == 0)
++    return;
++
++  if (badModRM(3, getRegNum(Index), getRegNum(Base))) {
++    info.op1 = CurOp + X86::AddrBaseReg;
++    info.op2 = CurOp + X86::AddrIndexReg;
++    info.fixup = true;
++  }
++}
 +
-+  unsigned srcReg = MO2.getReg();
-+  if (srcReg == X86::RAX || srcReg == X86::EAX || srcReg == X86::AX ||
-+      srcReg == X86::AL)
-+    SrcSet = true;
++struct FixupGadgetsPass::FixupInfo
++FixupGadgetsPass::isROPFriendly(MachineInstr &MI) const {
 +
-+  if (!SrcSet)
-+    return false;
++  const MCInstrDesc &Desc = MI.getDesc();
++  unsigned CurOp = X86II::getOperandBias(Desc);
++  uint64_t TSFlags = Desc.TSFlags;
++  uint64_t Form = TSFlags & X86II::FormMask;
++  bool HasVEX_4V = TSFlags & X86II::VEX_4V;
++  bool HasEVEX_K = TSFlags & X86II::EVEX_K;
++
++  struct FixupInfo info = {0, 0, false, false};
++
++  // Look for constants with c3 in them
++  for (const auto &MO : MI.operands()) {
++    if (MO.isImm() && isROPFriendlyImm(MO)) {
++      info.align = true;
++      break;
++    }
++  }
 +
-+  if ((MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg)
-+    OpcodeSet = true;
++  switch (Form) {
++  case X86II::Pseudo: {
++    // Pesudos that are replaced with real instructions later
++    switch (MI.getOpcode()) {
++    case X86::ADD64rr_DB:
++    case X86::ADD32rr_DB:
++    case X86::ADD16rr_DB:
++      goto Handle_MRMDestReg;
++    case X86::ACQUIRE_MOV8rm:
++    case X86::ACQUIRE_MOV16rm:
++    case X86::ACQUIRE_MOV32rm:
++    case X86::ACQUIRE_MOV64rm:
++      goto Handle_MRMSrcMem;
++    case X86::RELEASE_MOV8mr:
++    case X86::RELEASE_MOV16mr:
++    case X86::RELEASE_MOV32mr:
++    case X86::RELEASE_MOV64mr:
++    case X86::RELEASE_ADD8mr:
++    case X86::RELEASE_ADD32mr:
++    case X86::RELEASE_ADD64mr:
++    case X86::RELEASE_AND8mr:
++    case X86::RELEASE_AND32mr:
++    case X86::RELEASE_AND64mr:
++    case X86::RELEASE_OR8mr:
++    case X86::RELEASE_OR32mr:
++    case X86::RELEASE_OR64mr:
++    case X86::RELEASE_XOR8mr:
++    case X86::RELEASE_XOR32mr:
++    case X86::RELEASE_XOR64mr:
++      goto Handle_MRMDestMem;
++    case X86::RELEASE_MOV8mi:
++    case X86::RELEASE_MOV16mi:
++    case X86::RELEASE_MOV32mi:
++    case X86::RELEASE_ADD8mi:
++    case X86::RELEASE_MOV64mi32:
++    case X86::RELEASE_ADD32mi:
++    case X86::RELEASE_ADD64mi32:
++    case X86::RELEASE_AND8mi:
++    case X86::RELEASE_AND32mi:
++    case X86::RELEASE_AND64mi32:
++    case X86::RELEASE_OR8mi:
++    case X86::RELEASE_OR32mi:
++    case X86::RELEASE_OR64mi32:
++    case X86::RELEASE_XOR8mi:
++    case X86::RELEASE_XOR32mi:
++    case X86::RELEASE_XOR64mi32:
++    case X86::RELEASE_INC8m:
++    case X86::RELEASE_INC16m:
++    case X86::RELEASE_INC32m:
++    case X86::RELEASE_INC64m:
++    case X86::RELEASE_DEC8m:
++    case X86::RELEASE_DEC16m:
++    case X86::RELEASE_DEC32m:
++    case X86::RELEASE_DEC64m:
++      goto Handle_MRMXm;
++    case X86::ADD16ri_DB:
++    case X86::ADD32ri_DB:
++    case X86::ADD64ri32_DB:
++    case X86::ADD16ri8_DB:
++    case X86::ADD32ri8_DB:
++    case X86::ADD64ri8_DB:
++      goto Handle_MRMXr;
++    default:
++      break;
++    }
++    break;
++  }
++  case X86II::AddRegFrm: {
++    uint8_t BaseOpcode = X86II::getBaseOpcodeFor(TSFlags);
++    uint8_t Opcode = BaseOpcode + getRegNum(MI.getOperand(CurOp));
++    if (Opcode == 0xc2 || Opcode == 0xc3 || Opcode == 0xca || Opcode == 0xcb) 
{
++      info.op1 = CurOp;
++      info.fixup = true;
++    }
++    break;
++  }
++  case X86II::MRMDestMem: {
++  Handle_MRMDestMem:
++    checkSIB(MI, CurOp, info);
++    unsigned opcode = MI.getOpcode();
++    if (opcode == X86::MOVNTImr || opcode == X86::MOVNTI_64mr)
++      info.align = true;
++    break;
++  }
++  case X86II::MRMSrcMem: {
++  Handle_MRMSrcMem:
++    CurOp += 1;
++    if (HasVEX_4V)
++      CurOp += 1;
++    if (HasEVEX_K)
++      CurOp += 1;
++    checkSIB(MI, CurOp, info);
++    break;
++  }
++  case X86II::MRMSrcMem4VOp3: {
++    CurOp += 1;
++    checkSIB(MI, CurOp, info);
++    break;
++  }
++  case X86II::MRMSrcMemOp4: {
++    CurOp += 3;
++    checkSIB(MI, CurOp, info);
++    break;
++  }
++  case X86II::MRMXm:
++  case X86II::MRM0m:
++  case X86II::MRM1m:
++  case X86II::MRM2m:
++  case X86II::MRM3m:
++  case X86II::MRM4m:
++  case X86II::MRM5m:
++  case X86II::MRM6m:
++  case X86II::MRM7m: {
++  Handle_MRMXm:
++    if (HasVEX_4V)
++      CurOp += 1;
++    if (HasEVEX_K)
++      CurOp += 1;
++    checkSIB(MI, CurOp, info);
++    break;
++  }
++  case X86II::MRMDestReg: {
++  Handle_MRMDestReg:
++    const MachineOperand &DstReg = MI.getOperand(CurOp);
++    info.op1 = CurOp;
++    CurOp += 1;
++    if (HasVEX_4V)
++      CurOp += 1;
++    if (HasEVEX_K)
++      CurOp += 1;
++    const MachineOperand &SrcReg = MI.getOperand(CurOp);
++    info.op2 = CurOp;
++    if (isROPFriendlyRegPair(DstReg, SrcReg))
++      info.fixup = true;
++    break;
++  }
++  case X86II::MRMSrcReg: {
++    const MachineOperand &DstReg = MI.getOperand(CurOp);
++    info.op1 = CurOp;
++    CurOp += 1;
++    if (HasVEX_4V)
++      CurOp += 1;
++    if (HasEVEX_K)
++      CurOp += 1;
++    const MachineOperand &SrcReg = MI.getOperand(CurOp);
++    info.op2 = CurOp;
++    if (isROPFriendlyRegPair(SrcReg, DstReg))
++      info.fixup = true;
++    break;
++  }
++  case X86II::MRMSrcReg4VOp3: {
++    const MachineOperand &DstReg = MI.getOperand(CurOp);
++    info.op1 = CurOp;
++    CurOp += 1;
++    const MachineOperand &SrcReg = MI.getOperand(CurOp);
++    info.op2 = CurOp;
++    if (isROPFriendlyRegPair(SrcReg, DstReg))
++      info.fixup = true;
++    break;
++  }
++  case X86II::MRMSrcRegOp4: {
++    const MachineOperand &DstReg = MI.getOperand(CurOp);
++    info.op1 = CurOp;
++    CurOp += 3;
++    const MachineOperand &SrcReg = MI.getOperand(CurOp);
++    info.op2 = CurOp;
++    if (isROPFriendlyRegPair(SrcReg, DstReg))
++      info.fixup = true;
++    break;
++  }
++  case X86II::MRMXr:
++  case X86II::MRM0r:
++  case X86II::MRM1r: {
++Handle_MRMXr:
++    if (HasVEX_4V)
++      CurOp += 1;
++    if (HasEVEX_K)
++      CurOp += 1;
++    const MachineOperand &DstReg = MI.getOperand(CurOp);
++    info.op1 = CurOp;
++    if (isROPFriendlyReg(DstReg, Form == X86II::MRM1r ? 1 : 0))
++      info.fixup = true;
++    break;
++  }
++  case X86II::MRM_C2:
++  case X86II::MRM_C3:
++  case X86II::MRM_CA:
++  case X86II::MRM_CB: {
++    info.align = true;
++    break;
++  }
++  default:
++    break;
++  }
++  return info;
++}
 +
-+  return DestSet && SrcSet && OpcodeSet;
++bool FixupGadgetsPass::needsFixup(struct FixupInfo &fi) const {
++  return (fi.fixup == true);
 +}
 +
-+FixupGadgetsPass::InstrType
-+FixupGadgetsPass::isROPFriendly(MachineInstr &MI) const {
-+  switch (MI.getNumExplicitOperands()) {
-+  case 1:
-+    return isOneGPRegC3(MI) ? OneGPRegC3 : NoType;
-+  case 2:
-+    return isTwoGPRegC3(MI) ? TwoGPRegC3 : NoType;
-+  case 3:
-+    return isThreeGPRegC3(MI) ? ThreeGPRegC3 : NoType;
++bool FixupGadgetsPass::needsAlign(struct FixupInfo &fi) const {
++  return (fi.align == true);
++}
++
++unsigned FixupGadgetsPass::getWidestRegForReg(unsigned reg) const {
++
++  switch (reg) {
++  case X86::AL:
++  case X86::AH:
++  case X86::AX:
++  case X86::EAX:
++  case X86::RAX:
++    return Is64Bit ? X86::RAX : X86::EAX;
++  case X86::BL:
++  case X86::BH:
++  case X86::BX:
++  case X86::EBX:
++  case X86::RBX:
++    return Is64Bit ? X86::RBX : X86::EBX;
++  case X86::CL:
++  case X86::CH:
++  case X86::CX:
++  case X86::ECX:
++  case X86::RCX:
++    return Is64Bit ? X86::RCX : X86::ECX;
++  case X86::DL:
++  case X86::DH:
++  case X86::DX:
++  case X86::EDX:
++  case X86::RDX:
++    return Is64Bit ? X86::RDX : X86::EDX;
++  case X86::R8B:
++  case X86::R8W:
++  case X86::R8D:
++  case X86::R8:
++    return X86::R8;
++  case X86::R9B:
++  case X86::R9W:
++  case X86::R9D:
++  case X86::R9:
++    return X86::R9;
++  case X86::R10B:
++  case X86::R10W:
++  case X86::R10D:
++  case X86::R10:
++    return X86::R10;
++  case X86::R11B:
++  case X86::R11W:
++  case X86::R11D:
++  case X86::R11:
++    return X86::R11;
++  default:
++    return X86::NoRegister; // Non-GP Reg
++  }
++  return 0;
++}
++
++// For given register oreg return the equivalent size register
++// from the nreg register set. Eg. For oreg ebx and nreg ax, return eax.
++unsigned FixupGadgetsPass::getEquivalentRegForReg(unsigned oreg,
++                                                  unsigned nreg) const {
++  unsigned compreg = getWidestRegForReg(nreg);
++
++  switch (oreg) {
++  case X86::AL:
++  case X86::BL:
++  case X86::CL:
++  case X86::DL:
++  case X86::R8B:
++  case X86::R9B:
++  case X86::R10B:
++  case X86::R11B:
++    switch (compreg) {
++    case X86::EAX:
++    case X86::RAX:
++      return X86::AL;
++    case X86::EBX:
++    case X86::RBX:
++      return X86::BL;
++    case X86::ECX:
++    case X86::RCX:
++      return X86::CL;
++    case X86::EDX:
++    case X86::RDX:
++      return X86::DL;
++    case X86::R8:
++      return X86::R8B;
++    case X86::R9:
++      return X86::R9B;
++    case X86::R10:
++      return X86::R10B;
++    case X86::R11:
++      return X86::R11B;
++    default:
++      llvm_unreachable("Unknown 8 bit register");
++    }
++    break;
++  case X86::AH:
++  case X86::BH:
++  case X86::CH:
++  case X86::DH:
++    switch (compreg) {
++    case X86::EAX:
++      return X86::AH;
++    case X86::EBX:
++      return X86::BH;
++    case X86::ECX:
++      return X86::CH;
++    case X86::EDX:
++      return X86::DH;
++    default:
++      llvm_unreachable("Using H registers in REX mode");
++    }
++    break;
++  case X86::AX:
++  case X86::BX:
++  case X86::CX:
++  case X86::DX:
++  case X86::R8W:
++  case X86::R9W:
++  case X86::R10W:
++  case X86::R11W:
++    switch (compreg) {
++    case X86::EAX:
++    case X86::RAX:
++      return X86::AX;
++    case X86::EBX:
++    case X86::RBX:
++      return X86::BX;
++    case X86::ECX:
++    case X86::RCX:
++      return X86::CX;
++    case X86::EDX:
++    case X86::RDX:
++      return X86::DX;
++    case X86::R8:
++      return X86::R8W;
++    case X86::R9:
++      return X86::R9W;
++    case X86::R10:
++      return X86::R10W;
++    case X86::R11:
++      return X86::R11W;
++    default:
++      llvm_unreachable("Unknown 16 bit register");
++    }
++    break;
++  case X86::EAX:
++  case X86::EBX:
++  case X86::ECX:
++  case X86::EDX:
++  case X86::R8D:
++  case X86::R9D:
++  case X86::R10D:
++  case X86::R11D:
++    switch (compreg) {
++    case X86::EAX:
++    case X86::RAX:
++      return X86::EAX;
++    case X86::EBX:
++    case X86::RBX:
++      return X86::EBX;
++    case X86::ECX:
++    case X86::RCX:
++      return X86::ECX;
++    case X86::EDX:
++    case X86::RDX:
++      return X86::EDX;
++    case X86::R8:
++      return X86::R8D;
++    case X86::R9:
++      return X86::R9D;
++    case X86::R10:
++      return X86::R10D;
++    case X86::R11:
++      return X86::R11D;
++    default:
++      llvm_unreachable("Unknown 32 bit register");
++    }
++    break;
++  case X86::RAX:
++  case X86::RBX:
++  case X86::RCX:
++  case X86::RDX:
++  case X86::R8:
++  case X86::R9:
++  case X86::R10:
++  case X86::R11:
++    return compreg;
++  default:
++    llvm_unreachable("Unknown input register!");
 +  }
-+  return NoType;
++}
++
++bool FixupGadgetsPass::hasImplicitUseOrDef(const MachineInstr &MI,
++                                           unsigned Reg1, unsigned Reg2) 
const {
++
++  const MCInstrDesc &Desc = MI.getDesc();
++
++  const MCPhysReg *ImpDefs = Desc.getImplicitDefs();
++  if (ImpDefs) {
++    for (; *ImpDefs; ++ImpDefs) {
++      unsigned w = getWidestRegForReg(*ImpDefs);
++      if (w == Reg1 || w == Reg2) {
++        return true;
++      }
++    }
++  }
++
++  const MCPhysReg *ImpUses = Desc.getImplicitUses();
++  if (ImpUses) {
++    for (; *ImpUses; ++ImpUses) {
++      unsigned w = getWidestRegForReg(*ImpUses);
++      if (w == Reg1 || w == Reg2) {
++        return true;
++      }
++    }
++  }
++  return false;
 +}
 +
 +bool FixupGadgetsPass::fixupInstruction(MachineFunction &MF,
 +                                        MachineBasicBlock &MBB,
-+                                        MachineInstr &MI, InstrType type) {
++                                        MachineInstr &MI, FixupInfo Info) {
 +
-+  if (type == NoType)
++  if (!needsAlign(Info) && !needsFixup(Info))
 +    return false;
 +
-+  MachineOperand *MO0, *MO1, *MO2;
 +  DebugLoc DL = MI.getDebugLoc();
++
++  // Check for only needs alignment
++  if (needsAlign(Info) && !needsFixup(Info)) {
++    BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
++    return true;
++  }
++
 +  unsigned XCHG = Is64Bit ? X86::XCHG64rr : X86::XCHG32rr;
-+  unsigned SREG = Is64Bit ? X86::RAX : X86::EAX;
-+  unsigned DREG = Is64Bit ? X86::RBX : X86::EBX;
-+  unsigned tmpReg;
++
++  unsigned OrigReg1 = MI.getOperand(Info.op1).getReg();
++  // Swap with RAX/EAX unless we have a second register to swap with
++  unsigned OrigReg2 = Is64Bit ? X86::RAX : X86::EAX;
++  if (Info.op2)
++    OrigReg2 = MI.getOperand(Info.op2).getReg();
++
++  unsigned SwapReg1 = getWidestRegForReg(OrigReg1);
++  unsigned SwapReg2 = getWidestRegForReg(OrigReg2);
++  unsigned CompReg1 = SwapReg1;
++  unsigned CompReg2 = SwapReg2;
++
++  // Just align if:
++  // - we have a non-GP reg to swap with
++  // - the instruction implicitly uses one of the registers we are swapping
++  // - if we are fixing an instruction that skips the xchg back
++  if (SwapReg1 == X86::NoRegister || SwapReg2 == X86::NoRegister ||
++      hasImplicitUseOrDef(MI, CompReg1, CompReg2) || MI.isCall() ||
++      MI.isReturn() || MI.isBranch() || MI.isIndirectBranch() ||
++      MI.isBarrier()) {
++    BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
++    return true;
++  }
++
++  // Make sure our XCHG doesn't make a gadget
++  if (badModRM(3, getRegNum(SwapReg1), getRegNum(SwapReg2))) {
++    unsigned treg = SwapReg1;
++    SwapReg1 = SwapReg2;
++    SwapReg2 = treg;
++  }
 +
 +  // Swap the two registers to start
 +  BuildMI(MBB, MI, DL, TII->get(XCHG))
-+    .addReg(DREG, RegState::Define)
-+    .addReg(SREG, RegState::Define)
-+    .addReg(DREG).addReg(SREG);
-+
-+  switch (type) {
-+  case OneGPRegC3:
-+    MO0 = &MI.getOperand(0);
-+    switch (MO0->getReg()) {
-+    case X86::RBX:
-+      tmpReg = X86::RAX;
-+      break;
-+    case X86::EBX:
-+      tmpReg = X86::EAX;
-+      break;
-+    case X86::BX:
-+      tmpReg = X86::AX;
-+      break;
-+    case X86::BL:
-+      tmpReg = X86::AL;
-+      break;
-+    default:
-+      llvm_unreachable("Unknown DestReg in OneGPRegC3 fixup");
-+    }
-+    BuildMI(MBB, MI, DL, MI.getDesc(), tmpReg);
-+    break;
-+  case TwoGPRegC3:
-+    MO0 = &MI.getOperand(0);
-+    MO1 = &MI.getOperand(1);
-+    BuildMI(MBB, MI, DL, MI.getDesc(), MO1->getReg()).addReg(MO0->getReg());
-+    break;
-+  case ThreeGPRegC3:
-+    // Swap args around and set new dest reg
-+    MO0 = &MI.getOperand(0); // Destination
-+    MO2 = &MI.getOperand(2); // Source 2 == Other
-+    BuildMI(MBB, MI, DL, MI.getDesc(), MO2->getReg())
-+        .addReg(MO2->getReg())
-+        .addReg(MO0->getReg());
-+    break;
-+  default:
-+    llvm_unreachable("Unknown FixupGadgets Instruction Type");
++      .addReg(SwapReg1, RegState::Define)
++      .addReg(SwapReg2, RegState::Define)
++      .addReg(SwapReg1).addReg(SwapReg2);
++
++  // Check for needs alignment
++  if (needsAlign(Info))
++    BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
++
++  // Swap the registers inside the instruction
++  for (MachineOperand &MO : MI.operands()) {
++    if (!MO.isReg())
++      continue;
++
++    unsigned reg = MO.getReg();
++    unsigned match = getWidestRegForReg(reg);
++    if (match == CompReg1)
++      MO.setReg(getEquivalentRegForReg(reg, OrigReg2));
++    else if (match == CompReg2)
++      MO.setReg(getEquivalentRegForReg(reg, OrigReg1));
 +  }
 +
-+  // And swap them back to finish
-+  BuildMI(MBB, MI, DL, TII->get(XCHG))
-+    .addReg(DREG, RegState::Define)
-+    .addReg(SREG, RegState::Define)
-+    .addReg(DREG).addReg(SREG);
-+  // Erase original instruction
-+  MI.eraseFromParent();
++  // And swap the two registers back
++  BuildMI(MBB, ++MachineBasicBlock::instr_iterator(MI), DL, TII->get(XCHG))
++      .addReg(SwapReg1, RegState::Define)
++      .addReg(SwapReg2, RegState::Define)
++      .addReg(SwapReg1).addReg(SwapReg2);
 +
 +  return true;
 +}
@@ -265,17 +713,17 @@ Index: lib/Target/X86/X86FixupGadgets.cp
 +  TII = STI->getInstrInfo();
 +  TRI = STI->getRegisterInfo();
 +  Is64Bit = STI->is64Bit();
-+  std::vector<std::pair<MachineInstr *, InstrType>> fixups;
-+  InstrType type;
++  std::vector<std::pair<MachineInstr *, FixupInfo>> fixups;
++  FixupInfo info;
 +
 +  bool modified = false;
 +
 +  for (auto &MBB : MF) {
 +    fixups.clear();
 +    for (auto &MI : MBB) {
-+      type = isROPFriendly(MI);
-+      if (type != NoType)
-+        fixups.push_back(std::make_pair(&MI, type));
++      info = isROPFriendly(MI);
++      if (needsAlign(info) || needsFixup(info))
++        fixups.push_back(std::make_pair(&MI, info));
 +    }
 +    for (auto &fixup : fixups)
 +      modified |= fixupInstruction(MF, MBB, *fixup.first, fixup.second);
Index: patches/patch-lib_Target_X86_X86InstrCompiler_td
===================================================================
RCS file: 
/home/cvs/ports/devel/llvm/patches/patch-lib_Target_X86_X86InstrCompiler_td,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 patch-lib_Target_X86_X86InstrCompiler_td
--- patches/patch-lib_Target_X86_X86InstrCompiler_td    6 Jul 2018 06:55:10 
-0000       1.1
+++ patches/patch-lib_Target_X86_X86InstrCompiler_td    22 Feb 2019 19:22:37 
-0000
@@ -1,27 +1,28 @@
 $OpenBSD: patch-lib_Target_X86_X86InstrCompiler_td,v 1.1 2018/07/06 06:55:10 
ajacoutot Exp $
 
-Add RETGUARD to clang for amd64. This security mechanism uses per-function
-random cookies to protect access to function return instructions, with the
-effect that the integrity of the return address is protected, and function
-return instructions are harder to use in ROP gadgets.
-   
-On function entry the return address is combined with a per-function random
-cookie and stored in the stack frame. The integrity of this value is verified
-before function return, and if this check fails, the program aborts. In this 
way
-RETGUARD is an improved stack protector, since the cookies are per-function. 
The
-verification routine is constructed such that the binary space immediately
-before each ret instruction is padded with int03 instructions, which makes 
these
-return instructions difficult to use in ROP gadgets. In the kernel, this has 
the
-effect of removing approximately 50% of total ROP gadgets, and 15% of unique
-ROP gadgets compared to the 6.3 release kernel. Function epilogues are
-essentially gadget free, leaving only the polymorphic gadgets that result from
-jumping into the instruction stream partway through other instructions. Work to
-remove these gadgets will continue through other mechanisms.
+- Add RETGUARD to clang for amd64. This security mechanism uses per-function
+  random cookies to protect access to function return instructions, with the
+  effect that the integrity of the return address is protected, and function
+  return instructions are harder to use in ROP gadgets.
+
+  On function entry the return address is combined with a per-function random
+  cookie and stored in the stack frame. The integrity of this value is verified
+  before function return, and if this check fails, the program aborts. In this 
way
+  RETGUARD is an improved stack protector, since the cookies are per-function. 
The
+  verification routine is constructed such that the binary space immediately
+  before each ret instruction is padded with int03 instructions, which makes 
these
+  return instructions difficult to use in ROP gadgets. In the kernel, this has 
the
+  effect of removing approximately 50% of total ROP gadgets, and 15% of unique
+  ROP gadgets compared to the 6.3 release kernel. Function epilogues are
+  essentially gadget free, leaving only the polymorphic gadgets that result 
from
+  jumping into the instruction stream partway through other instructions. Work 
to
+  remove these gadgets will continue through other mechanisms.
+- Improve the X86FixupGadgets pass
 
 Index: lib/Target/X86/X86InstrCompiler.td
 --- lib/Target/X86/X86InstrCompiler.td.orig
 +++ lib/Target/X86/X86InstrCompiler.td
-@@ -267,6 +267,21 @@ def MORESTACK_RET_RESTORE_R10 : I<0, Pseudo, (outs), (
+@@ -267,6 +267,25 @@ def MORESTACK_RET_RESTORE_R10 : I<0, Pseudo, (outs), (
  }
  
  
//===----------------------------------------------------------------------===//
@@ -37,6 +38,10 @@ Index: lib/Target/X86/X86InstrCompiler.t
 +// the return value (ie mov %ecx, %eax instead of mov %cl, %al).
 +let isCodeGenOnly = 1, Uses = [EFLAGS] in {
 +def RETGUARD_JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>;
++}
++
++let isCodeGenOnly = 1 in {
++def JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>;
 +}
 +
 
+//===----------------------------------------------------------------------===//
Index: patches/patch-lib_Target_X86_X86MCInstLower_cpp
===================================================================
RCS file: 
/home/cvs/ports/devel/llvm/patches/patch-lib_Target_X86_X86MCInstLower_cpp,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 patch-lib_Target_X86_X86MCInstLower_cpp
--- patches/patch-lib_Target_X86_X86MCInstLower_cpp     28 Jan 2019 06:27:28 
-0000      1.5
+++ patches/patch-lib_Target_X86_X86MCInstLower_cpp     22 Feb 2019 19:12:52 
-0000
@@ -22,7 +22,7 @@ $OpenBSD: patch-lib_Target_X86_X86MCInst
 Index: lib/Target/X86/X86MCInstLower.cpp
 --- lib/Target/X86/X86MCInstLower.cpp.orig
 +++ lib/Target/X86/X86MCInstLower.cpp
-@@ -1831,6 +1831,16 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
+@@ -1831,6 +1831,27 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
          MCInstBuilder(X86::MOV64rr).addReg(X86::R10).addReg(X86::RAX));
      return;
  
@@ -36,10 +36,21 @@ Index: lib/Target/X86/X86MCInstLower.cpp
 +    return;
 +  }
 +
++  case X86::JMP_TRAP: {
++    MCSymbol *RGSuccSym = OutContext.createTempSymbol();
++    const MCExpr *RGSuccExpr = MCSymbolRefExpr::create(RGSuccSym, OutContext);
++    EmitAndCountInstruction(MCInstBuilder(X86::JMP_1).addExpr(RGSuccExpr));
++    EmitAndCountInstruction(MCInstBuilder(X86::INT3));
++    EmitAndCountInstruction(MCInstBuilder(X86::INT3));
++    OutStreamer->EmitValueToAlignment(8, 0xCC, 1);
++    OutStreamer->EmitLabel(RGSuccSym);
++    return;
++  }
++
    case X86::SEH_PushReg:
    case X86::SEH_SaveReg:
    case X86::SEH_SaveXMM:
-@@ -2257,4 +2267,10 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
+@@ -2257,4 +2278,10 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
    }
  
    EmitAndCountInstruction(TmpInst);
Index: patches/patch-tools_clang_include_clang_Driver_Options_td
===================================================================
RCS file: 
/home/cvs/ports/devel/llvm/patches/patch-tools_clang_include_clang_Driver_Options_td,v
retrieving revision 1.17
diff -u -p -u -p -r1.17 patch-tools_clang_include_clang_Driver_Options_td
--- patches/patch-tools_clang_include_clang_Driver_Options_td   11 Feb 2019 
05:24:16 -0000      1.17
+++ patches/patch-tools_clang_include_clang_Driver_Options_td   22 Feb 2019 
19:24:34 -0000
@@ -1,13 +1,14 @@
 $OpenBSD: patch-tools_clang_include_clang_Driver_Options_td,v 1.17 2019/02/11 
05:24:16 jca Exp $
 
 - Add ret protctor options as no-ops.
+- Improve the X86FixupGadgets pass
 - Alias the command line parameter -p to -pg.
 - implement -msave-args in clang/llvm, like the sun did for gcc
 
 Index: tools/clang/include/clang/Driver/Options.td
 --- tools/clang/include/clang/Driver/Options.td.orig
 +++ tools/clang/include/clang/Driver/Options.td
-@@ -1595,6 +1595,10 @@ def fstack_protector_strong : Flag<["-"], "fstack-prot
+@@ -1595,6 +1595,14 @@ def fstack_protector_strong : Flag<["-"], "fstack-prot
    HelpText<"Use a strong heuristic to apply stack protectors to functions">;
  def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>,
    HelpText<"Enable stack protectors for functions potentially vulnerable to 
stack smashing">;
@@ -15,10 +16,14 @@ Index: tools/clang/include/clang/Driver/
 +  HelpText<"Disable return protector">;
 +def fret_protector : Flag<["-"], "fret-protector">, Group<f_Group>,
 +  HelpText<"Enable return protector">;
++def fno_fixup_gadgets : Flag<["-"], "fno-fixup-gadgets">, Group<f_Group>,
++  HelpText<"Disable FixupGadgets pass (x86 only)">;
++def ffixup_gadgets : Flag<["-"], "ffixup-gadgets">, Group<f_Group>,
++  HelpText<"Replace ROP friendly instructions with safe alternatives (x86 
only)">;
  def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, 
Flags<[CoreOption]>,
    HelpText<"Emit full debug info for all types used by the program">;
  def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, 
Group<f_Group>, Flags<[CoreOption]>,
-@@ -2359,7 +2363,7 @@ def pthreads : Flag<["-"], "pthreads">;
+@@ -2359,7 +2367,7 @@ def pthreads : Flag<["-"], "pthreads">;
  def pthread : Flag<["-"], "pthread">, Flags<[CC1Option]>,
    HelpText<"Support POSIX threads in generated code">;
  def no_pthread : Flag<["-"], "no-pthread">, Flags<[CC1Option]>;
@@ -27,7 +32,7 @@ Index: tools/clang/include/clang/Driver/
  def pie : Flag<["-"], "pie">;
  def read__only__relocs : Separate<["-"], "read_only_relocs">;
  def remap : Flag<["-"], "remap">;
-@@ -2810,6 +2814,8 @@ def mretpoline : Flag<["-"], "mretpoline">, Group<m_x8
+@@ -2810,6 +2818,8 @@ def mretpoline : Flag<["-"], "mretpoline">, Group<m_x8
  def mno_retpoline : Flag<["-"], "mno-retpoline">, Group<m_x86_Features_Group>;
  def mretpoline_external_thunk : Flag<["-"], "mretpoline-external-thunk">, 
Group<m_x86_Features_Group>;
  def mno_retpoline_external_thunk : Flag<["-"], 
"mno-retpoline-external-thunk">, Group<m_x86_Features_Group>;
Index: patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp
===================================================================
RCS file: 
/home/cvs/ports/devel/llvm/patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp,v
retrieving revision 1.7
diff -u -p -u -p -r1.7 patch-tools_clang_lib_Driver_ToolChains_Clang_cpp
--- patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp   28 Jan 2019 
06:27:28 -0000      1.7
+++ patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp   22 Feb 2019 
19:28:40 -0000
@@ -22,6 +22,7 @@ $OpenBSD: patch-tools_clang_lib_Driver_T
   jumping into the instruction stream partway through other instructions. Work 
to
   remove these gadgets will continue through other mechanisms.
 - Add retguard for arm64.
+- Improve the X86FixupGadgets pass
 - On OpenBSD disable the malloc/calloc/realloc/free/str*dup builtins, since
   they can perform strange transforms and optimizations.  Some of those could
   gain a slight advantage, but would avoid the variety of important runtime
@@ -65,7 +66,7 @@ Index: tools/clang/lib/Driver/ToolChains
  
    if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
                                 options::OPT_fno_reroll_loops))
-@@ -4101,6 +4105,24 @@ void Clang::ConstructJob(Compilation &C, const JobActi
+@@ -4101,6 +4105,34 @@ void Clang::ConstructJob(Compilation &C, const JobActi
  
    RenderSSPOptions(getToolChain(), Args, CmdArgs, KernelOrKext);
  
@@ -87,10 +88,20 @@ Index: tools/clang/lib/Driver/ToolChains
 +    CmdArgs.push_back(Args.MakeArgString(Twine("-ret-protector")));
 +  }
 +
++  // -fixup-gadgets
++  if (Arg *A = Args.getLastArg(options::OPT_fno_fixup_gadgets,
++                               options::OPT_ffixup_gadgets)) {
++    CmdArgs.push_back(Args.MakeArgString(Twine("-mllvm")));
++    if (A->getOption().matches(options::OPT_fno_fixup_gadgets))
++      
CmdArgs.push_back(Args.MakeArgString(Twine("-x86-fixup-gadgets=false")));
++    else if (A->getOption().matches(options::OPT_ffixup_gadgets))
++      CmdArgs.push_back(Args.MakeArgString(Twine("-x86-fixup-gadgets=true")));
++  }
++
    // Translate -mstackrealign
    if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
                     false))
-@@ -4579,6 +4601,18 @@ void Clang::ConstructJob(Compilation &C, const JobActi
+@@ -4579,6 +4611,18 @@ void Clang::ConstructJob(Compilation &C, const JobActi
        llvm::sys::path::replace_extension(F, "opt.yaml");
        CmdArgs.push_back(Args.MakeArgString(F));
      }

Reply via email to