[mips] Implement NaCl sandboxing of loads, stores and SP changes:
[oota-llvm.git] / lib / Target / Mips / MCTargetDesc / MipsNaClELFStreamer.cpp
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.
16 //
17 //===----------------------------------------------------------------------===//
18
19 #define DEBUG_TYPE "mips-mc-nacl"
20
21 #include "Mips.h"
22 #include "MipsMCNaCl.h"
23 #include "llvm/MC/MCELFStreamer.h"
24
25 using namespace llvm;
26
27 namespace {
28
29 const unsigned IndirectBranchMaskReg = Mips::T6;
30 const unsigned LoadStoreStackMaskReg = Mips::T7;
31
32 /// Extend the generic MCELFStreamer class so that it can mask dangerous
33 /// instructions.
34
35 class MipsNaClELFStreamer : public MCELFStreamer {
36 public:
37   MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
38                       MCCodeEmitter *Emitter)
39     : MCELFStreamer(Context, TAB, OS, Emitter) {}
40
41   ~MipsNaClELFStreamer() {}
42
43 private:
44   bool isIndirectJump(const MCInst &MI) {
45     return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET;
46   }
47
48   bool isStackPointerFirstOperand(const MCInst &MI) {
49     return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
50             && MI.getOperand(0).getReg() == Mips::SP);
51   }
52
53   void emitMask(unsigned AddrReg, unsigned MaskReg,
54                 const MCSubtargetInfo &STI) {
55     MCInst MaskInst;
56     MaskInst.setOpcode(Mips::AND);
57     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
58     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
59     MaskInst.addOperand(MCOperand::CreateReg(MaskReg));
60     MCELFStreamer::EmitInstruction(MaskInst, STI);
61   }
62
63   // Sandbox indirect branch or return instruction by inserting mask operation
64   // before it.
65   void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
66     unsigned AddrReg = MI.getOperand(0).getReg();
67
68     EmitBundleLock(false);
69     emitMask(AddrReg, IndirectBranchMaskReg, STI);
70     MCELFStreamer::EmitInstruction(MI, STI);
71     EmitBundleUnlock();
72   }
73
74   // Sandbox memory access or SP change.  Insert mask operation before and/or
75   // after the instruction.
76   void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
77                                    const MCSubtargetInfo &STI, bool MaskBefore,
78                                    bool MaskAfter) {
79     EmitBundleLock(false);
80     if (MaskBefore) {
81       // Sandbox memory access.
82       unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
83       emitMask(BaseReg, LoadStoreStackMaskReg, STI);
84     }
85     MCELFStreamer::EmitInstruction(MI, STI);
86     if (MaskAfter) {
87       // Sandbox SP change.
88       unsigned SPReg = MI.getOperand(0).getReg();
89       assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
90       emitMask(SPReg, LoadStoreStackMaskReg, STI);
91     }
92     EmitBundleUnlock();
93   }
94
95 public:
96   /// This function is the one used to emit instruction data into the ELF
97   /// streamer.  We override it to mask dangerous instructions.
98   virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) {
99     // Sandbox indirect jumps.
100     if (isIndirectJump(Inst)) {
101       sandboxIndirectJump(Inst, STI);
102       return;
103     }
104
105     // Sandbox loads, stores and SP changes.
106     unsigned AddrIdx;
107     bool IsStore;
108     bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
109                                                     &IsStore);
110     bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
111     if (IsMemAccess || IsSPFirstOperand) {
112       bool MaskBefore = (IsMemAccess
113                          && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
114                                                           .getReg()));
115       bool MaskAfter = IsSPFirstOperand && !IsStore;
116       if (MaskBefore || MaskAfter)
117         sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
118       else
119         MCELFStreamer::EmitInstruction(Inst, STI);
120       return;
121     }
122
123     // None of the sandboxing applies, just emit the instruction.
124     MCELFStreamer::EmitInstruction(Inst, STI);
125   }
126 };
127
128 } // end anonymous namespace
129
130 namespace llvm {
131
132 bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
133                                   bool *IsStore) {
134   if (IsStore)
135     *IsStore = false;
136
137   switch (Opcode) {
138   default:
139     return false;
140
141   // Load instructions with base address register in position 1.
142   case Mips::LB:
143   case Mips::LBu:
144   case Mips::LH:
145   case Mips::LHu:
146   case Mips::LW:
147   case Mips::LWC1:
148   case Mips::LDC1:
149   case Mips::LL:
150   case Mips::LWL:
151   case Mips::LWR:
152     *AddrIdx = 1;
153     return true;
154
155   // Store instructions with base address register in position 1.
156   case Mips::SB:
157   case Mips::SH:
158   case Mips::SW:
159   case Mips::SWC1:
160   case Mips::SDC1:
161   case Mips::SWL:
162   case Mips::SWR:
163     *AddrIdx = 1;
164     if (IsStore)
165       *IsStore = true;
166     return true;
167
168   // Store instructions with base address register in position 2.
169   case Mips::SC:
170     *AddrIdx = 2;
171     if (IsStore)
172       *IsStore = true;
173     return true;
174   }
175 }
176
177 bool baseRegNeedsLoadStoreMask(unsigned Reg) {
178   // The contents of SP and thread pointer register do not require masking.
179   return Reg != Mips::SP && Reg != Mips::T8;
180 }
181
182 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
183                                          raw_ostream &OS,
184                                          MCCodeEmitter *Emitter, bool RelaxAll,
185                                          bool NoExecStack) {
186   MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
187   if (RelaxAll)
188     S->getAssembler().setRelaxAll(true);
189   if (NoExecStack)
190     S->getAssembler().setNoExecStack(true);
191
192   // Set bundle-alignment as required by the NaCl ABI for the target.
193   S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
194
195   return S;
196 }
197
198 }