[mips] Improve encapsulation of the .MIPS.abiflags implementation and limit scope...
[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.  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     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:
68     case Mips::BAL_BR:
69     case Mips::BLTZAL:
70     case Mips::BGEZAL:
71       return true;
72
73     case Mips::JALR:
74       *IsIndirectCall = true;
75       return true;
76     }
77   }
78
79   void emitMask(unsigned AddrReg, unsigned MaskReg,
80                 const MCSubtargetInfo &STI) {
81     MCInst MaskInst;
82     MaskInst.setOpcode(Mips::AND);
83     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
84     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
85     MaskInst.addOperand(MCOperand::CreateReg(MaskReg));
86     MipsELFStreamer::EmitInstruction(MaskInst, STI);
87   }
88
89   // Sandbox indirect branch or return instruction by inserting mask operation
90   // before it.
91   void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
92     unsigned AddrReg = MI.getOperand(0).getReg();
93
94     EmitBundleLock(false);
95     emitMask(AddrReg, IndirectBranchMaskReg, STI);
96     MipsELFStreamer::EmitInstruction(MI, STI);
97     EmitBundleUnlock();
98   }
99
100   // Sandbox memory access or SP change.  Insert mask operation before and/or
101   // after the instruction.
102   void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
103                                    const MCSubtargetInfo &STI, bool MaskBefore,
104                                    bool MaskAfter) {
105     EmitBundleLock(false);
106     if (MaskBefore) {
107       // Sandbox memory access.
108       unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
109       emitMask(BaseReg, LoadStoreStackMaskReg, STI);
110     }
111     MipsELFStreamer::EmitInstruction(MI, STI);
112     if (MaskAfter) {
113       // Sandbox SP change.
114       unsigned SPReg = MI.getOperand(0).getReg();
115       assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
116       emitMask(SPReg, LoadStoreStackMaskReg, STI);
117     }
118     EmitBundleUnlock();
119   }
120
121 public:
122   /// This function is the one used to emit instruction data into the ELF
123   /// streamer.  We override it to mask dangerous instructions.
124   void EmitInstruction(const MCInst &Inst,
125                        const MCSubtargetInfo &STI) override {
126     // Sandbox indirect jumps.
127     if (isIndirectJump(Inst)) {
128       if (PendingCall)
129         report_fatal_error("Dangerous instruction in branch delay slot!");
130       sandboxIndirectJump(Inst, STI);
131       return;
132     }
133
134     // Sandbox loads, stores and SP changes.
135     unsigned AddrIdx;
136     bool IsStore;
137     bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
138                                                     &IsStore);
139     bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
140     if (IsMemAccess || IsSPFirstOperand) {
141       bool MaskBefore = (IsMemAccess
142                          && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
143                                                           .getReg()));
144       bool MaskAfter = IsSPFirstOperand && !IsStore;
145       if (MaskBefore || MaskAfter) {
146         if (PendingCall)
147           report_fatal_error("Dangerous instruction in branch delay slot!");
148         sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
149         return;
150       }
151       // fallthrough
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
186 namespace llvm {
187
188 bool 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::LL_R6:
207   case Mips::LWL:
208   case Mips::LWR:
209     *AddrIdx = 1;
210     return true;
211
212   // Store instructions with base address register in position 1.
213   case Mips::SB:
214   case Mips::SH:
215   case Mips::SW:
216   case Mips::SWC1:
217   case Mips::SDC1:
218   case Mips::SWL:
219   case Mips::SWR:
220     *AddrIdx = 1;
221     if (IsStore)
222       *IsStore = true;
223     return true;
224
225   // Store instructions with base address register in position 2.
226   case Mips::SC:
227   case Mips::SC_R6:
228     *AddrIdx = 2;
229     if (IsStore)
230       *IsStore = true;
231     return true;
232   }
233 }
234
235 bool baseRegNeedsLoadStoreMask(unsigned Reg) {
236   // The contents of SP and thread pointer register do not require masking.
237   return Reg != Mips::SP && Reg != Mips::T8;
238 }
239
240 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
241                                          raw_ostream &OS,
242                                          MCCodeEmitter *Emitter,
243                                          const MCSubtargetInfo &STI,
244                                          bool RelaxAll, bool NoExecStack) {
245   MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter,
246                                                    STI);
247   if (RelaxAll)
248     S->getAssembler().setRelaxAll(true);
249   if (NoExecStack)
250     S->getAssembler().setNoExecStack(true);
251
252   // Set bundle-alignment as required by the NaCl ABI for the target.
253   S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
254
255   return S;
256 }
257
258 }