Index: lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp @@ -31,6 +31,8 @@ const unsigned IndirectBranchMaskReg = Mips::T6; const unsigned LoadStoreStackMaskReg = Mips::T7; +static MCInst EmptyMCInst; + /// Extend the generic MCELFStreamer class so that it can mask dangerous /// instructions. @@ -38,7 +40,10 @@ public: MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) - : MipsELFStreamer(Context, TAB, OS, Emitter, STI), PendingCall(false) {} + : MipsELFStreamer(Context, TAB, OS, Emitter, STI), PendingCall(false), + HasPrevBranchMask(false), PrevBranchMask(EmptyMCInst), + HasPrevLoadStoreMask(false), PrevLoadStoreMask(EmptyMCInst), + PendingStackMask(false) {} ~MipsNaClELFStreamer() {} @@ -47,6 +52,12 @@ // with branch delays and aligned to the bundle end. bool PendingCall; + bool HasPrevBranchMask; + MCInst &PrevBranchMask; + bool HasPrevLoadStoreMask; + MCInst &PrevLoadStoreMask; + bool PendingStackMask; + bool isIndirectJump(const MCInst &MI) { if (MI.getOpcode() == Mips::JALR) { // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead. @@ -62,6 +73,26 @@ && MI.getOperand(0).getReg() == Mips::SP); } + bool isMask(const MCInst &MI, unsigned MaskReg) { + return (MI.getOpcode() == Mips::AND && + MI.getOperand(0).getReg() == MI.getOperand(1).getReg() && + MI.getOperand(2).isReg() && MI.getOperand(2).getReg() == MaskReg); + } + + bool isIndirectBranchMask(const MCInst &MI) { + return isMask(MI, IndirectBranchMaskReg); + } + + bool isLoadStoreMask(const MCInst &MI) { + return (isMask(MI, LoadStoreStackMaskReg) && + baseRegNeedsLoadStoreMask(MI.getOperand(0).getReg())); + } + + bool isStackChangeMask(const MCInst &MI) { + return (isMask(MI, LoadStoreStackMaskReg) && + MI.getOperand(0).getReg() == Mips::SP); + } + bool isCall(const MCInst &MI, bool *IsIndirectCall) { unsigned Opcode = MI.getOpcode(); @@ -104,9 +135,11 @@ // before it. void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) { unsigned AddrReg = MI.getOperand(0).getReg(); - EmitBundleLock(false); - emitMask(AddrReg, IndirectBranchMaskReg, STI); + if (HasPrevBranchMask) + MipsELFStreamer::EmitInstruction(PrevBranchMask, STI); + else + emitMask(AddrReg, IndirectBranchMaskReg, STI); MipsELFStreamer::EmitInstruction(MI, STI); EmitBundleUnlock(); } @@ -120,9 +153,13 @@ if (MaskBefore) { // Sandbox memory access. unsigned BaseReg = MI.getOperand(AddrIdx).getReg(); - emitMask(BaseReg, LoadStoreStackMaskReg, STI); + if (HasPrevLoadStoreMask) + MipsELFStreamer::EmitInstruction(PrevLoadStoreMask, STI); + else + emitMask(BaseReg, LoadStoreStackMaskReg, STI); } MipsELFStreamer::EmitInstruction(MI, STI); + if (MaskAfter) { // Sandbox SP change. unsigned SPReg = MI.getOperand(0).getReg(); @@ -141,7 +178,11 @@ if (isIndirectJump(Inst)) { if (PendingCall) report_fatal_error("Dangerous instruction in branch delay slot!"); + sandboxIndirectJump(Inst, STI); + HasPrevBranchMask = false; + HasPrevLoadStoreMask = false; + PendingStackMask = false; return; } @@ -150,7 +191,8 @@ bool IsStore; bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx, &IsStore); - bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); + bool IsSPFirstOperand = (isStackPointerFirstOperand(Inst) && + !isStackChangeMask(Inst)); if (IsMemAccess || IsSPFirstOperand) { bool MaskBefore = (IsMemAccess && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) @@ -159,7 +201,11 @@ if (MaskBefore || MaskAfter) { if (PendingCall) report_fatal_error("Dangerous instruction in branch delay slot!"); + sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); + HasPrevBranchMask = false; + HasPrevLoadStoreMask = false; + PendingStackMask = MaskAfter; return; } // fallthrough @@ -176,10 +222,16 @@ EmitBundleLock(true); if (IsIndirectCall) { unsigned TargetReg = Inst.getOperand(1).getReg(); - emitMask(TargetReg, IndirectBranchMaskReg, STI); + if (HasPrevBranchMask) + MipsELFStreamer::EmitInstruction(PrevBranchMask, STI); + else + emitMask(TargetReg, IndirectBranchMaskReg, STI); } MipsELFStreamer::EmitInstruction(Inst, STI); PendingCall = true; + HasPrevBranchMask = false; + HasPrevLoadStoreMask = false; + PendingStackMask = false; return; } if (PendingCall) { @@ -189,9 +241,28 @@ PendingCall = false; return; } + if (PendingStackMask) { + PendingStackMask = false; + if (isStackChangeMask(Inst)) + return; + } + + if (isIndirectBranchMask(Inst)) { + PrevBranchMask = Inst; + HasPrevBranchMask = true; + return; + } + if (isLoadStoreMask(Inst)) { + PrevLoadStoreMask = Inst; + HasPrevLoadStoreMask = true; + return; + } // None of the sandboxing applies, just emit the instruction. MipsELFStreamer::EmitInstruction(Inst, STI); + HasPrevBranchMask = false; + HasPrevLoadStoreMask = false; + PendingStackMask = false; } };