Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
35294 views
//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements MCELFStreamer for Mips NaCl. It emits .o object files9// as required by NaCl's SFI sandbox. It inserts address-masking instructions10// before dangerous control-flow and memory access instructions. It inserts11// address-masking instructions after instructions that change the stack12// pointer. It ensures that the mask and the dangerous instruction are always13// emitted in the same bundle. It aligns call + branch delay to the bundle end,14// so that return address is always aligned to the start of next bundle.15//16//===----------------------------------------------------------------------===//1718#include "Mips.h"19#include "MipsELFStreamer.h"20#include "MipsMCNaCl.h"21#include "llvm/MC/MCAsmBackend.h"22#include "llvm/MC/MCAssembler.h"23#include "llvm/MC/MCCodeEmitter.h"24#include "llvm/MC/MCELFStreamer.h"25#include "llvm/MC/MCInst.h"26#include "llvm/MC/MCObjectWriter.h"27#include "llvm/Support/ErrorHandling.h"28#include <cassert>2930using namespace llvm;3132#define DEBUG_TYPE "mips-mc-nacl"3334namespace {3536const unsigned IndirectBranchMaskReg = Mips::T6;37const unsigned LoadStoreStackMaskReg = Mips::T7;3839/// Extend the generic MCELFStreamer class so that it can mask dangerous40/// instructions.4142class MipsNaClELFStreamer : public MipsELFStreamer {43public:44MipsNaClELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,45std::unique_ptr<MCObjectWriter> OW,46std::unique_ptr<MCCodeEmitter> Emitter)47: MipsELFStreamer(Context, std::move(TAB), std::move(OW),48std::move(Emitter)) {}4950~MipsNaClELFStreamer() override = default;5152private:53// Whether we started the sandboxing sequence for calls. Calls are bundled54// with branch delays and aligned to the bundle end.55bool PendingCall = false;5657bool isIndirectJump(const MCInst &MI) {58if (MI.getOpcode() == Mips::JALR) {59// MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.60// JALR is an indirect branch if the link register is $0.61assert(MI.getOperand(0).isReg());62return MI.getOperand(0).getReg() == Mips::ZERO;63}64return MI.getOpcode() == Mips::JR;65}6667bool isStackPointerFirstOperand(const MCInst &MI) {68return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()69&& MI.getOperand(0).getReg() == Mips::SP);70}7172bool isCall(const MCInst &MI, bool *IsIndirectCall) {73unsigned Opcode = MI.getOpcode();7475*IsIndirectCall = false;7677switch (Opcode) {78default:79return false;8081case Mips::JAL:82case Mips::BAL:83case Mips::BAL_BR:84case Mips::BLTZAL:85case Mips::BGEZAL:86return true;8788case Mips::JALR:89// JALR is only a call if the link register is not $0. Otherwise it's an90// indirect branch.91assert(MI.getOperand(0).isReg());92if (MI.getOperand(0).getReg() == Mips::ZERO)93return false;9495*IsIndirectCall = true;96return true;97}98}99100void emitMask(unsigned AddrReg, unsigned MaskReg,101const MCSubtargetInfo &STI) {102MCInst MaskInst;103MaskInst.setOpcode(Mips::AND);104MaskInst.addOperand(MCOperand::createReg(AddrReg));105MaskInst.addOperand(MCOperand::createReg(AddrReg));106MaskInst.addOperand(MCOperand::createReg(MaskReg));107MipsELFStreamer::emitInstruction(MaskInst, STI);108}109110// Sandbox indirect branch or return instruction by inserting mask operation111// before it.112void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {113unsigned AddrReg = MI.getOperand(0).getReg();114115emitBundleLock(false);116emitMask(AddrReg, IndirectBranchMaskReg, STI);117MipsELFStreamer::emitInstruction(MI, STI);118emitBundleUnlock();119}120121// Sandbox memory access or SP change. Insert mask operation before and/or122// after the instruction.123void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,124const MCSubtargetInfo &STI, bool MaskBefore,125bool MaskAfter) {126emitBundleLock(false);127if (MaskBefore) {128// Sandbox memory access.129unsigned BaseReg = MI.getOperand(AddrIdx).getReg();130emitMask(BaseReg, LoadStoreStackMaskReg, STI);131}132MipsELFStreamer::emitInstruction(MI, STI);133if (MaskAfter) {134// Sandbox SP change.135unsigned SPReg = MI.getOperand(0).getReg();136assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");137emitMask(SPReg, LoadStoreStackMaskReg, STI);138}139emitBundleUnlock();140}141142public:143/// This function is the one used to emit instruction data into the ELF144/// streamer. We override it to mask dangerous instructions.145void emitInstruction(const MCInst &Inst,146const MCSubtargetInfo &STI) override {147// Sandbox indirect jumps.148if (isIndirectJump(Inst)) {149if (PendingCall)150report_fatal_error("Dangerous instruction in branch delay slot!");151sandboxIndirectJump(Inst, STI);152return;153}154155// Sandbox loads, stores and SP changes.156unsigned AddrIdx = 0;157bool IsStore = false;158bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,159&IsStore);160bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);161if (IsMemAccess || IsSPFirstOperand) {162bool MaskBefore = (IsMemAccess163&& baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)164.getReg()));165bool MaskAfter = IsSPFirstOperand && !IsStore;166if (MaskBefore || MaskAfter) {167if (PendingCall)168report_fatal_error("Dangerous instruction in branch delay slot!");169sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);170return;171}172// fallthrough173}174175// Sandbox calls by aligning call and branch delay to the bundle end.176// For indirect calls, emit the mask before the call.177bool IsIndirectCall;178if (isCall(Inst, &IsIndirectCall)) {179if (PendingCall)180report_fatal_error("Dangerous instruction in branch delay slot!");181182// Start the sandboxing sequence by emitting call.183emitBundleLock(true);184if (IsIndirectCall) {185unsigned TargetReg = Inst.getOperand(1).getReg();186emitMask(TargetReg, IndirectBranchMaskReg, STI);187}188MipsELFStreamer::emitInstruction(Inst, STI);189PendingCall = true;190return;191}192if (PendingCall) {193// Finish the sandboxing sequence by emitting branch delay.194MipsELFStreamer::emitInstruction(Inst, STI);195emitBundleUnlock();196PendingCall = false;197return;198}199200// None of the sandboxing applies, just emit the instruction.201MipsELFStreamer::emitInstruction(Inst, STI);202}203};204205} // end anonymous namespace206207namespace llvm {208209bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,210bool *IsStore) {211if (IsStore)212*IsStore = false;213214switch (Opcode) {215default:216return false;217218// Load instructions with base address register in position 1.219case Mips::LB:220case Mips::LBu:221case Mips::LH:222case Mips::LHu:223case Mips::LW:224case Mips::LWC1:225case Mips::LDC1:226case Mips::LL:227case Mips::LL_R6:228case Mips::LWL:229case Mips::LWR:230*AddrIdx = 1;231return true;232233// Store instructions with base address register in position 1.234case Mips::SB:235case Mips::SH:236case Mips::SW:237case Mips::SWC1:238case Mips::SDC1:239case Mips::SWL:240case Mips::SWR:241*AddrIdx = 1;242if (IsStore)243*IsStore = true;244return true;245246// Store instructions with base address register in position 2.247case Mips::SC:248case Mips::SC_R6:249*AddrIdx = 2;250if (IsStore)251*IsStore = true;252return true;253}254}255256bool baseRegNeedsLoadStoreMask(unsigned Reg) {257// The contents of SP and thread pointer register do not require masking.258return Reg != Mips::SP && Reg != Mips::T8;259}260261MCELFStreamer *262createMipsNaClELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,263std::unique_ptr<MCObjectWriter> OW,264std::unique_ptr<MCCodeEmitter> Emitter) {265MipsNaClELFStreamer *S = new MipsNaClELFStreamer(266Context, std::move(TAB), std::move(OW), std::move(Emitter));267268// Set bundle-alignment as required by the NaCl ABI for the target.269S->emitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);270271return S;272}273274} // end namespace llvm275276277