Reorder Mips/MCTargetDesc/CMakeLists.txt.
[oota-llvm.git] / 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 instructions.  It aligns on bundle size all
13 // functions and all targets of indirect branches.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #define DEBUG_TYPE "mips-mc-nacl"
18
19 #include "Mips.h"
20 #include "MipsMCNaCl.h"
21 #include "llvm/MC/MCELFStreamer.h"
22
23 using namespace llvm;
24
25 namespace {
26
27 const unsigned IndirectBranchMaskReg = Mips::T6;
28
29 /// Extend the generic MCELFStreamer class so that it can mask dangerous
30 /// instructions.
31
32 class MipsNaClELFStreamer : public MCELFStreamer {
33 public:
34   MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
35                       MCCodeEmitter *Emitter)
36     : MCELFStreamer(Context, TAB, OS, Emitter) {}
37
38   ~MipsNaClELFStreamer() {}
39
40 private:
41   bool isIndirectJump(const MCInst &MI) {
42     return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET;
43   }
44
45   void emitMask(unsigned AddrReg, unsigned MaskReg,
46                 const MCSubtargetInfo &STI) {
47     MCInst MaskInst;
48     MaskInst.setOpcode(Mips::AND);
49     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
50     MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
51     MaskInst.addOperand(MCOperand::CreateReg(MaskReg));
52     MCELFStreamer::EmitInstruction(MaskInst, STI);
53   }
54
55   // Sandbox indirect branch or return instruction by inserting mask operation
56   // before it.
57   void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
58     unsigned AddrReg = MI.getOperand(0).getReg();
59
60     EmitBundleLock(false);
61     emitMask(AddrReg, IndirectBranchMaskReg, STI);
62     MCELFStreamer::EmitInstruction(MI, STI);
63     EmitBundleUnlock();
64   }
65
66 public:
67   /// This function is the one used to emit instruction data into the ELF
68   /// streamer.  We override it to mask dangerous instructions.
69   virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) {
70     if (isIndirectJump(Inst))
71       sandboxIndirectJump(Inst, STI);
72     else
73       MCELFStreamer::EmitInstruction(Inst, STI);
74   }
75 };
76
77 } // end anonymous namespace
78
79 namespace llvm {
80
81 MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
82                                          raw_ostream &OS,
83                                          MCCodeEmitter *Emitter, bool RelaxAll,
84                                          bool NoExecStack) {
85   MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
86   if (RelaxAll)
87     S->getAssembler().setRelaxAll(true);
88   if (NoExecStack)
89     S->getAssembler().setNoExecStack(true);
90
91   // Set bundle-alignment as required by the NaCl ABI for the target.
92   S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
93
94   return S;
95 }
96
97 }