MipsNaClELFStreamer.cpp revision 36b56886974eae4f9c5ebc96befd3e7bfe5de338
1//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements MCELFStreamer for Mips NaCl. It emits .o object files 11// as required by NaCl's SFI sandbox. It inserts address-masking instructions 12// before dangerous control-flow and memory access instructions. It inserts 13// address-masking instructions after instructions that change the stack 14// pointer. It ensures that the mask and the dangerous instruction are always 15// emitted in the same bundle. It aligns call + branch delay to the bundle end, 16// so that return address is always aligned to the start of next bundle. 17// 18//===----------------------------------------------------------------------===// 19 20#define DEBUG_TYPE "mips-mc-nacl" 21 22#include "Mips.h" 23#include "MipsELFStreamer.h" 24#include "MipsMCNaCl.h" 25#include "llvm/MC/MCELFStreamer.h" 26 27using namespace llvm; 28 29namespace { 30 31const unsigned IndirectBranchMaskReg = Mips::T6; 32const unsigned LoadStoreStackMaskReg = Mips::T7; 33 34/// Extend the generic MCELFStreamer class so that it can mask dangerous 35/// instructions. 36 37class MipsNaClELFStreamer : public MipsELFStreamer { 38public: 39 MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, 40 MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) 41 : MipsELFStreamer(Context, TAB, OS, Emitter, STI), PendingCall(false) {} 42 43 ~MipsNaClELFStreamer() {} 44 45private: 46 // Whether we started the sandboxing sequence for calls. Calls are bundled 47 // with branch delays and aligned to the bundle end. 48 bool PendingCall; 49 50 bool isIndirectJump(const MCInst &MI) { 51 return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET; 52 } 53 54 bool isStackPointerFirstOperand(const MCInst &MI) { 55 return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() 56 && MI.getOperand(0).getReg() == Mips::SP); 57 } 58 59 bool isCall(unsigned Opcode, bool *IsIndirectCall) { 60 *IsIndirectCall = false; 61 62 switch (Opcode) { 63 default: 64 return false; 65 66 case Mips::JAL: 67 case Mips::BAL_BR: 68 case Mips::BLTZAL: 69 case Mips::BGEZAL: 70 return true; 71 72 case Mips::JALR: 73 *IsIndirectCall = true; 74 return true; 75 } 76 } 77 78 void emitMask(unsigned AddrReg, unsigned MaskReg, 79 const MCSubtargetInfo &STI) { 80 MCInst MaskInst; 81 MaskInst.setOpcode(Mips::AND); 82 MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); 83 MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); 84 MaskInst.addOperand(MCOperand::CreateReg(MaskReg)); 85 MipsELFStreamer::EmitInstruction(MaskInst, STI); 86 } 87 88 // Sandbox indirect branch or return instruction by inserting mask operation 89 // before it. 90 void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) { 91 unsigned AddrReg = MI.getOperand(0).getReg(); 92 93 EmitBundleLock(false); 94 emitMask(AddrReg, IndirectBranchMaskReg, STI); 95 MipsELFStreamer::EmitInstruction(MI, STI); 96 EmitBundleUnlock(); 97 } 98 99 // Sandbox memory access or SP change. Insert mask operation before and/or 100 // after the instruction. 101 void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx, 102 const MCSubtargetInfo &STI, bool MaskBefore, 103 bool MaskAfter) { 104 EmitBundleLock(false); 105 if (MaskBefore) { 106 // Sandbox memory access. 107 unsigned BaseReg = MI.getOperand(AddrIdx).getReg(); 108 emitMask(BaseReg, LoadStoreStackMaskReg, STI); 109 } 110 MipsELFStreamer::EmitInstruction(MI, STI); 111 if (MaskAfter) { 112 // Sandbox SP change. 113 unsigned SPReg = MI.getOperand(0).getReg(); 114 assert((Mips::SP == SPReg) && "Unexpected stack-pointer register."); 115 emitMask(SPReg, LoadStoreStackMaskReg, STI); 116 } 117 EmitBundleUnlock(); 118 } 119 120public: 121 /// This function is the one used to emit instruction data into the ELF 122 /// streamer. We override it to mask dangerous instructions. 123 virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { 124 // Sandbox indirect jumps. 125 if (isIndirectJump(Inst)) { 126 if (PendingCall) 127 report_fatal_error("Dangerous instruction in branch delay slot!"); 128 sandboxIndirectJump(Inst, STI); 129 return; 130 } 131 132 // Sandbox loads, stores and SP changes. 133 unsigned AddrIdx; 134 bool IsStore; 135 bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx, 136 &IsStore); 137 bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); 138 if (IsMemAccess || IsSPFirstOperand) { 139 if (PendingCall) 140 report_fatal_error("Dangerous instruction in branch delay slot!"); 141 142 bool MaskBefore = (IsMemAccess 143 && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) 144 .getReg())); 145 bool MaskAfter = IsSPFirstOperand && !IsStore; 146 if (MaskBefore || MaskAfter) 147 sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); 148 else 149 MipsELFStreamer::EmitInstruction(Inst, STI); 150 return; 151 } 152 153 // Sandbox calls by aligning call and branch delay to the bundle end. 154 // For indirect calls, emit the mask before the call. 155 bool IsIndirectCall; 156 if (isCall(Inst.getOpcode(), &IsIndirectCall)) { 157 if (PendingCall) 158 report_fatal_error("Dangerous instruction in branch delay slot!"); 159 160 // Start the sandboxing sequence by emitting call. 161 EmitBundleLock(true); 162 if (IsIndirectCall) { 163 unsigned TargetReg = Inst.getOperand(1).getReg(); 164 emitMask(TargetReg, IndirectBranchMaskReg, STI); 165 } 166 MipsELFStreamer::EmitInstruction(Inst, STI); 167 PendingCall = true; 168 return; 169 } 170 if (PendingCall) { 171 // Finish the sandboxing sequence by emitting branch delay. 172 MipsELFStreamer::EmitInstruction(Inst, STI); 173 EmitBundleUnlock(); 174 PendingCall = false; 175 return; 176 } 177 178 // None of the sandboxing applies, just emit the instruction. 179 MipsELFStreamer::EmitInstruction(Inst, STI); 180 } 181}; 182 183} // end anonymous namespace 184 185namespace llvm { 186 187bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, 188 bool *IsStore) { 189 if (IsStore) 190 *IsStore = false; 191 192 switch (Opcode) { 193 default: 194 return false; 195 196 // Load instructions with base address register in position 1. 197 case Mips::LB: 198 case Mips::LBu: 199 case Mips::LH: 200 case Mips::LHu: 201 case Mips::LW: 202 case Mips::LWC1: 203 case Mips::LDC1: 204 case Mips::LL: 205 case Mips::LWL: 206 case Mips::LWR: 207 *AddrIdx = 1; 208 return true; 209 210 // Store instructions with base address register in position 1. 211 case Mips::SB: 212 case Mips::SH: 213 case Mips::SW: 214 case Mips::SWC1: 215 case Mips::SDC1: 216 case Mips::SWL: 217 case Mips::SWR: 218 *AddrIdx = 1; 219 if (IsStore) 220 *IsStore = true; 221 return true; 222 223 // Store instructions with base address register in position 2. 224 case Mips::SC: 225 *AddrIdx = 2; 226 if (IsStore) 227 *IsStore = true; 228 return true; 229 } 230} 231 232bool baseRegNeedsLoadStoreMask(unsigned Reg) { 233 // The contents of SP and thread pointer register do not require masking. 234 return Reg != Mips::SP && Reg != Mips::T8; 235} 236 237MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, 238 raw_ostream &OS, 239 MCCodeEmitter *Emitter, 240 const MCSubtargetInfo &STI, 241 bool RelaxAll, bool NoExecStack) { 242 MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter, 243 STI); 244 if (RelaxAll) 245 S->getAssembler().setRelaxAll(true); 246 if (NoExecStack) 247 S->getAssembler().setNoExecStack(true); 248 249 // Set bundle-alignment as required by the NaCl ABI for the target. 250 S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN); 251 252 return S; 253} 254 255} 256