]> git.proxmox.com Git - rustc.git/blob - src/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
Imported Upstream version 1.0.0+dfsg1
[rustc.git] / src / llvm / 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 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
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 }
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
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
249 bool 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
254 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
255 raw_ostream &OS,
256 MCCodeEmitter *Emitter,
257 const MCSubtargetInfo &STI,
258 bool RelaxAll) {
259 MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter,
260 STI);
261 if (RelaxAll)
262 S->getAssembler().setRelaxAll(true);
263
264 // Set bundle-alignment as required by the NaCl ABI for the target.
265 S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
266
267 return S;
268 }
269
270 }