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
25using namespace llvm;
26
27#define DEBUG_TYPE "mips-mc-nacl"
28
29namespace {
30
31const unsigned IndirectBranchMaskReg = Mips::T6;
32const unsigned LoadStoreStackMaskReg = Mips::T7;
33
34/// Extend the generic MCELFStreamer class so that it can mask dangerous
35/// instructions.
36
37class MipsNaClELFStreamer : public MipsELFStreamer {
38public:
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
45private:
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
135public:
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
200namespace llvm {
201
202bool 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
249bool 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
254MCELFStreamer *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