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