xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements MCELFStreamer for Mips NaCl.  It emits .o object files
100b57cec5SDimitry Andric // as required by NaCl's SFI sandbox.  It inserts address-masking instructions
110b57cec5SDimitry Andric // before dangerous control-flow and memory access instructions.  It inserts
120b57cec5SDimitry Andric // address-masking instructions after instructions that change the stack
130b57cec5SDimitry Andric // pointer.  It ensures that the mask and the dangerous instruction are always
140b57cec5SDimitry Andric // emitted in the same bundle.  It aligns call + branch delay to the bundle end,
150b57cec5SDimitry Andric // so that return address is always aligned to the start of next bundle.
160b57cec5SDimitry Andric //
170b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "Mips.h"
200b57cec5SDimitry Andric #include "MipsELFStreamer.h"
210b57cec5SDimitry Andric #include "MipsMCNaCl.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCCodeEmitter.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCELFStreamer.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
270b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
280b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
290b57cec5SDimitry Andric #include <cassert>
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #define DEBUG_TYPE "mips-mc-nacl"
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric namespace {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric const unsigned IndirectBranchMaskReg = Mips::T6;
380b57cec5SDimitry Andric const unsigned LoadStoreStackMaskReg = Mips::T7;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric /// Extend the generic MCELFStreamer class so that it can mask dangerous
410b57cec5SDimitry Andric /// instructions.
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric class MipsNaClELFStreamer : public MipsELFStreamer {
440b57cec5SDimitry Andric public:
MipsNaClELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> TAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)450b57cec5SDimitry Andric   MipsNaClELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
460b57cec5SDimitry Andric                       std::unique_ptr<MCObjectWriter> OW,
470b57cec5SDimitry Andric                       std::unique_ptr<MCCodeEmitter> Emitter)
480b57cec5SDimitry Andric       : MipsELFStreamer(Context, std::move(TAB), std::move(OW),
490b57cec5SDimitry Andric                         std::move(Emitter)) {}
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   ~MipsNaClELFStreamer() override = default;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric private:
540b57cec5SDimitry Andric   // Whether we started the sandboxing sequence for calls.  Calls are bundled
550b57cec5SDimitry Andric   // with branch delays and aligned to the bundle end.
560b57cec5SDimitry Andric   bool PendingCall = false;
570b57cec5SDimitry Andric 
isIndirectJump(const MCInst & MI)580b57cec5SDimitry Andric   bool isIndirectJump(const MCInst &MI) {
590b57cec5SDimitry Andric     if (MI.getOpcode() == Mips::JALR) {
600b57cec5SDimitry Andric       // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.
610b57cec5SDimitry Andric       // JALR is an indirect branch if the link register is $0.
620b57cec5SDimitry Andric       assert(MI.getOperand(0).isReg());
630b57cec5SDimitry Andric       return MI.getOperand(0).getReg() == Mips::ZERO;
640b57cec5SDimitry Andric     }
650b57cec5SDimitry Andric     return MI.getOpcode() == Mips::JR;
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
isStackPointerFirstOperand(const MCInst & MI)680b57cec5SDimitry Andric   bool isStackPointerFirstOperand(const MCInst &MI) {
690b57cec5SDimitry Andric     return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
700b57cec5SDimitry Andric             && MI.getOperand(0).getReg() == Mips::SP);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
isCall(const MCInst & MI,bool * IsIndirectCall)730b57cec5SDimitry Andric   bool isCall(const MCInst &MI, bool *IsIndirectCall) {
740b57cec5SDimitry Andric     unsigned Opcode = MI.getOpcode();
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     *IsIndirectCall = false;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric     switch (Opcode) {
790b57cec5SDimitry Andric     default:
800b57cec5SDimitry Andric       return false;
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric     case Mips::JAL:
830b57cec5SDimitry Andric     case Mips::BAL:
840b57cec5SDimitry Andric     case Mips::BAL_BR:
850b57cec5SDimitry Andric     case Mips::BLTZAL:
860b57cec5SDimitry Andric     case Mips::BGEZAL:
870b57cec5SDimitry Andric       return true;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric     case Mips::JALR:
900b57cec5SDimitry Andric       // JALR is only a call if the link register is not $0. Otherwise it's an
910b57cec5SDimitry Andric       // indirect branch.
920b57cec5SDimitry Andric       assert(MI.getOperand(0).isReg());
930b57cec5SDimitry Andric       if (MI.getOperand(0).getReg() == Mips::ZERO)
940b57cec5SDimitry Andric         return false;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric       *IsIndirectCall = true;
970b57cec5SDimitry Andric       return true;
980b57cec5SDimitry Andric     }
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
emitMask(unsigned AddrReg,unsigned MaskReg,const MCSubtargetInfo & STI)1010b57cec5SDimitry Andric   void emitMask(unsigned AddrReg, unsigned MaskReg,
1020b57cec5SDimitry Andric                 const MCSubtargetInfo &STI) {
1030b57cec5SDimitry Andric     MCInst MaskInst;
1040b57cec5SDimitry Andric     MaskInst.setOpcode(Mips::AND);
1050b57cec5SDimitry Andric     MaskInst.addOperand(MCOperand::createReg(AddrReg));
1060b57cec5SDimitry Andric     MaskInst.addOperand(MCOperand::createReg(AddrReg));
1070b57cec5SDimitry Andric     MaskInst.addOperand(MCOperand::createReg(MaskReg));
1085ffd83dbSDimitry Andric     MipsELFStreamer::emitInstruction(MaskInst, STI);
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   // Sandbox indirect branch or return instruction by inserting mask operation
1120b57cec5SDimitry Andric   // before it.
sandboxIndirectJump(const MCInst & MI,const MCSubtargetInfo & STI)1130b57cec5SDimitry Andric   void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
1140b57cec5SDimitry Andric     unsigned AddrReg = MI.getOperand(0).getReg();
1150b57cec5SDimitry Andric 
1165ffd83dbSDimitry Andric     emitBundleLock(false);
1170b57cec5SDimitry Andric     emitMask(AddrReg, IndirectBranchMaskReg, STI);
1185ffd83dbSDimitry Andric     MipsELFStreamer::emitInstruction(MI, STI);
1195ffd83dbSDimitry Andric     emitBundleUnlock();
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // Sandbox memory access or SP change.  Insert mask operation before and/or
1230b57cec5SDimitry Andric   // after the instruction.
sandboxLoadStoreStackChange(const MCInst & MI,unsigned AddrIdx,const MCSubtargetInfo & STI,bool MaskBefore,bool MaskAfter)1240b57cec5SDimitry Andric   void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
1250b57cec5SDimitry Andric                                    const MCSubtargetInfo &STI, bool MaskBefore,
1260b57cec5SDimitry Andric                                    bool MaskAfter) {
1275ffd83dbSDimitry Andric     emitBundleLock(false);
1280b57cec5SDimitry Andric     if (MaskBefore) {
1290b57cec5SDimitry Andric       // Sandbox memory access.
1300b57cec5SDimitry Andric       unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
1310b57cec5SDimitry Andric       emitMask(BaseReg, LoadStoreStackMaskReg, STI);
1320b57cec5SDimitry Andric     }
1335ffd83dbSDimitry Andric     MipsELFStreamer::emitInstruction(MI, STI);
1340b57cec5SDimitry Andric     if (MaskAfter) {
1350b57cec5SDimitry Andric       // Sandbox SP change.
1360b57cec5SDimitry Andric       unsigned SPReg = MI.getOperand(0).getReg();
1370b57cec5SDimitry Andric       assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
1380b57cec5SDimitry Andric       emitMask(SPReg, LoadStoreStackMaskReg, STI);
1390b57cec5SDimitry Andric     }
1405ffd83dbSDimitry Andric     emitBundleUnlock();
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric public:
1440b57cec5SDimitry Andric   /// This function is the one used to emit instruction data into the ELF
1450b57cec5SDimitry Andric   /// streamer.  We override it to mask dangerous instructions.
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)1465ffd83dbSDimitry Andric   void emitInstruction(const MCInst &Inst,
1470b57cec5SDimitry Andric                        const MCSubtargetInfo &STI) override {
1480b57cec5SDimitry Andric     // Sandbox indirect jumps.
1490b57cec5SDimitry Andric     if (isIndirectJump(Inst)) {
1500b57cec5SDimitry Andric       if (PendingCall)
1510b57cec5SDimitry Andric         report_fatal_error("Dangerous instruction in branch delay slot!");
1520b57cec5SDimitry Andric       sandboxIndirectJump(Inst, STI);
1530b57cec5SDimitry Andric       return;
1540b57cec5SDimitry Andric     }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric     // Sandbox loads, stores and SP changes.
157480093f4SDimitry Andric     unsigned AddrIdx = 0;
158480093f4SDimitry Andric     bool IsStore = false;
1590b57cec5SDimitry Andric     bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
1600b57cec5SDimitry Andric                                                     &IsStore);
1610b57cec5SDimitry Andric     bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
1620b57cec5SDimitry Andric     if (IsMemAccess || IsSPFirstOperand) {
1630b57cec5SDimitry Andric       bool MaskBefore = (IsMemAccess
1640b57cec5SDimitry Andric                          && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
1650b57cec5SDimitry Andric                                                           .getReg()));
1660b57cec5SDimitry Andric       bool MaskAfter = IsSPFirstOperand && !IsStore;
1670b57cec5SDimitry Andric       if (MaskBefore || MaskAfter) {
1680b57cec5SDimitry Andric         if (PendingCall)
1690b57cec5SDimitry Andric           report_fatal_error("Dangerous instruction in branch delay slot!");
1700b57cec5SDimitry Andric         sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
1710b57cec5SDimitry Andric         return;
1720b57cec5SDimitry Andric       }
1730b57cec5SDimitry Andric       // fallthrough
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     // Sandbox calls by aligning call and branch delay to the bundle end.
1770b57cec5SDimitry Andric     // For indirect calls, emit the mask before the call.
1780b57cec5SDimitry Andric     bool IsIndirectCall;
1790b57cec5SDimitry Andric     if (isCall(Inst, &IsIndirectCall)) {
1800b57cec5SDimitry Andric       if (PendingCall)
1810b57cec5SDimitry Andric         report_fatal_error("Dangerous instruction in branch delay slot!");
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric       // Start the sandboxing sequence by emitting call.
1845ffd83dbSDimitry Andric       emitBundleLock(true);
1850b57cec5SDimitry Andric       if (IsIndirectCall) {
1860b57cec5SDimitry Andric         unsigned TargetReg = Inst.getOperand(1).getReg();
1870b57cec5SDimitry Andric         emitMask(TargetReg, IndirectBranchMaskReg, STI);
1880b57cec5SDimitry Andric       }
1895ffd83dbSDimitry Andric       MipsELFStreamer::emitInstruction(Inst, STI);
1900b57cec5SDimitry Andric       PendingCall = true;
1910b57cec5SDimitry Andric       return;
1920b57cec5SDimitry Andric     }
1930b57cec5SDimitry Andric     if (PendingCall) {
1940b57cec5SDimitry Andric       // Finish the sandboxing sequence by emitting branch delay.
1955ffd83dbSDimitry Andric       MipsELFStreamer::emitInstruction(Inst, STI);
1965ffd83dbSDimitry Andric       emitBundleUnlock();
1970b57cec5SDimitry Andric       PendingCall = false;
1980b57cec5SDimitry Andric       return;
1990b57cec5SDimitry Andric     }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric     // None of the sandboxing applies, just emit the instruction.
2025ffd83dbSDimitry Andric     MipsELFStreamer::emitInstruction(Inst, STI);
2030b57cec5SDimitry Andric   }
2040b57cec5SDimitry Andric };
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric } // end anonymous namespace
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric namespace llvm {
2090b57cec5SDimitry Andric 
isBasePlusOffsetMemoryAccess(unsigned Opcode,unsigned * AddrIdx,bool * IsStore)2100b57cec5SDimitry Andric bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
2110b57cec5SDimitry Andric                                   bool *IsStore) {
2120b57cec5SDimitry Andric   if (IsStore)
2130b57cec5SDimitry Andric     *IsStore = false;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   switch (Opcode) {
2160b57cec5SDimitry Andric   default:
2170b57cec5SDimitry Andric     return false;
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   // Load instructions with base address register in position 1.
2200b57cec5SDimitry Andric   case Mips::LB:
2210b57cec5SDimitry Andric   case Mips::LBu:
2220b57cec5SDimitry Andric   case Mips::LH:
2230b57cec5SDimitry Andric   case Mips::LHu:
2240b57cec5SDimitry Andric   case Mips::LW:
2250b57cec5SDimitry Andric   case Mips::LWC1:
2260b57cec5SDimitry Andric   case Mips::LDC1:
2270b57cec5SDimitry Andric   case Mips::LL:
2280b57cec5SDimitry Andric   case Mips::LL_R6:
2290b57cec5SDimitry Andric   case Mips::LWL:
2300b57cec5SDimitry Andric   case Mips::LWR:
2310b57cec5SDimitry Andric     *AddrIdx = 1;
2320b57cec5SDimitry Andric     return true;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   // Store instructions with base address register in position 1.
2350b57cec5SDimitry Andric   case Mips::SB:
2360b57cec5SDimitry Andric   case Mips::SH:
2370b57cec5SDimitry Andric   case Mips::SW:
2380b57cec5SDimitry Andric   case Mips::SWC1:
2390b57cec5SDimitry Andric   case Mips::SDC1:
2400b57cec5SDimitry Andric   case Mips::SWL:
2410b57cec5SDimitry Andric   case Mips::SWR:
2420b57cec5SDimitry Andric     *AddrIdx = 1;
2430b57cec5SDimitry Andric     if (IsStore)
2440b57cec5SDimitry Andric       *IsStore = true;
2450b57cec5SDimitry Andric     return true;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   // Store instructions with base address register in position 2.
2480b57cec5SDimitry Andric   case Mips::SC:
2490b57cec5SDimitry Andric   case Mips::SC_R6:
2500b57cec5SDimitry Andric     *AddrIdx = 2;
2510b57cec5SDimitry Andric     if (IsStore)
2520b57cec5SDimitry Andric       *IsStore = true;
2530b57cec5SDimitry Andric     return true;
2540b57cec5SDimitry Andric   }
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric 
baseRegNeedsLoadStoreMask(unsigned Reg)2570b57cec5SDimitry Andric bool baseRegNeedsLoadStoreMask(unsigned Reg) {
2580b57cec5SDimitry Andric   // The contents of SP and thread pointer register do not require masking.
2590b57cec5SDimitry Andric   return Reg != Mips::SP && Reg != Mips::T8;
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric 
262*0fca6ea1SDimitry Andric MCELFStreamer *
createMipsNaClELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> TAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)263*0fca6ea1SDimitry Andric createMipsNaClELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
2640b57cec5SDimitry Andric                           std::unique_ptr<MCObjectWriter> OW,
265*0fca6ea1SDimitry Andric                           std::unique_ptr<MCCodeEmitter> Emitter) {
2660b57cec5SDimitry Andric   MipsNaClELFStreamer *S = new MipsNaClELFStreamer(
2670b57cec5SDimitry Andric       Context, std::move(TAB), std::move(OW), std::move(Emitter));
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   // Set bundle-alignment as required by the NaCl ABI for the target.
270bdd1243dSDimitry Andric   S->emitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   return S;
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric } // end namespace llvm
276