| //=== 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/MCExpr.h" |
| #include "llvm/MC/MCInstrInfo.h" |
| #include "llvm/MC/MCRegisterInfo.h" |
| #include "llvm/MC/MCInst.h" |
| #include "llvm/MC/MCStreamer.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/CodeGen/ValueTypes.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Debug.h" |
| |
| using namespace llvm; |
| |
| // This option makes it possible to overwrite the x86 jmp mask immediate. |
| // Setting it to -1 will effectively turn masking into a nop which will |
| // help with linking this code with non-sandboxed libs (at least for x86-32). |
| cl::opt<int> FlagSfiX86JmpMask("sfi-x86-jmp-mask", |
| cl::init(-kNaClX86InstructionBundleSize)); |
| |
| 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 EmitDirectCall(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. |
| |
| MCContext &Context = Out.getContext(); |
| |
| // Generate a label for the return address. |
| MCSymbol *RetTarget = CreateTempLabel(Context, "DirectCallRetAddr"); |
| const MCExpr *RetTargetExpr = MCSymbolRefExpr::Create(RetTarget, Context); |
| |
| // push return_addr |
| MCInst PUSHInst; |
| PUSHInst.setOpcode(X86::PUSH64i32); |
| PUSHInst.addOperand(MCOperand::CreateExpr(RetTargetExpr)); |
| Out.EmitInstruction(PUSHInst); |
| |
| // jmp target |
| MCInst JMPInst; |
| JMPInst.setOpcode(X86::JMP_4); |
| JMPInst.addOperand(Op); |
| Out.EmitInstruction(JMPInst); |
| |
| 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); |
| Out.EmitBundleUnlock(); |
| } |
| } |
| |
| static void EmitIndirectBranch(const MCOperand &Op, bool Is64Bit, bool IsCall, |
| MCStreamer &Out) { |
| const bool HideSandboxBase = (FlagHideSandboxBase && |
| Is64Bit && !FlagUseZeroBasedSandbox); |
| const int JmpMask = FlagSfiX86JmpMask; |
| 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. |
| |
| // 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); |
| Reg32 = SafeReg32; |
| } |
| } |
| const unsigned Reg64 = getX86SubSuperRegister_(Reg32, MVT::i64); |
| |
| // Explicitly push the (32-bit) return address for a NaCl64 call |
| // instruction. |
| MCSymbol *RetTarget = NULL; |
| if (IsCall && HideSandboxBase) { |
| MCContext &Context = Out.getContext(); |
| |
| // Generate a label for the return address. |
| RetTarget = CreateTempLabel(Context, "IndirectCallRetAddr"); |
| const MCExpr *RetTargetExpr = MCSymbolRefExpr::Create(RetTarget, Context); |
| |
| // push return_addr |
| MCInst PUSHInst; |
| PUSHInst.setOpcode(X86::PUSH64i32); |
| PUSHInst.addOperand(MCOperand::CreateExpr(RetTargetExpr)); |
| Out.EmitInstruction(PUSHInst); |
| } |
| |
| 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); |
| |
| 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); |
| } |
| |
| if (WillEmitCallInst) { |
| // callq *%rXX |
| MCInst CALLInst; |
| CALLInst.setOpcode(Is64Bit ? X86::CALL64r : X86::CALL32r); |
| CALLInst.addOperand(MCOperand::CreateReg(Is64Bit ? Reg64 : Reg32)); |
| Out.EmitInstruction(CALLInst); |
| } 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); |
| } |
| Out.EmitBundleUnlock(); |
| if (RetTarget) { |
| Out.EmitCodeAlignment(kNaClX86InstructionBundleSize); |
| Out.EmitLabel(RetTarget); |
| } |
| } |
| |
| static void EmitRet(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); |
| |
| 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); |
| } |
| |
| MCInst JMPInst; |
| JMPInst.setOpcode(Is64Bit ? X86::NACL_JMP64r : X86::NACL_JMP32r); |
| JMPInst.addOperand(MCOperand::CreateReg(RegTarget)); |
| Out.EmitInstruction(JMPInst); |
| } |
| |
| static void EmitTrap(bool Is64Bit, MCStreamer &Out) { |
| // Rewrite to: |
| // X86-32: mov $0, 0 |
| // X86-64: mov $0, (%r15) |
| unsigned BaseReg = Is64Bit && !FlagUseZeroBasedSandbox ? X86::R15 : 0; |
| |
| MCInst Tmp; |
| Tmp.setOpcode(X86::MOV32mi); |
| Tmp.addOperand(MCOperand::CreateReg(BaseReg)); // BaseReg |
| Tmp.addOperand(MCOperand::CreateImm(1)); // Scale |
| Tmp.addOperand(MCOperand::CreateReg(0)); // IndexReg |
| Tmp.addOperand(MCOperand::CreateImm(0)); // Offset |
| Tmp.addOperand(MCOperand::CreateReg(0)); // SegmentReg |
| Tmp.addOperand(MCOperand::CreateImm(0)); // Value |
| |
| Out.EmitInstruction(Tmp); |
| } |
| |
| // Fix a register after being truncated to 32-bits. |
| static void EmitRegFix(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); |
| } |
| } |
| |
| static void EmitSPArith(unsigned Opc, const MCOperand &ImmOp, |
| MCStreamer &Out) { |
| Out.EmitBundleLock(false); |
| |
| MCInst Tmp; |
| Tmp.setOpcode(Opc); |
| Tmp.addOperand(MCOperand::CreateReg(X86::RSP)); |
| Tmp.addOperand(MCOperand::CreateReg(X86::RSP)); |
| Tmp.addOperand(ImmOp); |
| Out.EmitInstruction(Tmp); |
| |
| EmitRegFix(X86::RSP, Out); |
| Out.EmitBundleUnlock(); |
| } |
| |
| static void EmitSPAdj(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); |
| |
| EmitRegFix(X86::RSP, Out); |
| Out.EmitBundleUnlock(); |
| } |
| |
| static void EmitPrefix(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); |
| |
| assert(State.PrefixSaved == 0); |
| assert(State.PrefixPass == false); |
| } |
| |
| static void EmitMoveRegReg(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); |
| } |
| |
| static void EmitRegTruncate(unsigned Reg64, MCStreamer &Out) { |
| unsigned Reg32 = getX86SubSuperRegister_(Reg64, MVT::i32); |
| EmitMoveRegReg(false, Reg32, Reg32, Out); |
| } |
| |
| static void HandleMemoryRefTruncation(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(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(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); |
| } |
| |
| 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 EmitTLSAddr32(const MCInst &Inst, MCStreamer &Out) { |
| Out.EmitBundleLock(true); |
| |
| MCInst LeaInst; |
| LeaInst.setOpcode(X86::LEA32r); |
| LeaInst.addOperand(MCOperand::CreateReg(X86::EAX)); // DestReg |
| LeaInst.addOperand(Inst.getOperand(0)); // BaseReg |
| LeaInst.addOperand(Inst.getOperand(1)); // Scale |
| LeaInst.addOperand(Inst.getOperand(2)); // IndexReg |
| LeaInst.addOperand(Inst.getOperand(3)); // Offset |
| LeaInst.addOperand(Inst.getOperand(4)); // SegmentReg |
| Out.EmitInstruction(LeaInst); |
| |
| MCInst CALLInst; |
| CALLInst.setOpcode(X86::CALLpcrel32); |
| MCContext &context = Out.getContext(); |
| const MCSymbolRefExpr *expr = |
| MCSymbolRefExpr::Create( |
| context.GetOrCreateSymbol(StringRef("___tls_get_addr")), |
| MCSymbolRefExpr::VK_PLT, context); |
| CALLInst.addOperand(MCOperand::CreateExpr(expr)); |
| Out.EmitInstruction(CALLInst); |
| Out.EmitBundleUnlock(); |
| } |
| |
| |
| static void EmitREST(const MCInst &Inst, unsigned Reg32, |
| bool IsMem, MCStreamer &Out) { |
| unsigned Reg64 = getX86SubSuperRegister_(Reg32, MVT::i64); |
| Out.EmitBundleLock(false); |
| if (!IsMem) { |
| EmitMoveRegReg(false, Reg32, Inst.getOperand(0).getReg(), Out); |
| } else { |
| unsigned IndexOpPosition; |
| MCInst SandboxedInst = Inst; |
| if (SandboxMemoryRef(&SandboxedInst, &IndexOpPosition)) { |
| HandleMemoryRefTruncation(&SandboxedInst, IndexOpPosition, Out); |
| ShortenMemoryRef(&SandboxedInst, IndexOpPosition); |
| } |
| EmitLoad(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(Reg64, Out); |
| Out.EmitBundleUnlock(); |
| } |
| |
| |
| 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 MCInst &Inst, MCStreamer &Out, |
| X86MCNaClSFIState &State) { |
| // If we are emitting to .s, just emit all pseudo-instructions directly. |
| if (Out.hasRawTextSupport()) { |
| return false; |
| } |
| 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::NACL_TRAP32: |
| assert(State.PrefixSaved == 0); |
| EmitTrap(false, Out); |
| return true; |
| case X86::NACL_TRAP64: |
| assert(State.PrefixSaved == 0); |
| EmitTrap(true, Out); |
| return true; |
| case X86::NACL_CALL32d: |
| assert(State.PrefixSaved == 0); |
| EmitDirectCall(Inst.getOperand(0), false, Out); |
| return true; |
| case X86::NACL_CALL64d: |
| assert(State.PrefixSaved == 0); |
| EmitDirectCall(Inst.getOperand(0), true, Out); |
| return true; |
| case X86::NACL_CALL32r: |
| assert(State.PrefixSaved == 0); |
| EmitIndirectBranch(Inst.getOperand(0), false, true, Out); |
| return true; |
| case X86::NACL_CALL64r: |
| assert(State.PrefixSaved == 0); |
| EmitIndirectBranch(Inst.getOperand(0), true, true, Out); |
| return true; |
| case X86::NACL_JMP32r: |
| assert(State.PrefixSaved == 0); |
| EmitIndirectBranch(Inst.getOperand(0), false, false, Out); |
| return true; |
| case X86::NACL_TLS_addr32: |
| assert(State.PrefixSaved == 0); |
| EmitTLSAddr32(Inst, Out); |
| return true; |
| case X86::NACL_JMP64r: |
| case X86::NACL_JMP64z: |
| assert(State.PrefixSaved == 0); |
| EmitIndirectBranch(Inst.getOperand(0), true, false, Out); |
| return true; |
| case X86::NACL_RET32: |
| assert(State.PrefixSaved == 0); |
| EmitRet(NULL, false, Out); |
| return true; |
| case X86::NACL_RET64: |
| assert(State.PrefixSaved == 0); |
| EmitRet(NULL, true, Out); |
| return true; |
| case X86::NACL_RETI32: |
| assert(State.PrefixSaved == 0); |
| EmitRet(&Inst.getOperand(0), false, Out); |
| return true; |
| case X86::NACL_ASPi8: |
| assert(State.PrefixSaved == 0); |
| EmitSPArith(X86::ADD32ri8, Inst.getOperand(0), Out); |
| return true; |
| case X86::NACL_ASPi32: |
| assert(State.PrefixSaved == 0); |
| EmitSPArith(X86::ADD32ri, Inst.getOperand(0), Out); |
| return true; |
| case X86::NACL_SSPi8: |
| assert(State.PrefixSaved == 0); |
| EmitSPArith(X86::SUB32ri8, Inst.getOperand(0), Out); |
| return true; |
| case X86::NACL_SSPi32: |
| assert(State.PrefixSaved == 0); |
| EmitSPArith(X86::SUB32ri, Inst.getOperand(0), Out); |
| return true; |
| case X86::NACL_ANDSPi32: |
| assert(State.PrefixSaved == 0); |
| EmitSPArith(X86::AND32ri, Inst.getOperand(0), Out); |
| return true; |
| case X86::NACL_SPADJi32: |
| assert(State.PrefixSaved == 0); |
| EmitSPAdj(Inst.getOperand(0), Out); |
| return true; |
| case X86::NACL_RESTBPm: |
| assert(State.PrefixSaved == 0); |
| EmitREST(Inst, X86::EBP, true, Out); |
| return true; |
| case X86::NACL_RESTBPr: |
| case X86::NACL_RESTBPrz: |
| assert(State.PrefixSaved == 0); |
| EmitREST(Inst, X86::EBP, false, Out); |
| return true; |
| case X86::NACL_RESTSPm: |
| assert(State.PrefixSaved == 0); |
| EmitREST(Inst, X86::ESP, true, Out); |
| return true; |
| case X86::NACL_RESTSPr: |
| case X86::NACL_RESTSPrz: |
| assert(State.PrefixSaved == 0); |
| EmitREST(Inst, X86::ESP, false, Out); |
| return true; |
| } |
| |
| unsigned IndexOpPosition; |
| MCInst SandboxedInst = Inst; |
| if (SandboxMemoryRef(&SandboxedInst, &IndexOpPosition)) { |
| unsigned PrefixLocal = State.PrefixSaved; |
| State.PrefixSaved = 0; |
| |
| if (PrefixLocal || !FlagUseZeroBasedSandbox) |
| Out.EmitBundleLock(false); |
| |
| HandleMemoryRefTruncation(&SandboxedInst, IndexOpPosition, Out); |
| ShortenMemoryRef(&SandboxedInst, IndexOpPosition); |
| |
| if (PrefixLocal) |
| EmitPrefix(PrefixLocal, Out, State); |
| Out.EmitInstruction(SandboxedInst); |
| |
| if (PrefixLocal || !FlagUseZeroBasedSandbox) |
| Out.EmitBundleUnlock(); |
| return true; |
| } |
| |
| if (State.PrefixSaved) { |
| unsigned PrefixLocal = State.PrefixSaved; |
| State.PrefixSaved = 0; |
| EmitPrefix(PrefixLocal, Out, State); |
| } |
| 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 |
| // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |