LLVM API Documentation

MipsNaClELFStreamer.cpp
Go to the documentation of this file.
00001 //===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements MCELFStreamer for Mips NaCl.  It emits .o object files
00011 // as required by NaCl's SFI sandbox.  It inserts address-masking instructions
00012 // before dangerous control-flow and memory access instructions.  It inserts
00013 // address-masking instructions after instructions that change the stack
00014 // pointer.  It ensures that the mask and the dangerous instruction are always
00015 // emitted in the same bundle.  It aligns call + branch delay to the bundle end,
00016 // so that return address is always aligned to the start of next bundle.
00017 //
00018 //===----------------------------------------------------------------------===//
00019 
00020 #include "Mips.h"
00021 #include "MipsELFStreamer.h"
00022 #include "MipsMCNaCl.h"
00023 #include "llvm/MC/MCELFStreamer.h"
00024 
00025 using namespace llvm;
00026 
00027 #define DEBUG_TYPE "mips-mc-nacl"
00028 
00029 namespace {
00030 
00031 const unsigned IndirectBranchMaskReg = Mips::T6;
00032 const unsigned LoadStoreStackMaskReg = Mips::T7;
00033 
00034 /// Extend the generic MCELFStreamer class so that it can mask dangerous
00035 /// instructions.
00036 
00037 class MipsNaClELFStreamer : public MipsELFStreamer {
00038 public:
00039   MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
00040                       MCCodeEmitter *Emitter, const MCSubtargetInfo &STI)
00041     : MipsELFStreamer(Context, TAB, OS, Emitter, STI), PendingCall(false) {}
00042 
00043   ~MipsNaClELFStreamer() {}
00044 
00045 private:
00046   // Whether we started the sandboxing sequence for calls.  Calls are bundled
00047   // with branch delays and aligned to the bundle end.
00048   bool PendingCall;
00049 
00050   bool isIndirectJump(const MCInst &MI) {
00051     if (MI.getOpcode() == Mips::JALR) {
00052       // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.
00053       // JALR is an indirect branch if the link register is $0.
00054       assert(MI.getOperand(0).isReg());
00055       return MI.getOperand(0).getReg() == Mips::ZERO;
00056     }
00057     return MI.getOpcode() == Mips::JR;
00058   }
00059 
00060   bool isStackPointerFirstOperand(const MCInst &MI) {
00061     return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
00062             && MI.getOperand(0).getReg() == Mips::SP);
00063   }
00064 
00065   bool isCall(const MCInst &MI, bool *IsIndirectCall) {
00066     unsigned Opcode = MI.getOpcode();
00067 
00068     *IsIndirectCall = false;
00069 
00070     switch (Opcode) {
00071     default:
00072       return false;
00073 
00074     case Mips::JAL:
00075     case Mips::BAL:
00076     case Mips::BAL_BR:
00077     case Mips::BLTZAL:
00078     case Mips::BGEZAL:
00079       return true;
00080 
00081     case Mips::JALR:
00082       // JALR is only a call if the link register is not $0. Otherwise it's an
00083       // indirect branch.
00084       assert(MI.getOperand(0).isReg());
00085       if (MI.getOperand(0).getReg() == Mips::ZERO)
00086         return false;
00087 
00088       *IsIndirectCall = true;
00089       return true;
00090     }
00091   }
00092 
00093   void emitMask(unsigned AddrReg, unsigned MaskReg,
00094                 const MCSubtargetInfo &STI) {
00095     MCInst MaskInst;
00096     MaskInst.setOpcode(Mips::AND);
00097     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
00098     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
00099     MaskInst.addOperand(MCOperand::CreateReg(MaskReg));
00100     MipsELFStreamer::EmitInstruction(MaskInst, STI);
00101   }
00102 
00103   // Sandbox indirect branch or return instruction by inserting mask operation
00104   // before it.
00105   void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
00106     unsigned AddrReg = MI.getOperand(0).getReg();
00107 
00108     EmitBundleLock(false);
00109     emitMask(AddrReg, IndirectBranchMaskReg, STI);
00110     MipsELFStreamer::EmitInstruction(MI, STI);
00111     EmitBundleUnlock();
00112   }
00113 
00114   // Sandbox memory access or SP change.  Insert mask operation before and/or
00115   // after the instruction.
00116   void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
00117                                    const MCSubtargetInfo &STI, bool MaskBefore,
00118                                    bool MaskAfter) {
00119     EmitBundleLock(false);
00120     if (MaskBefore) {
00121       // Sandbox memory access.
00122       unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
00123       emitMask(BaseReg, LoadStoreStackMaskReg, STI);
00124     }
00125     MipsELFStreamer::EmitInstruction(MI, STI);
00126     if (MaskAfter) {
00127       // Sandbox SP change.
00128       unsigned SPReg = MI.getOperand(0).getReg();
00129       assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
00130       emitMask(SPReg, LoadStoreStackMaskReg, STI);
00131     }
00132     EmitBundleUnlock();
00133   }
00134 
00135 public:
00136   /// This function is the one used to emit instruction data into the ELF
00137   /// streamer.  We override it to mask dangerous instructions.
00138   void EmitInstruction(const MCInst &Inst,
00139                        const MCSubtargetInfo &STI) override {
00140     // Sandbox indirect jumps.
00141     if (isIndirectJump(Inst)) {
00142       if (PendingCall)
00143         report_fatal_error("Dangerous instruction in branch delay slot!");
00144       sandboxIndirectJump(Inst, STI);
00145       return;
00146     }
00147 
00148     // Sandbox loads, stores and SP changes.
00149     unsigned AddrIdx;
00150     bool IsStore;
00151     bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
00152                                                     &IsStore);
00153     bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
00154     if (IsMemAccess || IsSPFirstOperand) {
00155       bool MaskBefore = (IsMemAccess
00156                          && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
00157                                                           .getReg()));
00158       bool MaskAfter = IsSPFirstOperand && !IsStore;
00159       if (MaskBefore || MaskAfter) {
00160         if (PendingCall)
00161           report_fatal_error("Dangerous instruction in branch delay slot!");
00162         sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
00163         return;
00164       }
00165       // fallthrough
00166     }
00167 
00168     // Sandbox calls by aligning call and branch delay to the bundle end.
00169     // For indirect calls, emit the mask before the call.
00170     bool IsIndirectCall;
00171     if (isCall(Inst, &IsIndirectCall)) {
00172       if (PendingCall)
00173         report_fatal_error("Dangerous instruction in branch delay slot!");
00174 
00175       // Start the sandboxing sequence by emitting call.
00176       EmitBundleLock(true);
00177       if (IsIndirectCall) {
00178         unsigned TargetReg = Inst.getOperand(1).getReg();
00179         emitMask(TargetReg, IndirectBranchMaskReg, STI);
00180       }
00181       MipsELFStreamer::EmitInstruction(Inst, STI);
00182       PendingCall = true;
00183       return;
00184     }
00185     if (PendingCall) {
00186       // Finish the sandboxing sequence by emitting branch delay.
00187       MipsELFStreamer::EmitInstruction(Inst, STI);
00188       EmitBundleUnlock();
00189       PendingCall = false;
00190       return;
00191     }
00192 
00193     // None of the sandboxing applies, just emit the instruction.
00194     MipsELFStreamer::EmitInstruction(Inst, STI);
00195   }
00196 };
00197 
00198 } // end anonymous namespace
00199 
00200 namespace llvm {
00201 
00202 bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
00203                                   bool *IsStore) {
00204   if (IsStore)
00205     *IsStore = false;
00206 
00207   switch (Opcode) {
00208   default:
00209     return false;
00210 
00211   // Load instructions with base address register in position 1.
00212   case Mips::LB:
00213   case Mips::LBu:
00214   case Mips::LH:
00215   case Mips::LHu:
00216   case Mips::LW:
00217   case Mips::LWC1:
00218   case Mips::LDC1:
00219   case Mips::LL:
00220   case Mips::LL_R6:
00221   case Mips::LWL:
00222   case Mips::LWR:
00223     *AddrIdx = 1;
00224     return true;
00225 
00226   // Store instructions with base address register in position 1.
00227   case Mips::SB:
00228   case Mips::SH:
00229   case Mips::SW:
00230   case Mips::SWC1:
00231   case Mips::SDC1:
00232   case Mips::SWL:
00233   case Mips::SWR:
00234     *AddrIdx = 1;
00235     if (IsStore)
00236       *IsStore = true;
00237     return true;
00238 
00239   // Store instructions with base address register in position 2.
00240   case Mips::SC:
00241   case Mips::SC_R6:
00242     *AddrIdx = 2;
00243     if (IsStore)
00244       *IsStore = true;
00245     return true;
00246   }
00247 }
00248 
00249 bool baseRegNeedsLoadStoreMask(unsigned Reg) {
00250   // The contents of SP and thread pointer register do not require masking.
00251   return Reg != Mips::SP && Reg != Mips::T8;
00252 }
00253 
00254 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
00255                                          raw_ostream &OS,
00256                                          MCCodeEmitter *Emitter,
00257                                          const MCSubtargetInfo &STI,
00258                                          bool RelaxAll, bool NoExecStack) {
00259   MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter,
00260                                                    STI);
00261   if (RelaxAll)
00262     S->getAssembler().setRelaxAll(true);
00263   if (NoExecStack)
00264     S->getAssembler().setNoExecStack(true);
00265 
00266   // Set bundle-alignment as required by the NaCl ABI for the target.
00267   S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
00268 
00269   return S;
00270 }
00271 
00272 }