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