1 //===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
18 //===----------------------------------------------------------------------===//
20 #define DEBUG_TYPE "mips-mc-nacl"
23 #include "MipsMCNaCl.h"
24 #include "llvm/MC/MCELFStreamer.h"
30 const unsigned IndirectBranchMaskReg = Mips::T6;
31 const unsigned LoadStoreStackMaskReg = Mips::T7;
33 /// Extend the generic MCELFStreamer class so that it can mask dangerous
36 class MipsNaClELFStreamer : public MCELFStreamer {
38 MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
39 MCCodeEmitter *Emitter)
40 : MCELFStreamer(Context, TAB, OS, Emitter), PendingCall(false) {}
42 ~MipsNaClELFStreamer() {}
45 // Whether we started the sandboxing sequence for calls. Calls are bundled
46 // with branch delays and aligned to the bundle end.
49 bool isIndirectJump(const MCInst &MI) {
50 return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET;
53 bool isStackPointerFirstOperand(const MCInst &MI) {
54 return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
55 && MI.getOperand(0).getReg() == Mips::SP);
58 bool isCall(unsigned Opcode, bool *IsIndirectCall) {
59 *IsIndirectCall = false;
72 *IsIndirectCall = true;
77 void emitMask(unsigned AddrReg, unsigned MaskReg,
78 const MCSubtargetInfo &STI) {
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);
87 // Sandbox indirect branch or return instruction by inserting mask operation
89 void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
90 unsigned AddrReg = MI.getOperand(0).getReg();
92 EmitBundleLock(false);
93 emitMask(AddrReg, IndirectBranchMaskReg, STI);
94 MCELFStreamer::EmitInstruction(MI, STI);
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,
103 EmitBundleLock(false);
105 // Sandbox memory access.
106 unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
107 emitMask(BaseReg, LoadStoreStackMaskReg, STI);
109 MCELFStreamer::EmitInstruction(MI, STI);
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);
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)) {
126 report_fatal_error("Dangerous instruction in branch delay slot!");
127 sandboxIndirectJump(Inst, STI);
131 // Sandbox loads, stores and SP changes.
134 bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
136 bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
137 if (IsMemAccess || IsSPFirstOperand) {
139 report_fatal_error("Dangerous instruction in branch delay slot!");
141 bool MaskBefore = (IsMemAccess
142 && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
144 bool MaskAfter = IsSPFirstOperand && !IsStore;
145 if (MaskBefore || MaskAfter)
146 sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
148 MCELFStreamer::EmitInstruction(Inst, STI);
152 // Sandbox calls by aligning call and branch delay to the bundle end.
153 // For indirect calls, emit the mask before the call.
155 if (isCall(Inst.getOpcode(), &IsIndirectCall)) {
157 report_fatal_error("Dangerous instruction in branch delay slot!");
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);
165 MCELFStreamer::EmitInstruction(Inst, STI);
170 // Finish the sandboxing sequence by emitting branch delay.
171 MCELFStreamer::EmitInstruction(Inst, STI);
177 // None of the sandboxing applies, just emit the instruction.
178 MCELFStreamer::EmitInstruction(Inst, STI);
182 } // end anonymous namespace
186 bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
195 // Load instructions with base address register in position 1.
209 // Store instructions with base address register in position 1.
222 // Store instructions with base address register in position 2.
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;
236 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
238 MCCodeEmitter *Emitter, bool RelaxAll,
240 MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
242 S->getAssembler().setRelaxAll(true);
244 S->getAssembler().setNoExecStack(true);
246 // Set bundle-alignment as required by the NaCl ABI for the target.
247 S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);