LLVM  3.7.0
MipsNaClELFStreamer.cpp
Go to the documentation of this file.
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,
40  raw_pwrite_stream &OS, MCCodeEmitter *Emitter)
41  : MipsELFStreamer(Context, TAB, OS, Emitter), PendingCall(false) {}
42 
43  ~MipsNaClELFStreamer() override {}
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  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);
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  }
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 
135 public:
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  }
182  PendingCall = true;
183  return;
184  }
185  if (PendingCall) {
186  // Finish the sandboxing sequence by emitting branch delay.
188  EmitBundleUnlock();
189  PendingCall = false;
190  return;
191  }
192 
193  // None of the sandboxing applies, just emit the instruction.
195  }
196 };
197 
198 } // end anonymous namespace
199 
200 namespace llvm {
201 
202 bool 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 
250  // The contents of SP and thread pointer register do not require masking.
251  return Reg != Mips::SP && Reg != Mips::T8;
252 }
253 
255  raw_pwrite_stream &OS,
256  MCCodeEmitter *Emitter,
257  bool RelaxAll) {
258  MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
259  if (RelaxAll)
260  S->getAssembler().setRelaxAll(true);
261 
262  // Set bundle-alignment as required by the NaCl ABI for the target.
263  S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
264 
265  return S;
266 }
267 
268 }
bool isReg() const
Definition: MCInst.h:56
bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, bool *IsStore=nullptr)
static bool IsIndirectCall(MachineInstr *MI)
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag=true)
Reports a serious error, calling any installed error handler.
static MCOperand createReg(unsigned Reg)
Definition: MCInst.h:111
Reg
All possible values of the reg field in the ModR/M byte.
bool baseRegNeedsLoadStoreMask(unsigned Reg)
Context object for machine code objects.
Definition: MCContext.h:48
unsigned getReg() const
Returns the register number.
Definition: MCInst.h:63
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:150
MCCodeEmitter - Generic instruction encoding interface.
Definition: MCCodeEmitter.h:23
MCELFStreamer * createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_pwrite_stream &OS, MCCodeEmitter *Emitter, bool RelaxAll)
void setOpcode(unsigned Op)
Definition: MCInst.h:158
CHAIN = SC CHAIN, Imm128 - System call.
unsigned getOpcode() const
Definition: MCInst.h:159
static const unsigned MIPS_NACL_BUNDLE_ALIGN
Definition: MipsMCNaCl.h:18
unsigned getNumOperands() const
Definition: MCInst.h:166
MCSubtargetInfo - Generic base class for all target subtargets.
An abstract base class for streams implementations that also support a pwrite operation.
Definition: raw_ostream.h:321
cl::opt< bool > RelaxAll("mc-relax-all", cl::desc("When used with filetype=obj, ""relax all fixups in the emitted object file"))
Generic interface to target specific assembler backends.
Definition: MCAsmBackend.h:34
void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override
Overriding this function allows us to add arbitrary behaviour before the Inst is actually emitted...
void addOperand(const MCOperand &Op)
Definition: MCInst.h:168
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:164