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