1 //===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements MCELFStreamer for Mips NaCl. It emits .o object files
10 // as required by NaCl's SFI sandbox. It inserts address-masking instructions
11 // before dangerous control-flow and memory access instructions. It inserts
12 // address-masking instructions after instructions that change the stack
13 // pointer. It ensures that the mask and the dangerous instruction are always
14 // emitted in the same bundle. It aligns call + branch delay to the bundle end,
15 // so that return address is always aligned to the start of next bundle.
17 //===----------------------------------------------------------------------===//
20 #include "MipsELFStreamer.h"
21 #include "MipsMCNaCl.h"
22 #include "llvm/MC/MCAsmBackend.h"
23 #include "llvm/MC/MCAssembler.h"
24 #include "llvm/MC/MCCodeEmitter.h"
25 #include "llvm/MC/MCELFStreamer.h"
26 #include "llvm/MC/MCInst.h"
27 #include "llvm/MC/MCObjectWriter.h"
28 #include "llvm/Support/ErrorHandling.h"
33 #define DEBUG_TYPE "mips-mc-nacl"
37 const unsigned IndirectBranchMaskReg
= Mips::T6
;
38 const unsigned LoadStoreStackMaskReg
= Mips::T7
;
40 /// Extend the generic MCELFStreamer class so that it can mask dangerous
43 class MipsNaClELFStreamer
: public MipsELFStreamer
{
45 MipsNaClELFStreamer(MCContext
&Context
, std::unique_ptr
<MCAsmBackend
> TAB
,
46 std::unique_ptr
<MCObjectWriter
> OW
,
47 std::unique_ptr
<MCCodeEmitter
> Emitter
)
48 : MipsELFStreamer(Context
, std::move(TAB
), std::move(OW
),
49 std::move(Emitter
)) {}
51 ~MipsNaClELFStreamer() override
= default;
54 // Whether we started the sandboxing sequence for calls. Calls are bundled
55 // with branch delays and aligned to the bundle end.
56 bool PendingCall
= false;
58 bool isIndirectJump(const MCInst
&MI
) {
59 if (MI
.getOpcode() == Mips::JALR
) {
60 // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.
61 // JALR is an indirect branch if the link register is $0.
62 assert(MI
.getOperand(0).isReg());
63 return MI
.getOperand(0).getReg() == Mips::ZERO
;
65 return MI
.getOpcode() == Mips::JR
;
68 bool isStackPointerFirstOperand(const MCInst
&MI
) {
69 return (MI
.getNumOperands() > 0 && MI
.getOperand(0).isReg()
70 && MI
.getOperand(0).getReg() == Mips::SP
);
73 bool isCall(const MCInst
&MI
, bool *IsIndirectCall
) {
74 unsigned Opcode
= MI
.getOpcode();
76 *IsIndirectCall
= false;
90 // JALR is only a call if the link register is not $0. Otherwise it's an
92 assert(MI
.getOperand(0).isReg());
93 if (MI
.getOperand(0).getReg() == Mips::ZERO
)
96 *IsIndirectCall
= true;
101 void emitMask(unsigned AddrReg
, unsigned MaskReg
,
102 const MCSubtargetInfo
&STI
) {
104 MaskInst
.setOpcode(Mips::AND
);
105 MaskInst
.addOperand(MCOperand::createReg(AddrReg
));
106 MaskInst
.addOperand(MCOperand::createReg(AddrReg
));
107 MaskInst
.addOperand(MCOperand::createReg(MaskReg
));
108 MipsELFStreamer::EmitInstruction(MaskInst
, STI
);
111 // Sandbox indirect branch or return instruction by inserting mask operation
113 void sandboxIndirectJump(const MCInst
&MI
, const MCSubtargetInfo
&STI
) {
114 unsigned AddrReg
= MI
.getOperand(0).getReg();
116 EmitBundleLock(false);
117 emitMask(AddrReg
, IndirectBranchMaskReg
, STI
);
118 MipsELFStreamer::EmitInstruction(MI
, STI
);
122 // Sandbox memory access or SP change. Insert mask operation before and/or
123 // after the instruction.
124 void sandboxLoadStoreStackChange(const MCInst
&MI
, unsigned AddrIdx
,
125 const MCSubtargetInfo
&STI
, bool MaskBefore
,
127 EmitBundleLock(false);
129 // Sandbox memory access.
130 unsigned BaseReg
= MI
.getOperand(AddrIdx
).getReg();
131 emitMask(BaseReg
, LoadStoreStackMaskReg
, STI
);
133 MipsELFStreamer::EmitInstruction(MI
, STI
);
135 // Sandbox SP change.
136 unsigned SPReg
= MI
.getOperand(0).getReg();
137 assert((Mips::SP
== SPReg
) && "Unexpected stack-pointer register.");
138 emitMask(SPReg
, LoadStoreStackMaskReg
, STI
);
144 /// This function is the one used to emit instruction data into the ELF
145 /// streamer. We override it to mask dangerous instructions.
146 void EmitInstruction(const MCInst
&Inst
,
147 const MCSubtargetInfo
&STI
) override
{
148 // Sandbox indirect jumps.
149 if (isIndirectJump(Inst
)) {
151 report_fatal_error("Dangerous instruction in branch delay slot!");
152 sandboxIndirectJump(Inst
, STI
);
156 // Sandbox loads, stores and SP changes.
159 bool IsMemAccess
= isBasePlusOffsetMemoryAccess(Inst
.getOpcode(), &AddrIdx
,
161 bool IsSPFirstOperand
= isStackPointerFirstOperand(Inst
);
162 if (IsMemAccess
|| IsSPFirstOperand
) {
163 bool MaskBefore
= (IsMemAccess
164 && baseRegNeedsLoadStoreMask(Inst
.getOperand(AddrIdx
)
166 bool MaskAfter
= IsSPFirstOperand
&& !IsStore
;
167 if (MaskBefore
|| MaskAfter
) {
169 report_fatal_error("Dangerous instruction in branch delay slot!");
170 sandboxLoadStoreStackChange(Inst
, AddrIdx
, STI
, MaskBefore
, MaskAfter
);
176 // Sandbox calls by aligning call and branch delay to the bundle end.
177 // For indirect calls, emit the mask before the call.
179 if (isCall(Inst
, &IsIndirectCall
)) {
181 report_fatal_error("Dangerous instruction in branch delay slot!");
183 // Start the sandboxing sequence by emitting call.
184 EmitBundleLock(true);
185 if (IsIndirectCall
) {
186 unsigned TargetReg
= Inst
.getOperand(1).getReg();
187 emitMask(TargetReg
, IndirectBranchMaskReg
, STI
);
189 MipsELFStreamer::EmitInstruction(Inst
, STI
);
194 // Finish the sandboxing sequence by emitting branch delay.
195 MipsELFStreamer::EmitInstruction(Inst
, STI
);
201 // None of the sandboxing applies, just emit the instruction.
202 MipsELFStreamer::EmitInstruction(Inst
, STI
);
206 } // end anonymous namespace
210 bool isBasePlusOffsetMemoryAccess(unsigned Opcode
, unsigned *AddrIdx
,
219 // Load instructions with base address register in position 1.
234 // Store instructions with base address register in position 1.
247 // Store instructions with base address register in position 2.
257 bool baseRegNeedsLoadStoreMask(unsigned Reg
) {
258 // The contents of SP and thread pointer register do not require masking.
259 return Reg
!= Mips::SP
&& Reg
!= Mips::T8
;
262 MCELFStreamer
*createMipsNaClELFStreamer(MCContext
&Context
,
263 std::unique_ptr
<MCAsmBackend
> TAB
,
264 std::unique_ptr
<MCObjectWriter
> OW
,
265 std::unique_ptr
<MCCodeEmitter
> Emitter
,
267 MipsNaClELFStreamer
*S
= new MipsNaClELFStreamer(
268 Context
, std::move(TAB
), std::move(OW
), std::move(Emitter
));
270 S
->getAssembler().setRelaxAll(true);
272 // Set bundle-alignment as required by the NaCl ABI for the target.
273 S
->EmitBundleAlignMode(Log2(MIPS_NACL_BUNDLE_ALIGN
));
278 } // end namespace llvm