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