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