]>
git.proxmox.com Git - rustc.git/blob - src/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
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 //===----------------------------------------------------------------------===//
21 #include "MipsELFStreamer.h"
22 #include "MipsMCNaCl.h"
23 #include "llvm/MC/MCELFStreamer.h"
27 #define DEBUG_TYPE "mips-mc-nacl"
31 const unsigned IndirectBranchMaskReg
= Mips::T6
;
32 const unsigned LoadStoreStackMaskReg
= Mips::T7
;
34 /// Extend the generic MCELFStreamer class so that it can mask dangerous
37 class MipsNaClELFStreamer
: public MipsELFStreamer
{
39 MipsNaClELFStreamer(MCContext
&Context
, MCAsmBackend
&TAB
, raw_ostream
&OS
,
40 MCCodeEmitter
*Emitter
, const MCSubtargetInfo
&STI
)
41 : MipsELFStreamer(Context
, TAB
, OS
, Emitter
, STI
), PendingCall(false) {}
43 ~MipsNaClELFStreamer() {}
46 // Whether we started the sandboxing sequence for calls. Calls are bundled
47 // with branch delays and aligned to the bundle end.
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
;
57 return MI
.getOpcode() == Mips::JR
;
60 bool isStackPointerFirstOperand(const MCInst
&MI
) {
61 return (MI
.getNumOperands() > 0 && MI
.getOperand(0).isReg()
62 && MI
.getOperand(0).getReg() == Mips::SP
);
65 bool isCall(const MCInst
&MI
, bool *IsIndirectCall
) {
66 unsigned Opcode
= MI
.getOpcode();
68 *IsIndirectCall
= false;
82 // JALR is only a call if the link register is not $0. Otherwise it's an
84 assert(MI
.getOperand(0).isReg());
85 if (MI
.getOperand(0).getReg() == Mips::ZERO
)
88 *IsIndirectCall
= true;
93 void emitMask(unsigned AddrReg
, unsigned MaskReg
,
94 const MCSubtargetInfo
&STI
) {
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
);
103 // Sandbox indirect branch or return instruction by inserting mask operation
105 void sandboxIndirectJump(const MCInst
&MI
, const MCSubtargetInfo
&STI
) {
106 unsigned AddrReg
= MI
.getOperand(0).getReg();
108 EmitBundleLock(false);
109 emitMask(AddrReg
, IndirectBranchMaskReg
, STI
);
110 MipsELFStreamer::EmitInstruction(MI
, STI
);
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
,
119 EmitBundleLock(false);
121 // Sandbox memory access.
122 unsigned BaseReg
= MI
.getOperand(AddrIdx
).getReg();
123 emitMask(BaseReg
, LoadStoreStackMaskReg
, STI
);
125 MipsELFStreamer::EmitInstruction(MI
, STI
);
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
);
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
)) {
143 report_fatal_error("Dangerous instruction in branch delay slot!");
144 sandboxIndirectJump(Inst
, STI
);
148 // Sandbox loads, stores and SP changes.
151 bool IsMemAccess
= isBasePlusOffsetMemoryAccess(Inst
.getOpcode(), &AddrIdx
,
153 bool IsSPFirstOperand
= isStackPointerFirstOperand(Inst
);
154 if (IsMemAccess
|| IsSPFirstOperand
) {
155 bool MaskBefore
= (IsMemAccess
156 && baseRegNeedsLoadStoreMask(Inst
.getOperand(AddrIdx
)
158 bool MaskAfter
= IsSPFirstOperand
&& !IsStore
;
159 if (MaskBefore
|| MaskAfter
) {
161 report_fatal_error("Dangerous instruction in branch delay slot!");
162 sandboxLoadStoreStackChange(Inst
, AddrIdx
, STI
, MaskBefore
, MaskAfter
);
168 // Sandbox calls by aligning call and branch delay to the bundle end.
169 // For indirect calls, emit the mask before the call.
171 if (isCall(Inst
, &IsIndirectCall
)) {
173 report_fatal_error("Dangerous instruction in branch delay slot!");
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
);
181 MipsELFStreamer::EmitInstruction(Inst
, STI
);
186 // Finish the sandboxing sequence by emitting branch delay.
187 MipsELFStreamer::EmitInstruction(Inst
, STI
);
193 // None of the sandboxing applies, just emit the instruction.
194 MipsELFStreamer::EmitInstruction(Inst
, STI
);
198 } // end anonymous namespace
202 bool isBasePlusOffsetMemoryAccess(unsigned Opcode
, unsigned *AddrIdx
,
211 // Load instructions with base address register in position 1.
226 // Store instructions with base address register in position 1.
239 // Store instructions with base address register in position 2.
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
;
254 MCELFStreamer
*createMipsNaClELFStreamer(MCContext
&Context
, MCAsmBackend
&TAB
,
256 MCCodeEmitter
*Emitter
,
257 const MCSubtargetInfo
&STI
,
259 MipsNaClELFStreamer
*S
= new MipsNaClELFStreamer(Context
, TAB
, OS
, Emitter
,
262 S
->getAssembler().setRelaxAll(true);
264 // Set bundle-alignment as required by the NaCl ABI for the target.
265 S
->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN
);