Index: lib/Target/X86/MCTargetDesc/X86MCNaCl.cpp |
diff --git a/lib/Target/X86/MCTargetDesc/X86MCNaCl.cpp b/lib/Target/X86/MCTargetDesc/X86MCNaCl.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2e3e4e5449613b651b940d62e535109c8dd2402a |
--- /dev/null |
+++ b/lib/Target/X86/MCTargetDesc/X86MCNaCl.cpp |
@@ -0,0 +1,842 @@ |
+//=== X86MCNaCl.cpp - Expansion of NaCl pseudo-instructions --*- C++ -*-=// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+//===----------------------------------------------------------------------===// |
+#define DEBUG_TYPE "x86-sandboxing" |
+ |
+#include "MCTargetDesc/X86MCTargetDesc.h" |
+#include "MCTargetDesc/X86BaseInfo.h" |
+#include "MCTargetDesc/X86MCNaCl.h" |
+#include "X86NaClDecls.h" |
+#include "llvm/MC/MCAsmInfo.h" |
+#include "llvm/MC/MCContext.h" |
+#include "llvm/MC/MCExpr.h" |
+#include "llvm/MC/MCInstrInfo.h" |
+#include "llvm/MC/MCRegisterInfo.h" |
+#include "llvm/MC/MCInst.h" |
+#include "llvm/MC/MCObjectFileInfo.h" |
+#include "llvm/MC/MCStreamer.h" |
+#include "llvm/CodeGen/ValueTypes.h" |
+#include "llvm/Support/CommandLine.h" |
+#include "llvm/Support/Debug.h" |
+ |
+using namespace llvm; |
+ |
+cl::opt<bool> FlagUseZeroBasedSandbox("sfi-zero-based-sandbox", |
+ cl::desc("Use a zero-based sandbox model" |
+ " for the NaCl SFI."), |
+ cl::init(false)); |
+// This flag can be set to false to test the performance impact of |
+// hiding the sandbox base. |
+cl::opt<bool> FlagHideSandboxBase("sfi-hide-sandbox-base", |
+ cl::desc("Prevent 64-bit NaCl sandbox" |
+ " pointers from being written to" |
+ " the stack. [default=true]"), |
+ cl::init(true)); |
+ |
+const int kNaClX86InstructionBundleSize = 32; |
+ |
+// See the notes below where these functions are defined. |
+namespace { |
+unsigned getX86SubSuperRegister_(unsigned Reg, EVT VT, bool High=false); |
+unsigned DemoteRegTo32_(unsigned RegIn); |
+} // namespace |
+ |
+static MCSymbol *CreateTempLabel(MCContext &Context, const char *Prefix) { |
+ SmallString<128> NameSV; |
+ raw_svector_ostream(NameSV) |
+ << Context.getAsmInfo()->getPrivateGlobalPrefix() // get internal label |
+ << Prefix << Context.getUniqueSymbolID(); |
+ return Context.GetOrCreateSymbol(NameSV); |
+} |
+ |
+static void PushReturnAddress(const llvm::MCSubtargetInfo &STI, |
+ MCContext &Context, MCStreamer &Out, |
+ MCSymbol *RetTarget) { |
+ const MCExpr *RetTargetExpr = MCSymbolRefExpr::Create(RetTarget, Context); |
+ if (Context.getObjectFileInfo()->getRelocM() == Reloc::PIC_) { |
+ // Calculate return_addr |
+ // The return address should not be calculated into R11 because if the push |
+ // instruction ends up at the start of a bundle, an attacker could arrange |
+ // an indirect jump to it, which would push the full jump target |
+ // (which itself was calculated into r11) onto the stack. |
+ MCInst LEAInst; |
+ LEAInst.setOpcode(X86::LEA64_32r); |
+ LEAInst.addOperand(MCOperand::CreateReg(X86::R10D)); // DestReg |
+ LEAInst.addOperand(MCOperand::CreateReg(X86::RIP)); // BaseReg |
+ LEAInst.addOperand(MCOperand::CreateImm(1)); // Scale |
+ LEAInst.addOperand(MCOperand::CreateReg(0)); // IndexReg |
+ LEAInst.addOperand(MCOperand::CreateExpr(RetTargetExpr)); // Offset |
+ LEAInst.addOperand(MCOperand::CreateReg(0)); // SegmentReg |
+ Out.EmitInstruction(LEAInst, STI); |
+ // push return_addr |
+ MCInst PUSHInst; |
+ PUSHInst.setOpcode(X86::PUSH64r); |
+ PUSHInst.addOperand(MCOperand::CreateReg(X86::R10)); |
+ Out.EmitInstruction(PUSHInst, STI); |
+ } else { |
+ // push return_addr |
+ MCInst PUSHInst; |
+ PUSHInst.setOpcode(X86::PUSH64i32); |
+ PUSHInst.addOperand(MCOperand::CreateExpr(RetTargetExpr)); |
+ Out.EmitInstruction(PUSHInst, STI); |
+ } |
+} |
+ |
+static void EmitDirectCall(const llvm::MCSubtargetInfo &STI, |
+ const MCOperand &Op, bool Is64Bit, MCStreamer &Out) { |
+ const bool HideSandboxBase = |
+ (FlagHideSandboxBase && Is64Bit && !FlagUseZeroBasedSandbox); |
+ if (HideSandboxBase) { |
+ // For NaCl64, the sequence |
+ // call target |
+ // return_addr: |
+ // is changed to |
+ // push return_addr |
+ // jmp target |
+ // .align 32 |
+ // return_addr: |
+ // This avoids exposing the sandbox base address via the return |
+ // address on the stack. |
+ |
+ // When generating PIC code, calculate the return address manually: |
+ // leal return_addr(%rip), %r10d |
+ // push %r10 |
+ // jmp target |
+ // .align 32 |
+ // return_addr: |
+ |
+ MCContext &Context = Out.getContext(); |
+ |
+ // Generate a label for the return address. |
+ MCSymbol *RetTarget = CreateTempLabel(Context, "DirectCallRetAddr"); |
+ |
+ PushReturnAddress(STI, Context, Out, RetTarget); |
+ |
+ // jmp target |
+ MCInst JMPInst; |
+ JMPInst.setOpcode(X86::JMP_4); |
+ JMPInst.addOperand(Op); |
+ Out.EmitInstruction(JMPInst, STI); |
+ |
+ Out.EmitCodeAlignment(kNaClX86InstructionBundleSize); |
+ Out.EmitLabel(RetTarget); |
+ } else { |
+ Out.EmitBundleLock(true); |
+ |
+ MCInst CALLInst; |
+ CALLInst.setOpcode(Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32); |
+ CALLInst.addOperand(Op); |
+ Out.EmitInstruction(CALLInst, STI); |
+ Out.EmitBundleUnlock(); |
+ } |
+} |
+ |
+static void EmitIndirectBranch(const llvm::MCSubtargetInfo &STI, |
+ const MCOperand &Op, bool Is64Bit, bool IsCall, |
+ MCStreamer &Out) { |
+ const bool HideSandboxBase = |
+ (FlagHideSandboxBase && Is64Bit && !FlagUseZeroBasedSandbox); |
+ const int JmpMask = -kNaClX86InstructionBundleSize; |
+ unsigned Reg32 = Op.getReg(); |
+ |
+ // For NaCl64, the sequence |
+ // jmp *%rXX |
+ // is changed to |
+ // mov %rXX,%r11d |
+ // and $0xffffffe0,%r11d |
+ // add %r15,%r11 |
+ // jmpq *%r11 |
+ // |
+ // And the sequence |
+ // call *%rXX |
+ // return_addr: |
+ // is changed to |
+ // mov %rXX,%r11d |
+ // push return_addr |
+ // and $0xffffffe0,%r11d |
+ // add %r15,%r11 |
+ // jmpq *%r11 |
+ // .align 32 |
+ // return_addr: |
+ // |
+ // This avoids exposing the sandbox base address via the return |
+ // address on the stack. |
+ |
+ // When generating PIC code for calls, calculate the return address manually: |
+ // mov %rXX,%r11d |
+ // leal return_addr(%rip), %r10d |
+ // pushq %r10 |
+ // and $0xffffffe0,%r11d |
+ // add %r15,%r11 |
+ // jmpq *%r11 |
+ // .align 32 |
+ // return_addr: |
+ |
+ MCSymbol *RetTarget = NULL; |
+ |
+ // For NaCl64, force an assignment of the branch target into r11, |
+ // and subsequently use r11 as the ultimate branch target, so that |
+ // only r11 (which will never be written to memory) exposes the |
+ // sandbox base address. But avoid a redundant assignment if the |
+ // original branch target is already r11 or r11d. |
+ const unsigned SafeReg32 = X86::R11D; |
+ const unsigned SafeReg64 = X86::R11; |
+ if (HideSandboxBase) { |
+ // In some cases, EmitIndirectBranch() is called with a 32-bit |
+ // register Op (e.g. r11d), and in other cases a 64-bit register |
+ // (e.g. r11), so we need to test both variants to avoid a |
+ // redundant assignment. TODO(stichnot): Make callers consistent |
+ // on 32 vs 64 bit register. |
+ if ((Reg32 != SafeReg32) && (Reg32 != SafeReg64)) { |
+ MCInst MOVInst; |
+ MOVInst.setOpcode(X86::MOV32rr); |
+ MOVInst.addOperand(MCOperand::CreateReg(SafeReg32)); |
+ MOVInst.addOperand(MCOperand::CreateReg(Reg32)); |
+ Out.EmitInstruction(MOVInst, STI); |
+ Reg32 = SafeReg32; |
+ } |
+ if (IsCall) { |
+ MCContext &Context = Out.getContext(); |
+ // Generate a label for the return address. |
+ RetTarget = CreateTempLabel(Context, "IndirectCallRetAddr"); |
+ // Explicitly push the (32-bit) return address for a NaCl64 call |
+ // instruction. |
+ PushReturnAddress(STI, Context, Out, RetTarget); |
+ } |
+ } |
+ const unsigned Reg64 = getX86SubSuperRegister_(Reg32, MVT::i64); |
+ |
+ const bool WillEmitCallInst = IsCall && !HideSandboxBase; |
+ Out.EmitBundleLock(WillEmitCallInst); |
+ |
+ MCInst ANDInst; |
+ ANDInst.setOpcode(X86::AND32ri8); |
+ ANDInst.addOperand(MCOperand::CreateReg(Reg32)); |
+ ANDInst.addOperand(MCOperand::CreateReg(Reg32)); |
+ ANDInst.addOperand(MCOperand::CreateImm(JmpMask)); |
+ Out.EmitInstruction(ANDInst, STI); |
+ |
+ if (Is64Bit && !FlagUseZeroBasedSandbox) { |
+ MCInst InstADD; |
+ InstADD.setOpcode(X86::ADD64rr); |
+ InstADD.addOperand(MCOperand::CreateReg(Reg64)); |
+ InstADD.addOperand(MCOperand::CreateReg(Reg64)); |
+ InstADD.addOperand(MCOperand::CreateReg(X86::R15)); |
+ Out.EmitInstruction(InstADD, STI); |
+ } |
+ |
+ if (WillEmitCallInst) { |
+ // callq *%rXX |
+ MCInst CALLInst; |
+ CALLInst.setOpcode(Is64Bit ? X86::CALL64r : X86::CALL32r); |
+ CALLInst.addOperand(MCOperand::CreateReg(Is64Bit ? Reg64 : Reg32)); |
+ Out.EmitInstruction(CALLInst, STI); |
+ } else { |
+ // jmpq *%rXX -or- jmpq *%r11 |
+ MCInst JMPInst; |
+ JMPInst.setOpcode(Is64Bit ? X86::JMP64r : X86::JMP32r); |
+ JMPInst.addOperand(MCOperand::CreateReg(Is64Bit ? Reg64 : Reg32)); |
+ Out.EmitInstruction(JMPInst, STI); |
+ } |
+ Out.EmitBundleUnlock(); |
+ if (RetTarget) { |
+ Out.EmitCodeAlignment(kNaClX86InstructionBundleSize); |
+ Out.EmitLabel(RetTarget); |
+ } |
+} |
+ |
+static void EmitRet(const llvm::MCSubtargetInfo &STI, const MCOperand *AmtOp, |
+ bool Is64Bit, MCStreamer &Out) { |
+ // For NaCl64 returns, follow the convention of using r11 to hold |
+ // the target of an indirect jump to avoid potentially leaking the |
+ // sandbox base address. |
+ const bool HideSandboxBase = (FlagHideSandboxBase && |
+ Is64Bit && !FlagUseZeroBasedSandbox); |
+ // For NaCl64 sandbox hiding, use r11 to hold the branch target. |
+ // Otherwise, use rcx/ecx for fewer instruction bytes (no REX |
+ // prefix). |
+ const unsigned RegTarget = HideSandboxBase ? X86::R11 : |
+ (Is64Bit ? X86::RCX : X86::ECX); |
+ MCInst POPInst; |
+ POPInst.setOpcode(Is64Bit ? X86::POP64r : X86::POP32r); |
+ POPInst.addOperand(MCOperand::CreateReg(RegTarget)); |
+ Out.EmitInstruction(POPInst, STI); |
+ |
+ if (AmtOp) { |
+ assert(!Is64Bit); |
+ MCInst ADDInst; |
+ unsigned ADDReg = X86::ESP; |
+ ADDInst.setOpcode(X86::ADD32ri); |
+ ADDInst.addOperand(MCOperand::CreateReg(ADDReg)); |
+ ADDInst.addOperand(MCOperand::CreateReg(ADDReg)); |
+ ADDInst.addOperand(*AmtOp); |
+ Out.EmitInstruction(ADDInst, STI); |
+ } |
+ |
+ EmitIndirectBranch(STI, MCOperand::CreateReg(RegTarget), Is64Bit, false, Out); |
+} |
+ |
+// Fix a register after being truncated to 32-bits. |
+static void EmitRegFix(const llvm::MCSubtargetInfo &STI, unsigned Reg64, |
+ MCStreamer &Out) { |
+ // lea (%rsp, %r15, 1), %rsp |
+ // We do not need to add the R15 base for the zero-based sandbox model |
+ if (!FlagUseZeroBasedSandbox) { |
+ MCInst Tmp; |
+ Tmp.setOpcode(X86::LEA64r); |
+ Tmp.addOperand(MCOperand::CreateReg(Reg64)); // DestReg |
+ Tmp.addOperand(MCOperand::CreateReg(Reg64)); // BaseReg |
+ Tmp.addOperand(MCOperand::CreateImm(1)); // Scale |
+ Tmp.addOperand(MCOperand::CreateReg(X86::R15)); // IndexReg |
+ Tmp.addOperand(MCOperand::CreateImm(0)); // Offset |
+ Tmp.addOperand(MCOperand::CreateReg(0)); // SegmentReg |
+ Out.EmitInstruction(Tmp, STI); |
+ } |
+} |
+ |
+static void EmitSPArith(const llvm::MCSubtargetInfo &STI, unsigned Opc, |
+ const MCOperand &ImmOp, MCStreamer &Out) { |
+ Out.EmitBundleLock(false); |
+ |
+ MCInst Tmp; |
+ Tmp.setOpcode(Opc); |
+ Tmp.addOperand(MCOperand::CreateReg(X86::ESP)); |
+ Tmp.addOperand(MCOperand::CreateReg(X86::ESP)); |
+ Tmp.addOperand(ImmOp); |
+ Out.EmitInstruction(Tmp, STI); |
+ |
+ EmitRegFix(STI, X86::RSP, Out); |
+ Out.EmitBundleUnlock(); |
+} |
+ |
+static void EmitSPAdj(const llvm::MCSubtargetInfo &STI, const MCOperand &ImmOp, |
+ MCStreamer &Out) { |
+ Out.EmitBundleLock(false); |
+ |
+ MCInst Tmp; |
+ Tmp.setOpcode(X86::LEA64_32r); |
+ Tmp.addOperand(MCOperand::CreateReg(X86::RSP)); // DestReg |
+ Tmp.addOperand(MCOperand::CreateReg(X86::RBP)); // BaseReg |
+ Tmp.addOperand(MCOperand::CreateImm(1)); // Scale |
+ Tmp.addOperand(MCOperand::CreateReg(0)); // IndexReg |
+ Tmp.addOperand(ImmOp); // Offset |
+ Tmp.addOperand(MCOperand::CreateReg(0)); // SegmentReg |
+ Out.EmitInstruction(Tmp, STI); |
+ |
+ EmitRegFix(STI, X86::RSP, Out); |
+ Out.EmitBundleUnlock(); |
+} |
+ |
+static void EmitPrefix(const llvm::MCSubtargetInfo &STI, unsigned Opc, |
+ MCStreamer &Out, X86MCNaClSFIState &State) { |
+ assert(State.PrefixSaved == 0); |
+ assert(State.PrefixPass == false); |
+ |
+ MCInst PrefixInst; |
+ PrefixInst.setOpcode(Opc); |
+ State.PrefixPass = true; |
+ Out.EmitInstruction(PrefixInst, STI); |
+ |
+ assert(State.PrefixSaved == 0); |
+ assert(State.PrefixPass == false); |
+} |
+ |
+static void EmitMoveRegReg(const llvm::MCSubtargetInfo &STI, bool Is64Bit, |
+ unsigned ToReg, unsigned FromReg, MCStreamer &Out) { |
+ MCInst Move; |
+ Move.setOpcode(Is64Bit ? X86::MOV64rr : X86::MOV32rr); |
+ Move.addOperand(MCOperand::CreateReg(ToReg)); |
+ Move.addOperand(MCOperand::CreateReg(FromReg)); |
+ Out.EmitInstruction(Move, STI); |
+} |
+ |
+static void EmitRegTruncate(const llvm::MCSubtargetInfo &STI, unsigned Reg64, |
+ MCStreamer &Out) { |
+ unsigned Reg32 = getX86SubSuperRegister_(Reg64, MVT::i32); |
+ EmitMoveRegReg(STI, false, Reg32, Reg32, Out); |
+} |
+ |
+static void HandleMemoryRefTruncation(const llvm::MCSubtargetInfo &STI, |
+ MCInst *Inst, unsigned IndexOpPosition, |
+ MCStreamer &Out) { |
+ unsigned IndexReg = Inst->getOperand(IndexOpPosition).getReg(); |
+ if (FlagUseZeroBasedSandbox) { |
+ // With the zero-based sandbox, we use a 32-bit register on the index |
+ Inst->getOperand(IndexOpPosition).setReg(DemoteRegTo32_(IndexReg)); |
+ } else { |
+ EmitRegTruncate(STI, IndexReg, Out); |
+ } |
+} |
+ |
+static void ShortenMemoryRef(MCInst *Inst, unsigned IndexOpPosition) { |
+ unsigned ImmOpPosition = IndexOpPosition - 1; |
+ unsigned BaseOpPosition = IndexOpPosition - 2; |
+ unsigned IndexReg = Inst->getOperand(IndexOpPosition).getReg(); |
+ // For the SIB byte, if the scale is 1 and the base is 0, then |
+ // an equivalent setup moves index to base, and index to 0. The |
+ // equivalent setup is optimized to remove the SIB byte in |
+ // X86MCCodeEmitter.cpp. |
+ if (Inst->getOperand(ImmOpPosition).getImm() == 1 && |
+ Inst->getOperand(BaseOpPosition).getReg() == 0) { |
+ Inst->getOperand(BaseOpPosition).setReg(IndexReg); |
+ Inst->getOperand(IndexOpPosition).setReg(0); |
+ } |
+} |
+ |
+static void EmitLoad(const llvm::MCSubtargetInfo &STI, bool Is64Bit, |
+ unsigned DestReg, unsigned BaseReg, unsigned Scale, |
+ unsigned IndexReg, unsigned Offset, unsigned SegmentReg, |
+ MCStreamer &Out) { |
+ // Load DestReg from address BaseReg + Scale * IndexReg + Offset |
+ MCInst Load; |
+ Load.setOpcode(Is64Bit ? X86::MOV64rm : X86::MOV32rm); |
+ Load.addOperand(MCOperand::CreateReg(DestReg)); |
+ Load.addOperand(MCOperand::CreateReg(BaseReg)); |
+ Load.addOperand(MCOperand::CreateImm(Scale)); |
+ Load.addOperand(MCOperand::CreateReg(IndexReg)); |
+ Load.addOperand(MCOperand::CreateImm(Offset)); |
+ Load.addOperand(MCOperand::CreateReg(SegmentReg)); |
+ Out.EmitInstruction(Load, STI); |
+} |
+ |
+static bool SandboxMemoryRef(MCInst *Inst, |
+ unsigned *IndexOpPosition) { |
+ for (unsigned i = 0, last = Inst->getNumOperands(); i < last; i++) { |
+ if (!Inst->getOperand(i).isReg() || |
+ Inst->getOperand(i).getReg() != X86::PSEUDO_NACL_SEG) { |
+ continue; |
+ } |
+ // Return the index register that will need to be truncated. |
+ // The order of operands on a memory reference is always: |
+ // (BaseReg, ScaleImm, IndexReg, DisplacementImm, SegmentReg), |
+ // So if we found a match for a segment register value, we know that |
+ // the index register is exactly two operands prior. |
+ *IndexOpPosition = i - 2; |
+ |
+ // Remove the PSEUDO_NACL_SEG annotation. |
+ Inst->getOperand(i).setReg(0); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+static void EmitREST(const llvm::MCSubtargetInfo &STI, const MCInst &Inst, |
+ unsigned Reg32, bool IsMem, MCStreamer &Out) { |
+ unsigned Reg64 = getX86SubSuperRegister_(Reg32, MVT::i64); |
+ Out.EmitBundleLock(false); |
+ if (!IsMem) { |
+ EmitMoveRegReg(STI, false, Reg32, Inst.getOperand(0).getReg(), Out); |
+ } else { |
+ unsigned IndexOpPosition; |
+ MCInst SandboxedInst = Inst; |
+ if (SandboxMemoryRef(&SandboxedInst, &IndexOpPosition)) { |
+ HandleMemoryRefTruncation(STI, &SandboxedInst, IndexOpPosition, Out); |
+ ShortenMemoryRef(&SandboxedInst, IndexOpPosition); |
+ } |
+ EmitLoad(STI, false, Reg32, |
+ SandboxedInst.getOperand(0).getReg(), // BaseReg |
+ SandboxedInst.getOperand(1).getImm(), // Scale |
+ SandboxedInst.getOperand(2).getReg(), // IndexReg |
+ SandboxedInst.getOperand(3).getImm(), // Offset |
+ SandboxedInst.getOperand(4).getReg(), // SegmentReg |
+ Out); |
+ } |
+ |
+ EmitRegFix(STI, Reg64, Out); |
+ Out.EmitBundleUnlock(); |
+} |
+ |
+ |
+namespace { |
+// RAII holder for the recursion guard. |
+class EmitRawState { |
+ public: |
+ EmitRawState(X86MCNaClSFIState &S) : State(S) { |
+ State.EmitRaw = true; |
+ } |
+ ~EmitRawState() { |
+ State.EmitRaw = false; |
+ } |
+ private: |
+ X86MCNaClSFIState &State; |
+}; |
+} |
+ |
+namespace llvm { |
+// CustomExpandInstNaClX86 - |
+// If Inst is a NaCl pseudo instruction, emits the substitute |
+// expansion to the MCStreamer and returns true. |
+// Otherwise, returns false. |
+// |
+// NOTE: Each time this function calls Out.EmitInstruction(), it will be |
+// called again recursively to rewrite the new instruction being emitted. |
+// Care must be taken to ensure that this does not result in an infinite |
+// loop. Also, global state must be managed carefully so that it is |
+// consistent during recursive calls. |
+// |
+// We need global state to keep track of the explicit prefix (PREFIX_*) |
+// instructions. Unfortunately, the assembly parser prefers to generate |
+// these instead of combined instructions. At this time, having only |
+// one explicit prefix is supported. |
+bool CustomExpandInstNaClX86(const llvm::MCSubtargetInfo &STI, |
+ const MCInst &Inst, MCStreamer &Out, |
+ X86MCNaClSFIState &State) { |
+ // If we are emitting to .s, only sandbox pseudos not supported by gas. |
+ if (Out.hasRawTextSupport()) { |
+ if (!(Inst.getOpcode() == X86::NACL_ANDSPi8 || |
+ Inst.getOpcode() == X86::NACL_ANDSPi32)) |
+ return false; |
+ } |
+ // If we make a call to EmitInstruction, we will be called recursively. In |
+ // this case we just want the raw instruction to be emitted instead of |
+ // handling the insruction here. |
+ if (State.EmitRaw == true && !State.PrefixPass) { |
+ return false; |
+ } |
+ EmitRawState E(State); |
+ unsigned Opc = Inst.getOpcode(); |
+ DEBUG(dbgs() << "CustomExpandInstNaClX86("; Inst.dump(); dbgs() << ")\n"); |
+ switch (Opc) { |
+ case X86::LOCK_PREFIX: |
+ case X86::REP_PREFIX: |
+ case X86::REPNE_PREFIX: |
+ case X86::REX64_PREFIX: |
+ // Ugly hack because LLVM AsmParser is not smart enough to combine |
+ // prefixes back into the instruction they modify. |
+ if (State.PrefixPass) { |
+ State.PrefixPass = false; |
+ State.PrefixSaved = 0; |
+ return false; |
+ } |
+ assert(State.PrefixSaved == 0); |
+ State.PrefixSaved = Opc; |
+ return true; |
+ case X86::CALLpcrel32: |
+ assert(State.PrefixSaved == 0); |
+ EmitDirectCall(STI, Inst.getOperand(0), false, Out); |
+ return true; |
+ case X86::CALL64pcrel32: |
+ case X86::NACL_CALL64d: |
+ assert(State.PrefixSaved == 0); |
+ EmitDirectCall(STI, Inst.getOperand(0), true, Out); |
+ return true; |
+ case X86::NACL_CALL32r: |
+ assert(State.PrefixSaved == 0); |
+ EmitIndirectBranch(STI, Inst.getOperand(0), false, true, Out); |
+ return true; |
+ case X86::NACL_CALL64r: |
+ assert(State.PrefixSaved == 0); |
+ EmitIndirectBranch(STI, Inst.getOperand(0), true, true, Out); |
+ return true; |
+ case X86::NACL_JMP32r: |
+ assert(State.PrefixSaved == 0); |
+ EmitIndirectBranch(STI, Inst.getOperand(0), false, false, Out); |
+ return true; |
+ case X86::NACL_JMP64r: |
+ case X86::NACL_JMP64z: |
+ assert(State.PrefixSaved == 0); |
+ EmitIndirectBranch(STI, Inst.getOperand(0), true, false, Out); |
+ return true; |
+ case X86::NACL_RET32: |
+ assert(State.PrefixSaved == 0); |
+ EmitRet(STI, NULL, false, Out); |
+ return true; |
+ case X86::NACL_RET64: |
+ assert(State.PrefixSaved == 0); |
+ EmitRet(STI, NULL, true, Out); |
+ return true; |
+ case X86::NACL_RETI32: |
+ assert(State.PrefixSaved == 0); |
+ EmitRet(STI, &Inst.getOperand(0), false, Out); |
+ return true; |
+ case X86::NACL_ASPi8: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPArith(STI, X86::ADD32ri8, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_ASPi32: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPArith(STI, X86::ADD32ri, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_SSPi8: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPArith(STI, X86::SUB32ri8, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_SSPi32: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPArith(STI, X86::SUB32ri, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_ANDSPi8: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPArith(STI, X86::AND32ri8, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_ANDSPi32: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPArith(STI, X86::AND32ri, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_SPADJi32: |
+ assert(State.PrefixSaved == 0); |
+ EmitSPAdj(STI, Inst.getOperand(0), Out); |
+ return true; |
+ case X86::NACL_RESTBPm: |
+ assert(State.PrefixSaved == 0); |
+ EmitREST(STI, Inst, X86::EBP, true, Out); |
+ return true; |
+ case X86::NACL_RESTBPr: |
+ case X86::NACL_RESTBPrz: |
+ assert(State.PrefixSaved == 0); |
+ EmitREST(STI, Inst, X86::EBP, false, Out); |
+ return true; |
+ case X86::NACL_RESTSPm: |
+ assert(State.PrefixSaved == 0); |
+ EmitREST(STI, Inst, X86::ESP, true, Out); |
+ return true; |
+ case X86::NACL_RESTSPr: |
+ case X86::NACL_RESTSPrz: |
+ assert(State.PrefixSaved == 0); |
+ EmitREST(STI, Inst, X86::ESP, false, Out); |
+ return true; |
+ } |
+ |
+ unsigned IndexOpPosition; |
+ MCInst SandboxedInst = Inst; |
+ // If we need to sandbox a memory reference and we have a saved prefix, |
+ // use a single bundle-lock/unlock for the whole sequence of |
+ // added_truncating_inst + prefix + mem_ref_inst. |
+ if (SandboxMemoryRef(&SandboxedInst, &IndexOpPosition)) { |
+ unsigned PrefixLocal = State.PrefixSaved; |
+ State.PrefixSaved = 0; |
+ |
+ if (PrefixLocal || !FlagUseZeroBasedSandbox) |
+ Out.EmitBundleLock(false); |
+ |
+ HandleMemoryRefTruncation(STI, &SandboxedInst, IndexOpPosition, Out); |
+ ShortenMemoryRef(&SandboxedInst, IndexOpPosition); |
+ |
+ if (PrefixLocal) |
+ EmitPrefix(STI, PrefixLocal, Out, State); |
+ Out.EmitInstruction(SandboxedInst, STI); |
+ |
+ if (PrefixLocal || !FlagUseZeroBasedSandbox) |
+ Out.EmitBundleUnlock(); |
+ return true; |
+ } |
+ |
+ // If the special case above doesn't apply, but there is still a saved prefix, |
+ // then the saved prefix should be bundled-locked with Inst, so that it cannot |
+ // be separated by bundle padding. |
+ if (State.PrefixSaved) { |
+ unsigned PrefixLocal = State.PrefixSaved; |
+ State.PrefixSaved = 0; |
+ Out.EmitBundleLock(false); |
+ EmitPrefix(STI, PrefixLocal, Out, State); |
+ Out.EmitInstruction(Inst, STI); |
+ Out.EmitBundleUnlock(); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+} // namespace llvm |
+ |
+ |
+ |
+ |
+// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
+// |
+// This is an exact copy of getX86SubSuperRegister from X86RegisterInfo.h |
+// We cannot use the original because it is part of libLLVMX86CodeGen, |
+// which cannot be a dependency of this module (libLLVMX86Desc). |
+// |
+// However, in all likelyhood, the real getX86SubSuperRegister will |
+// eventually be moved to MCTargetDesc, and then this copy can be |
+// removed. |
+ |
+namespace { |
+unsigned getX86SubSuperRegister_(unsigned Reg, EVT VT, bool High) { |
+ switch (VT.getSimpleVT().SimpleTy) { |
+ default: return Reg; |
+ case MVT::i8: |
+ if (High) { |
+ switch (Reg) { |
+ default: return 0; |
+ case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: |
+ return X86::AH; |
+ case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: |
+ return X86::DH; |
+ case X86::CH: case X86::CL: case X86::CX: case X86::ECX: case X86::RCX: |
+ return X86::CH; |
+ case X86::BH: case X86::BL: case X86::BX: case X86::EBX: case X86::RBX: |
+ return X86::BH; |
+ } |
+ } else { |
+ switch (Reg) { |
+ default: return 0; |
+ case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: |
+ return X86::AL; |
+ case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: |
+ return X86::DL; |
+ case X86::CH: case X86::CL: case X86::CX: case X86::ECX: case X86::RCX: |
+ return X86::CL; |
+ case X86::BH: case X86::BL: case X86::BX: case X86::EBX: case X86::RBX: |
+ return X86::BL; |
+ case X86::SIL: case X86::SI: case X86::ESI: case X86::RSI: |
+ return X86::SIL; |
+ case X86::DIL: case X86::DI: case X86::EDI: case X86::RDI: |
+ return X86::DIL; |
+ case X86::BPL: case X86::BP: case X86::EBP: case X86::RBP: |
+ return X86::BPL; |
+ case X86::SPL: case X86::SP: case X86::ESP: case X86::RSP: |
+ return X86::SPL; |
+ case X86::R8B: case X86::R8W: case X86::R8D: case X86::R8: |
+ return X86::R8B; |
+ case X86::R9B: case X86::R9W: case X86::R9D: case X86::R9: |
+ return X86::R9B; |
+ case X86::R10B: case X86::R10W: case X86::R10D: case X86::R10: |
+ return X86::R10B; |
+ case X86::R11B: case X86::R11W: case X86::R11D: case X86::R11: |
+ return X86::R11B; |
+ case X86::R12B: case X86::R12W: case X86::R12D: case X86::R12: |
+ return X86::R12B; |
+ case X86::R13B: case X86::R13W: case X86::R13D: case X86::R13: |
+ return X86::R13B; |
+ case X86::R14B: case X86::R14W: case X86::R14D: case X86::R14: |
+ return X86::R14B; |
+ case X86::R15B: case X86::R15W: case X86::R15D: case X86::R15: |
+ return X86::R15B; |
+ } |
+ } |
+ case MVT::i16: |
+ switch (Reg) { |
+ default: return Reg; |
+ case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: |
+ return X86::AX; |
+ case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: |
+ return X86::DX; |
+ case X86::CH: case X86::CL: case X86::CX: case X86::ECX: case X86::RCX: |
+ return X86::CX; |
+ case X86::BH: case X86::BL: case X86::BX: case X86::EBX: case X86::RBX: |
+ return X86::BX; |
+ case X86::SIL: case X86::SI: case X86::ESI: case X86::RSI: |
+ return X86::SI; |
+ case X86::DIL: case X86::DI: case X86::EDI: case X86::RDI: |
+ return X86::DI; |
+ case X86::BPL: case X86::BP: case X86::EBP: case X86::RBP: |
+ return X86::BP; |
+ case X86::SPL: case X86::SP: case X86::ESP: case X86::RSP: |
+ return X86::SP; |
+ case X86::R8B: case X86::R8W: case X86::R8D: case X86::R8: |
+ return X86::R8W; |
+ case X86::R9B: case X86::R9W: case X86::R9D: case X86::R9: |
+ return X86::R9W; |
+ case X86::R10B: case X86::R10W: case X86::R10D: case X86::R10: |
+ return X86::R10W; |
+ case X86::R11B: case X86::R11W: case X86::R11D: case X86::R11: |
+ return X86::R11W; |
+ case X86::R12B: case X86::R12W: case X86::R12D: case X86::R12: |
+ return X86::R12W; |
+ case X86::R13B: case X86::R13W: case X86::R13D: case X86::R13: |
+ return X86::R13W; |
+ case X86::R14B: case X86::R14W: case X86::R14D: case X86::R14: |
+ return X86::R14W; |
+ case X86::R15B: case X86::R15W: case X86::R15D: case X86::R15: |
+ return X86::R15W; |
+ } |
+ case MVT::i32: |
+ switch (Reg) { |
+ default: return Reg; |
+ case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: |
+ return X86::EAX; |
+ case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: |
+ return X86::EDX; |
+ case X86::CH: case X86::CL: case X86::CX: case X86::ECX: case X86::RCX: |
+ return X86::ECX; |
+ case X86::BH: case X86::BL: case X86::BX: case X86::EBX: case X86::RBX: |
+ return X86::EBX; |
+ case X86::SIL: case X86::SI: case X86::ESI: case X86::RSI: |
+ return X86::ESI; |
+ case X86::DIL: case X86::DI: case X86::EDI: case X86::RDI: |
+ return X86::EDI; |
+ case X86::BPL: case X86::BP: case X86::EBP: case X86::RBP: |
+ return X86::EBP; |
+ case X86::SPL: case X86::SP: case X86::ESP: case X86::RSP: |
+ return X86::ESP; |
+ case X86::R8B: case X86::R8W: case X86::R8D: case X86::R8: |
+ return X86::R8D; |
+ case X86::R9B: case X86::R9W: case X86::R9D: case X86::R9: |
+ return X86::R9D; |
+ case X86::R10B: case X86::R10W: case X86::R10D: case X86::R10: |
+ return X86::R10D; |
+ case X86::R11B: case X86::R11W: case X86::R11D: case X86::R11: |
+ return X86::R11D; |
+ case X86::R12B: case X86::R12W: case X86::R12D: case X86::R12: |
+ return X86::R12D; |
+ case X86::R13B: case X86::R13W: case X86::R13D: case X86::R13: |
+ return X86::R13D; |
+ case X86::R14B: case X86::R14W: case X86::R14D: case X86::R14: |
+ return X86::R14D; |
+ case X86::R15B: case X86::R15W: case X86::R15D: case X86::R15: |
+ return X86::R15D; |
+ } |
+ case MVT::i64: |
+ switch (Reg) { |
+ default: return Reg; |
+ case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: |
+ return X86::RAX; |
+ case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: |
+ return X86::RDX; |
+ case X86::CH: case X86::CL: case X86::CX: case X86::ECX: case X86::RCX: |
+ return X86::RCX; |
+ case X86::BH: case X86::BL: case X86::BX: case X86::EBX: case X86::RBX: |
+ return X86::RBX; |
+ case X86::SIL: case X86::SI: case X86::ESI: case X86::RSI: |
+ return X86::RSI; |
+ case X86::DIL: case X86::DI: case X86::EDI: case X86::RDI: |
+ return X86::RDI; |
+ case X86::BPL: case X86::BP: case X86::EBP: case X86::RBP: |
+ return X86::RBP; |
+ case X86::SPL: case X86::SP: case X86::ESP: case X86::RSP: |
+ return X86::RSP; |
+ 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; |
+ case X86::R12B: case X86::R12W: case X86::R12D: case X86::R12: |
+ return X86::R12; |
+ case X86::R13B: case X86::R13W: case X86::R13D: case X86::R13: |
+ return X86::R13; |
+ case X86::R14B: case X86::R14W: case X86::R14D: case X86::R14: |
+ return X86::R14; |
+ case X86::R15B: case X86::R15W: case X86::R15D: case X86::R15: |
+ return X86::R15; |
+ } |
+ } |
+ |
+ return Reg; |
+} |
+ |
+// This is a copy of DemoteRegTo32 from X86NaClRewritePass.cpp. |
+// We cannot use the original because it uses part of libLLVMX86CodeGen, |
+// which cannot be a dependency of this module (libLLVMX86Desc). |
+// Note that this function calls getX86SubSuperRegister_, which is |
+// also a copied function for the same reason. |
+ |
+unsigned DemoteRegTo32_(unsigned RegIn) { |
+ if (RegIn == 0) |
+ return 0; |
+ unsigned RegOut = getX86SubSuperRegister_(RegIn, MVT::i32, false); |
+ assert(RegOut != 0); |
+ return RegOut; |
+} |
+} //namespace |
+// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |