diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h | 4 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp | 111 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp | 13 |
3 files changed, 123 insertions, 5 deletions
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h index 62d67d9f3f1..90264a607af 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h @@ -17,6 +17,10 @@ namespace llvm { // Log2 of the NaCl MIPS sandbox's instruction bundle size. static const unsigned MIPS_NACL_BUNDLE_ALIGN = 4u; +bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, + bool *IsStore = NULL); +bool baseRegNeedsLoadStoreMask(unsigned Reg); + // This function creates an MCELFStreamer for Mips NaCl. MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp index a442e5b31bb..3353cfef33c 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp @@ -9,8 +9,10 @@ // // This file implements MCELFStreamer for Mips NaCl. It emits .o object files // as required by NaCl's SFI sandbox. It inserts address-masking instructions -// before dangerous control-flow instructions. It aligns on bundle size all -// functions and all targets of indirect branches. +// before dangerous control-flow and memory access instructions. It inserts +// address-masking instructions after instructions that change the stack +// pointer. It ensures that the mask and the dangerous instruction are always +// emitted in the same bundle. // //===----------------------------------------------------------------------===// @@ -25,6 +27,7 @@ using namespace llvm; namespace { const unsigned IndirectBranchMaskReg = Mips::T6; +const unsigned LoadStoreStackMaskReg = Mips::T7; /// Extend the generic MCELFStreamer class so that it can mask dangerous /// instructions. @@ -42,6 +45,11 @@ private: return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET; } + bool isStackPointerFirstOperand(const MCInst &MI) { + return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() + && MI.getOperand(0).getReg() == Mips::SP); + } + void emitMask(unsigned AddrReg, unsigned MaskReg, const MCSubtargetInfo &STI) { MCInst MaskInst; @@ -63,14 +71,57 @@ private: EmitBundleUnlock(); } + // Sandbox memory access or SP change. Insert mask operation before and/or + // after the instruction. + void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx, + const MCSubtargetInfo &STI, bool MaskBefore, + bool MaskAfter) { + EmitBundleLock(false); + if (MaskBefore) { + // Sandbox memory access. + unsigned BaseReg = MI.getOperand(AddrIdx).getReg(); + emitMask(BaseReg, LoadStoreStackMaskReg, STI); + } + MCELFStreamer::EmitInstruction(MI, STI); + if (MaskAfter) { + // Sandbox SP change. + unsigned SPReg = MI.getOperand(0).getReg(); + assert((Mips::SP == SPReg) && "Unexpected stack-pointer register."); + emitMask(SPReg, LoadStoreStackMaskReg, STI); + } + EmitBundleUnlock(); + } + public: /// This function is the one used to emit instruction data into the ELF /// streamer. We override it to mask dangerous instructions. virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { - if (isIndirectJump(Inst)) + // Sandbox indirect jumps. + if (isIndirectJump(Inst)) { sandboxIndirectJump(Inst, STI); - else - MCELFStreamer::EmitInstruction(Inst, STI); + return; + } + + // Sandbox loads, stores and SP changes. + unsigned AddrIdx; + bool IsStore; + bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx, + &IsStore); + bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); + if (IsMemAccess || IsSPFirstOperand) { + bool MaskBefore = (IsMemAccess + && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) + .getReg())); + bool MaskAfter = IsSPFirstOperand && !IsStore; + if (MaskBefore || MaskAfter) + sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); + else + MCELFStreamer::EmitInstruction(Inst, STI); + return; + } + + // None of the sandboxing applies, just emit the instruction. + MCELFStreamer::EmitInstruction(Inst, STI); } }; @@ -78,6 +129,56 @@ public: namespace llvm { +bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, + bool *IsStore) { + if (IsStore) + *IsStore = false; + + switch (Opcode) { + default: + return false; + + // Load instructions with base address register in position 1. + case Mips::LB: + case Mips::LBu: + case Mips::LH: + case Mips::LHu: + case Mips::LW: + case Mips::LWC1: + case Mips::LDC1: + case Mips::LL: + case Mips::LWL: + case Mips::LWR: + *AddrIdx = 1; + return true; + + // Store instructions with base address register in position 1. + case Mips::SB: + case Mips::SH: + case Mips::SW: + case Mips::SWC1: + case Mips::SDC1: + case Mips::SWL: + case Mips::SWR: + *AddrIdx = 1; + if (IsStore) + *IsStore = true; + return true; + + // Store instructions with base address register in position 2. + case Mips::SC: + *AddrIdx = 2; + if (IsStore) + *IsStore = true; + return true; + } +} + +bool baseRegNeedsLoadStoreMask(unsigned Reg) { + // The contents of SP and thread pointer register do not require masking. + return Reg != Mips::SP && Reg != Mips::T8; +} + MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter, bool RelaxAll, diff --git a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp index 47ccbfbc426..eef9f38daf8 100644 --- a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp +++ b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "delay-slot-filler" +#include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsInstrInfo.h" #include "MipsTargetMachine.h" @@ -531,6 +532,18 @@ bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End, if (delayHasHazard(*I, RegDU, IM)) continue; + if (TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) { + // In NaCl, instructions that must be masked are forbidden in delay slots. + // We only check for loads, stores and SP changes. Calls, returns and + // branches are not checked because non-NaCl targets never put them in + // delay slots. + unsigned AddrIdx; + if ((isBasePlusOffsetMemoryAccess(I->getOpcode(), &AddrIdx) + && baseRegNeedsLoadStoreMask(I->getOperand(AddrIdx).getReg())) + || I->modifiesRegister(Mips::SP, TM.getRegisterInfo())) + continue; + } + Filler = I; return true; } |

