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