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