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