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 #include "Mips.h" 21 #include "MipsELFStreamer.h" 22 #include "MipsMCNaCl.h" 23 #include "llvm/MC/MCELFStreamer.h" 24 25 using namespace llvm; 26 27 #define DEBUG_TYPE "mips-mc-nacl" 28 29 namespace { 30 31 const unsigned IndirectBranchMaskReg = Mips::T6; 32 const unsigned LoadStoreStackMaskReg = Mips::T7; 33 34 /// Extend the generic MCELFStreamer class so that it can mask dangerous 35 /// instructions. 36 37 class MipsNaClELFStreamer : public MipsELFStreamer { 38 public: 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 45 private: 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 if (MI.getOpcode() == Mips::JALR) { 52 // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead. 53 // JALR is an indirect branch if the link register is $0. 54 assert(MI.getOperand(0).isReg()); 55 return MI.getOperand(0).getReg() == Mips::ZERO; 56 } 57 return MI.getOpcode() == Mips::JR; 58 } 59 60 bool isStackPointerFirstOperand(const MCInst &MI) { 61 return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() 62 && MI.getOperand(0).getReg() == Mips::SP); 63 } 64 65 bool isCall(const MCInst &MI, bool *IsIndirectCall) { 66 unsigned Opcode = MI.getOpcode(); 67 68 *IsIndirectCall = false; 69 70 switch (Opcode) { 71 default: 72 return false; 73 74 case Mips::JAL: 75 case Mips::BAL: 76 case Mips::BAL_BR: 77 case Mips::BLTZAL: 78 case Mips::BGEZAL: 79 return true; 80 81 case Mips::JALR: 82 // JALR is only a call if the link register is not $0. Otherwise it's an 83 // indirect branch. 84 assert(MI.getOperand(0).isReg()); 85 if (MI.getOperand(0).getReg() == Mips::ZERO) 86 return false; 87 88 *IsIndirectCall = true; 89 return true; 90 } 91 } 92 93 void emitMask(unsigned AddrReg, unsigned MaskReg, 94 const MCSubtargetInfo &STI) { 95 MCInst MaskInst; 96 MaskInst.setOpcode(Mips::AND); 97 MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); 98 MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); 99 MaskInst.addOperand(MCOperand::CreateReg(MaskReg)); 100 MipsELFStreamer::EmitInstruction(MaskInst, STI); 101 } 102 103 // Sandbox indirect branch or return instruction by inserting mask operation 104 // before it. 105 void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) { 106 unsigned AddrReg = MI.getOperand(0).getReg(); 107 108 EmitBundleLock(false); 109 emitMask(AddrReg, IndirectBranchMaskReg, STI); 110 MipsELFStreamer::EmitInstruction(MI, STI); 111 EmitBundleUnlock(); 112 } 113 114 // Sandbox memory access or SP change. Insert mask operation before and/or 115 // after the instruction. 116 void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx, 117 const MCSubtargetInfo &STI, bool MaskBefore, 118 bool MaskAfter) { 119 EmitBundleLock(false); 120 if (MaskBefore) { 121 // Sandbox memory access. 122 unsigned BaseReg = MI.getOperand(AddrIdx).getReg(); 123 emitMask(BaseReg, LoadStoreStackMaskReg, STI); 124 } 125 MipsELFStreamer::EmitInstruction(MI, STI); 126 if (MaskAfter) { 127 // Sandbox SP change. 128 unsigned SPReg = MI.getOperand(0).getReg(); 129 assert((Mips::SP == SPReg) && "Unexpected stack-pointer register."); 130 emitMask(SPReg, LoadStoreStackMaskReg, STI); 131 } 132 EmitBundleUnlock(); 133 } 134 135 public: 136 /// This function is the one used to emit instruction data into the ELF 137 /// streamer. We override it to mask dangerous instructions. 138 void EmitInstruction(const MCInst &Inst, 139 const MCSubtargetInfo &STI) override { 140 // Sandbox indirect jumps. 141 if (isIndirectJump(Inst)) { 142 if (PendingCall) 143 report_fatal_error("Dangerous instruction in branch delay slot!"); 144 sandboxIndirectJump(Inst, STI); 145 return; 146 } 147 148 // Sandbox loads, stores and SP changes. 149 unsigned AddrIdx; 150 bool IsStore; 151 bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx, 152 &IsStore); 153 bool IsSPFirstOperand = isStackPointerFirstOperand(Inst); 154 if (IsMemAccess || IsSPFirstOperand) { 155 bool MaskBefore = (IsMemAccess 156 && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx) 157 .getReg())); 158 bool MaskAfter = IsSPFirstOperand && !IsStore; 159 if (MaskBefore || MaskAfter) { 160 if (PendingCall) 161 report_fatal_error("Dangerous instruction in branch delay slot!"); 162 sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter); 163 return; 164 } 165 // fallthrough 166 } 167 168 // Sandbox calls by aligning call and branch delay to the bundle end. 169 // For indirect calls, emit the mask before the call. 170 bool IsIndirectCall; 171 if (isCall(Inst, &IsIndirectCall)) { 172 if (PendingCall) 173 report_fatal_error("Dangerous instruction in branch delay slot!"); 174 175 // Start the sandboxing sequence by emitting call. 176 EmitBundleLock(true); 177 if (IsIndirectCall) { 178 unsigned TargetReg = Inst.getOperand(1).getReg(); 179 emitMask(TargetReg, IndirectBranchMaskReg, STI); 180 } 181 MipsELFStreamer::EmitInstruction(Inst, STI); 182 PendingCall = true; 183 return; 184 } 185 if (PendingCall) { 186 // Finish the sandboxing sequence by emitting branch delay. 187 MipsELFStreamer::EmitInstruction(Inst, STI); 188 EmitBundleUnlock(); 189 PendingCall = false; 190 return; 191 } 192 193 // None of the sandboxing applies, just emit the instruction. 194 MipsELFStreamer::EmitInstruction(Inst, STI); 195 } 196 }; 197 198 } // end anonymous namespace 199 200 namespace llvm { 201 202 bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, 203 bool *IsStore) { 204 if (IsStore) 205 *IsStore = false; 206 207 switch (Opcode) { 208 default: 209 return false; 210 211 // Load instructions with base address register in position 1. 212 case Mips::LB: 213 case Mips::LBu: 214 case Mips::LH: 215 case Mips::LHu: 216 case Mips::LW: 217 case Mips::LWC1: 218 case Mips::LDC1: 219 case Mips::LL: 220 case Mips::LL_R6: 221 case Mips::LWL: 222 case Mips::LWR: 223 *AddrIdx = 1; 224 return true; 225 226 // Store instructions with base address register in position 1. 227 case Mips::SB: 228 case Mips::SH: 229 case Mips::SW: 230 case Mips::SWC1: 231 case Mips::SDC1: 232 case Mips::SWL: 233 case Mips::SWR: 234 *AddrIdx = 1; 235 if (IsStore) 236 *IsStore = true; 237 return true; 238 239 // Store instructions with base address register in position 2. 240 case Mips::SC: 241 case Mips::SC_R6: 242 *AddrIdx = 2; 243 if (IsStore) 244 *IsStore = true; 245 return true; 246 } 247 } 248 249 bool baseRegNeedsLoadStoreMask(unsigned Reg) { 250 // The contents of SP and thread pointer register do not require masking. 251 return Reg != Mips::SP && Reg != Mips::T8; 252 } 253 254 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, 255 raw_ostream &OS, 256 MCCodeEmitter *Emitter, 257 const MCSubtargetInfo &STI, 258 bool RelaxAll, bool NoExecStack) { 259 MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter, 260 STI); 261 if (RelaxAll) 262 S->getAssembler().setRelaxAll(true); 263 if (NoExecStack) 264 S->getAssembler().setNoExecStack(true); 265 266 // Set bundle-alignment as required by the NaCl ABI for the target. 267 S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN); 268 269 return S; 270 } 271 272 } 273