109467b48Spatrick //===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file implements MCELFStreamer for Mips NaCl. It emits .o object files
1009467b48Spatrick // as required by NaCl's SFI sandbox. It inserts address-masking instructions
1109467b48Spatrick // before dangerous control-flow and memory access instructions. It inserts
1209467b48Spatrick // address-masking instructions after instructions that change the stack
1309467b48Spatrick // pointer. It ensures that the mask and the dangerous instruction are always
1409467b48Spatrick // emitted in the same bundle. It aligns call + branch delay to the bundle end,
1509467b48Spatrick // so that return address is always aligned to the start of next bundle.
1609467b48Spatrick //
1709467b48Spatrick //===----------------------------------------------------------------------===//
1809467b48Spatrick
1909467b48Spatrick #include "Mips.h"
2009467b48Spatrick #include "MipsELFStreamer.h"
2109467b48Spatrick #include "MipsMCNaCl.h"
2209467b48Spatrick #include "llvm/MC/MCAsmBackend.h"
2309467b48Spatrick #include "llvm/MC/MCAssembler.h"
2409467b48Spatrick #include "llvm/MC/MCCodeEmitter.h"
2509467b48Spatrick #include "llvm/MC/MCELFStreamer.h"
2609467b48Spatrick #include "llvm/MC/MCInst.h"
2709467b48Spatrick #include "llvm/MC/MCObjectWriter.h"
2809467b48Spatrick #include "llvm/Support/ErrorHandling.h"
2909467b48Spatrick #include <cassert>
3009467b48Spatrick
3109467b48Spatrick using namespace llvm;
3209467b48Spatrick
3309467b48Spatrick #define DEBUG_TYPE "mips-mc-nacl"
3409467b48Spatrick
3509467b48Spatrick namespace {
3609467b48Spatrick
3709467b48Spatrick const unsigned IndirectBranchMaskReg = Mips::T6;
3809467b48Spatrick const unsigned LoadStoreStackMaskReg = Mips::T7;
3909467b48Spatrick
4009467b48Spatrick /// Extend the generic MCELFStreamer class so that it can mask dangerous
4109467b48Spatrick /// instructions.
4209467b48Spatrick
4309467b48Spatrick class MipsNaClELFStreamer : public MipsELFStreamer {
4409467b48Spatrick public:
MipsNaClELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> TAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)4509467b48Spatrick MipsNaClELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
4609467b48Spatrick std::unique_ptr<MCObjectWriter> OW,
4709467b48Spatrick std::unique_ptr<MCCodeEmitter> Emitter)
4809467b48Spatrick : MipsELFStreamer(Context, std::move(TAB), std::move(OW),
4909467b48Spatrick std::move(Emitter)) {}
5009467b48Spatrick
5109467b48Spatrick ~MipsNaClELFStreamer() override = default;
5209467b48Spatrick
5309467b48Spatrick private:
5409467b48Spatrick // Whether we started the sandboxing sequence for calls. Calls are bundled
5509467b48Spatrick // with branch delays and aligned to the bundle end.
5609467b48Spatrick bool PendingCall = false;
5709467b48Spatrick
isIndirectJump(const MCInst & MI)5809467b48Spatrick bool isIndirectJump(const MCInst &MI) {
5909467b48Spatrick if (MI.getOpcode() == Mips::JALR) {
6009467b48Spatrick // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.
6109467b48Spatrick // JALR is an indirect branch if the link register is $0.
6209467b48Spatrick assert(MI.getOperand(0).isReg());
6309467b48Spatrick return MI.getOperand(0).getReg() == Mips::ZERO;
6409467b48Spatrick }
6509467b48Spatrick return MI.getOpcode() == Mips::JR;
6609467b48Spatrick }
6709467b48Spatrick
isStackPointerFirstOperand(const MCInst & MI)6809467b48Spatrick bool isStackPointerFirstOperand(const MCInst &MI) {
6909467b48Spatrick return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
7009467b48Spatrick && MI.getOperand(0).getReg() == Mips::SP);
7109467b48Spatrick }
7209467b48Spatrick
isCall(const MCInst & MI,bool * IsIndirectCall)7309467b48Spatrick bool isCall(const MCInst &MI, bool *IsIndirectCall) {
7409467b48Spatrick unsigned Opcode = MI.getOpcode();
7509467b48Spatrick
7609467b48Spatrick *IsIndirectCall = false;
7709467b48Spatrick
7809467b48Spatrick switch (Opcode) {
7909467b48Spatrick default:
8009467b48Spatrick return false;
8109467b48Spatrick
8209467b48Spatrick case Mips::JAL:
8309467b48Spatrick case Mips::BAL:
8409467b48Spatrick case Mips::BAL_BR:
8509467b48Spatrick case Mips::BLTZAL:
8609467b48Spatrick case Mips::BGEZAL:
8709467b48Spatrick return true;
8809467b48Spatrick
8909467b48Spatrick case Mips::JALR:
9009467b48Spatrick // JALR is only a call if the link register is not $0. Otherwise it's an
9109467b48Spatrick // indirect branch.
9209467b48Spatrick assert(MI.getOperand(0).isReg());
9309467b48Spatrick if (MI.getOperand(0).getReg() == Mips::ZERO)
9409467b48Spatrick return false;
9509467b48Spatrick
9609467b48Spatrick *IsIndirectCall = true;
9709467b48Spatrick return true;
9809467b48Spatrick }
9909467b48Spatrick }
10009467b48Spatrick
emitMask(unsigned AddrReg,unsigned MaskReg,const MCSubtargetInfo & STI)10109467b48Spatrick void emitMask(unsigned AddrReg, unsigned MaskReg,
10209467b48Spatrick const MCSubtargetInfo &STI) {
10309467b48Spatrick MCInst MaskInst;
10409467b48Spatrick MaskInst.setOpcode(Mips::AND);
10509467b48Spatrick MaskInst.addOperand(MCOperand::createReg(AddrReg));
10609467b48Spatrick MaskInst.addOperand(MCOperand::createReg(AddrReg));
10709467b48Spatrick MaskInst.addOperand(MCOperand::createReg(MaskReg));
108097a140dSpatrick MipsELFStreamer::emitInstruction(MaskInst, STI);
10909467b48Spatrick }
11009467b48Spatrick
11109467b48Spatrick // Sandbox indirect branch or return instruction by inserting mask operation
11209467b48Spatrick // before it.
sandboxIndirectJump(const MCInst & MI,const MCSubtargetInfo & STI)11309467b48Spatrick void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
11409467b48Spatrick unsigned AddrReg = MI.getOperand(0).getReg();
11509467b48Spatrick
116097a140dSpatrick emitBundleLock(false);
11709467b48Spatrick emitMask(AddrReg, IndirectBranchMaskReg, STI);
118097a140dSpatrick MipsELFStreamer::emitInstruction(MI, STI);
119097a140dSpatrick emitBundleUnlock();
12009467b48Spatrick }
12109467b48Spatrick
12209467b48Spatrick // Sandbox memory access or SP change. Insert mask operation before and/or
12309467b48Spatrick // after the instruction.
sandboxLoadStoreStackChange(const MCInst & MI,unsigned AddrIdx,const MCSubtargetInfo & STI,bool MaskBefore,bool MaskAfter)12409467b48Spatrick void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
12509467b48Spatrick const MCSubtargetInfo &STI, bool MaskBefore,
12609467b48Spatrick bool MaskAfter) {
127097a140dSpatrick emitBundleLock(false);
12809467b48Spatrick if (MaskBefore) {
12909467b48Spatrick // Sandbox memory access.
13009467b48Spatrick unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
13109467b48Spatrick emitMask(BaseReg, LoadStoreStackMaskReg, STI);
13209467b48Spatrick }
133097a140dSpatrick MipsELFStreamer::emitInstruction(MI, STI);
13409467b48Spatrick if (MaskAfter) {
13509467b48Spatrick // Sandbox SP change.
13609467b48Spatrick unsigned SPReg = MI.getOperand(0).getReg();
13709467b48Spatrick assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
13809467b48Spatrick emitMask(SPReg, LoadStoreStackMaskReg, STI);
13909467b48Spatrick }
140097a140dSpatrick emitBundleUnlock();
14109467b48Spatrick }
14209467b48Spatrick
14309467b48Spatrick public:
14409467b48Spatrick /// This function is the one used to emit instruction data into the ELF
14509467b48Spatrick /// streamer. We override it to mask dangerous instructions.
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)146097a140dSpatrick void emitInstruction(const MCInst &Inst,
14709467b48Spatrick const MCSubtargetInfo &STI) override {
14809467b48Spatrick // Sandbox indirect jumps.
14909467b48Spatrick if (isIndirectJump(Inst)) {
15009467b48Spatrick if (PendingCall)
15109467b48Spatrick report_fatal_error("Dangerous instruction in branch delay slot!");
15209467b48Spatrick sandboxIndirectJump(Inst, STI);
15309467b48Spatrick return;
15409467b48Spatrick }
15509467b48Spatrick
15609467b48Spatrick // Sandbox loads, stores and SP changes.
15709467b48Spatrick unsigned AddrIdx = 0;
15809467b48Spatrick bool IsStore = false;
15909467b48Spatrick bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
16009467b48Spatrick &IsStore);
16109467b48Spatrick bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
16209467b48Spatrick if (IsMemAccess || IsSPFirstOperand) {
16309467b48Spatrick bool MaskBefore = (IsMemAccess
16409467b48Spatrick && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
16509467b48Spatrick .getReg()));
16609467b48Spatrick bool MaskAfter = IsSPFirstOperand && !IsStore;
16709467b48Spatrick if (MaskBefore || MaskAfter) {
16809467b48Spatrick if (PendingCall)
16909467b48Spatrick report_fatal_error("Dangerous instruction in branch delay slot!");
17009467b48Spatrick sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
17109467b48Spatrick return;
17209467b48Spatrick }
17309467b48Spatrick // fallthrough
17409467b48Spatrick }
17509467b48Spatrick
17609467b48Spatrick // Sandbox calls by aligning call and branch delay to the bundle end.
17709467b48Spatrick // For indirect calls, emit the mask before the call.
17809467b48Spatrick bool IsIndirectCall;
17909467b48Spatrick if (isCall(Inst, &IsIndirectCall)) {
18009467b48Spatrick if (PendingCall)
18109467b48Spatrick report_fatal_error("Dangerous instruction in branch delay slot!");
18209467b48Spatrick
18309467b48Spatrick // Start the sandboxing sequence by emitting call.
184097a140dSpatrick emitBundleLock(true);
18509467b48Spatrick if (IsIndirectCall) {
18609467b48Spatrick unsigned TargetReg = Inst.getOperand(1).getReg();
18709467b48Spatrick emitMask(TargetReg, IndirectBranchMaskReg, STI);
18809467b48Spatrick }
189097a140dSpatrick MipsELFStreamer::emitInstruction(Inst, STI);
19009467b48Spatrick PendingCall = true;
19109467b48Spatrick return;
19209467b48Spatrick }
19309467b48Spatrick if (PendingCall) {
19409467b48Spatrick // Finish the sandboxing sequence by emitting branch delay.
195097a140dSpatrick MipsELFStreamer::emitInstruction(Inst, STI);
196097a140dSpatrick emitBundleUnlock();
19709467b48Spatrick PendingCall = false;
19809467b48Spatrick return;
19909467b48Spatrick }
20009467b48Spatrick
20109467b48Spatrick // None of the sandboxing applies, just emit the instruction.
202097a140dSpatrick MipsELFStreamer::emitInstruction(Inst, STI);
20309467b48Spatrick }
20409467b48Spatrick };
20509467b48Spatrick
20609467b48Spatrick } // end anonymous namespace
20709467b48Spatrick
20809467b48Spatrick namespace llvm {
20909467b48Spatrick
isBasePlusOffsetMemoryAccess(unsigned Opcode,unsigned * AddrIdx,bool * IsStore)21009467b48Spatrick bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
21109467b48Spatrick bool *IsStore) {
21209467b48Spatrick if (IsStore)
21309467b48Spatrick *IsStore = false;
21409467b48Spatrick
21509467b48Spatrick switch (Opcode) {
21609467b48Spatrick default:
21709467b48Spatrick return false;
21809467b48Spatrick
21909467b48Spatrick // Load instructions with base address register in position 1.
22009467b48Spatrick case Mips::LB:
22109467b48Spatrick case Mips::LBu:
22209467b48Spatrick case Mips::LH:
22309467b48Spatrick case Mips::LHu:
22409467b48Spatrick case Mips::LW:
22509467b48Spatrick case Mips::LWC1:
22609467b48Spatrick case Mips::LDC1:
22709467b48Spatrick case Mips::LL:
22809467b48Spatrick case Mips::LL_R6:
22909467b48Spatrick case Mips::LWL:
23009467b48Spatrick case Mips::LWR:
23109467b48Spatrick *AddrIdx = 1;
23209467b48Spatrick return true;
23309467b48Spatrick
23409467b48Spatrick // Store instructions with base address register in position 1.
23509467b48Spatrick case Mips::SB:
23609467b48Spatrick case Mips::SH:
23709467b48Spatrick case Mips::SW:
23809467b48Spatrick case Mips::SWC1:
23909467b48Spatrick case Mips::SDC1:
24009467b48Spatrick case Mips::SWL:
24109467b48Spatrick case Mips::SWR:
24209467b48Spatrick *AddrIdx = 1;
24309467b48Spatrick if (IsStore)
24409467b48Spatrick *IsStore = true;
24509467b48Spatrick return true;
24609467b48Spatrick
24709467b48Spatrick // Store instructions with base address register in position 2.
24809467b48Spatrick case Mips::SC:
24909467b48Spatrick case Mips::SC_R6:
25009467b48Spatrick *AddrIdx = 2;
25109467b48Spatrick if (IsStore)
25209467b48Spatrick *IsStore = true;
25309467b48Spatrick return true;
25409467b48Spatrick }
25509467b48Spatrick }
25609467b48Spatrick
baseRegNeedsLoadStoreMask(unsigned Reg)25709467b48Spatrick bool baseRegNeedsLoadStoreMask(unsigned Reg) {
25809467b48Spatrick // The contents of SP and thread pointer register do not require masking.
25909467b48Spatrick return Reg != Mips::SP && Reg != Mips::T8;
26009467b48Spatrick }
26109467b48Spatrick
createMipsNaClELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> TAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter,bool RelaxAll)26209467b48Spatrick MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context,
26309467b48Spatrick std::unique_ptr<MCAsmBackend> TAB,
26409467b48Spatrick std::unique_ptr<MCObjectWriter> OW,
26509467b48Spatrick std::unique_ptr<MCCodeEmitter> Emitter,
26609467b48Spatrick bool RelaxAll) {
26709467b48Spatrick MipsNaClELFStreamer *S = new MipsNaClELFStreamer(
26809467b48Spatrick Context, std::move(TAB), std::move(OW), std::move(Emitter));
26909467b48Spatrick if (RelaxAll)
27009467b48Spatrick S->getAssembler().setRelaxAll(true);
27109467b48Spatrick
27209467b48Spatrick // Set bundle-alignment as required by the NaCl ABI for the target.
273*d415bd75Srobert S->emitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
27409467b48Spatrick
27509467b48Spatrick return S;
27609467b48Spatrick }
27709467b48Spatrick
27809467b48Spatrick } // end namespace llvm
279