xref: /aosp_15_r20/external/llvm/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This file implements MCELFStreamer for Mips NaCl.  It emits .o object files
11*9880d681SAndroid Build Coastguard Worker // as required by NaCl's SFI sandbox.  It inserts address-masking instructions
12*9880d681SAndroid Build Coastguard Worker // before dangerous control-flow and memory access instructions.  It inserts
13*9880d681SAndroid Build Coastguard Worker // address-masking instructions after instructions that change the stack
14*9880d681SAndroid Build Coastguard Worker // pointer.  It ensures that the mask and the dangerous instruction are always
15*9880d681SAndroid Build Coastguard Worker // emitted in the same bundle.  It aligns call + branch delay to the bundle end,
16*9880d681SAndroid Build Coastguard Worker // so that return address is always aligned to the start of next bundle.
17*9880d681SAndroid Build Coastguard Worker //
18*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
19*9880d681SAndroid Build Coastguard Worker 
20*9880d681SAndroid Build Coastguard Worker #include "Mips.h"
21*9880d681SAndroid Build Coastguard Worker #include "MipsELFStreamer.h"
22*9880d681SAndroid Build Coastguard Worker #include "MipsMCNaCl.h"
23*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCELFStreamer.h"
24*9880d681SAndroid Build Coastguard Worker 
25*9880d681SAndroid Build Coastguard Worker using namespace llvm;
26*9880d681SAndroid Build Coastguard Worker 
27*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "mips-mc-nacl"
28*9880d681SAndroid Build Coastguard Worker 
29*9880d681SAndroid Build Coastguard Worker namespace {
30*9880d681SAndroid Build Coastguard Worker 
31*9880d681SAndroid Build Coastguard Worker const unsigned IndirectBranchMaskReg = Mips::T6;
32*9880d681SAndroid Build Coastguard Worker const unsigned LoadStoreStackMaskReg = Mips::T7;
33*9880d681SAndroid Build Coastguard Worker 
34*9880d681SAndroid Build Coastguard Worker /// Extend the generic MCELFStreamer class so that it can mask dangerous
35*9880d681SAndroid Build Coastguard Worker /// instructions.
36*9880d681SAndroid Build Coastguard Worker 
37*9880d681SAndroid Build Coastguard Worker class MipsNaClELFStreamer : public MipsELFStreamer {
38*9880d681SAndroid Build Coastguard Worker public:
MipsNaClELFStreamer(MCContext & Context,MCAsmBackend & TAB,raw_pwrite_stream & OS,MCCodeEmitter * Emitter)39*9880d681SAndroid Build Coastguard Worker   MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
40*9880d681SAndroid Build Coastguard Worker                       raw_pwrite_stream &OS, MCCodeEmitter *Emitter)
41*9880d681SAndroid Build Coastguard Worker       : MipsELFStreamer(Context, TAB, OS, Emitter), PendingCall(false) {}
42*9880d681SAndroid Build Coastguard Worker 
~MipsNaClELFStreamer()43*9880d681SAndroid Build Coastguard Worker   ~MipsNaClELFStreamer() override {}
44*9880d681SAndroid Build Coastguard Worker 
45*9880d681SAndroid Build Coastguard Worker private:
46*9880d681SAndroid Build Coastguard Worker   // Whether we started the sandboxing sequence for calls.  Calls are bundled
47*9880d681SAndroid Build Coastguard Worker   // with branch delays and aligned to the bundle end.
48*9880d681SAndroid Build Coastguard Worker   bool PendingCall;
49*9880d681SAndroid Build Coastguard Worker 
isIndirectJump(const MCInst & MI)50*9880d681SAndroid Build Coastguard Worker   bool isIndirectJump(const MCInst &MI) {
51*9880d681SAndroid Build Coastguard Worker     if (MI.getOpcode() == Mips::JALR) {
52*9880d681SAndroid Build Coastguard Worker       // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.
53*9880d681SAndroid Build Coastguard Worker       // JALR is an indirect branch if the link register is $0.
54*9880d681SAndroid Build Coastguard Worker       assert(MI.getOperand(0).isReg());
55*9880d681SAndroid Build Coastguard Worker       return MI.getOperand(0).getReg() == Mips::ZERO;
56*9880d681SAndroid Build Coastguard Worker     }
57*9880d681SAndroid Build Coastguard Worker     return MI.getOpcode() == Mips::JR;
58*9880d681SAndroid Build Coastguard Worker   }
59*9880d681SAndroid Build Coastguard Worker 
isStackPointerFirstOperand(const MCInst & MI)60*9880d681SAndroid Build Coastguard Worker   bool isStackPointerFirstOperand(const MCInst &MI) {
61*9880d681SAndroid Build Coastguard Worker     return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
62*9880d681SAndroid Build Coastguard Worker             && MI.getOperand(0).getReg() == Mips::SP);
63*9880d681SAndroid Build Coastguard Worker   }
64*9880d681SAndroid Build Coastguard Worker 
isCall(const MCInst & MI,bool * IsIndirectCall)65*9880d681SAndroid Build Coastguard Worker   bool isCall(const MCInst &MI, bool *IsIndirectCall) {
66*9880d681SAndroid Build Coastguard Worker     unsigned Opcode = MI.getOpcode();
67*9880d681SAndroid Build Coastguard Worker 
68*9880d681SAndroid Build Coastguard Worker     *IsIndirectCall = false;
69*9880d681SAndroid Build Coastguard Worker 
70*9880d681SAndroid Build Coastguard Worker     switch (Opcode) {
71*9880d681SAndroid Build Coastguard Worker     default:
72*9880d681SAndroid Build Coastguard Worker       return false;
73*9880d681SAndroid Build Coastguard Worker 
74*9880d681SAndroid Build Coastguard Worker     case Mips::JAL:
75*9880d681SAndroid Build Coastguard Worker     case Mips::BAL:
76*9880d681SAndroid Build Coastguard Worker     case Mips::BAL_BR:
77*9880d681SAndroid Build Coastguard Worker     case Mips::BLTZAL:
78*9880d681SAndroid Build Coastguard Worker     case Mips::BGEZAL:
79*9880d681SAndroid Build Coastguard Worker       return true;
80*9880d681SAndroid Build Coastguard Worker 
81*9880d681SAndroid Build Coastguard Worker     case Mips::JALR:
82*9880d681SAndroid Build Coastguard Worker       // JALR is only a call if the link register is not $0. Otherwise it's an
83*9880d681SAndroid Build Coastguard Worker       // indirect branch.
84*9880d681SAndroid Build Coastguard Worker       assert(MI.getOperand(0).isReg());
85*9880d681SAndroid Build Coastguard Worker       if (MI.getOperand(0).getReg() == Mips::ZERO)
86*9880d681SAndroid Build Coastguard Worker         return false;
87*9880d681SAndroid Build Coastguard Worker 
88*9880d681SAndroid Build Coastguard Worker       *IsIndirectCall = true;
89*9880d681SAndroid Build Coastguard Worker       return true;
90*9880d681SAndroid Build Coastguard Worker     }
91*9880d681SAndroid Build Coastguard Worker   }
92*9880d681SAndroid Build Coastguard Worker 
emitMask(unsigned AddrReg,unsigned MaskReg,const MCSubtargetInfo & STI)93*9880d681SAndroid Build Coastguard Worker   void emitMask(unsigned AddrReg, unsigned MaskReg,
94*9880d681SAndroid Build Coastguard Worker                 const MCSubtargetInfo &STI) {
95*9880d681SAndroid Build Coastguard Worker     MCInst MaskInst;
96*9880d681SAndroid Build Coastguard Worker     MaskInst.setOpcode(Mips::AND);
97*9880d681SAndroid Build Coastguard Worker     MaskInst.addOperand(MCOperand::createReg(AddrReg));
98*9880d681SAndroid Build Coastguard Worker     MaskInst.addOperand(MCOperand::createReg(AddrReg));
99*9880d681SAndroid Build Coastguard Worker     MaskInst.addOperand(MCOperand::createReg(MaskReg));
100*9880d681SAndroid Build Coastguard Worker     MipsELFStreamer::EmitInstruction(MaskInst, STI);
101*9880d681SAndroid Build Coastguard Worker   }
102*9880d681SAndroid Build Coastguard Worker 
103*9880d681SAndroid Build Coastguard Worker   // Sandbox indirect branch or return instruction by inserting mask operation
104*9880d681SAndroid Build Coastguard Worker   // before it.
sandboxIndirectJump(const MCInst & MI,const MCSubtargetInfo & STI)105*9880d681SAndroid Build Coastguard Worker   void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
106*9880d681SAndroid Build Coastguard Worker     unsigned AddrReg = MI.getOperand(0).getReg();
107*9880d681SAndroid Build Coastguard Worker 
108*9880d681SAndroid Build Coastguard Worker     EmitBundleLock(false);
109*9880d681SAndroid Build Coastguard Worker     emitMask(AddrReg, IndirectBranchMaskReg, STI);
110*9880d681SAndroid Build Coastguard Worker     MipsELFStreamer::EmitInstruction(MI, STI);
111*9880d681SAndroid Build Coastguard Worker     EmitBundleUnlock();
112*9880d681SAndroid Build Coastguard Worker   }
113*9880d681SAndroid Build Coastguard Worker 
114*9880d681SAndroid Build Coastguard Worker   // Sandbox memory access or SP change.  Insert mask operation before and/or
115*9880d681SAndroid Build Coastguard Worker   // after the instruction.
sandboxLoadStoreStackChange(const MCInst & MI,unsigned AddrIdx,const MCSubtargetInfo & STI,bool MaskBefore,bool MaskAfter)116*9880d681SAndroid Build Coastguard Worker   void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
117*9880d681SAndroid Build Coastguard Worker                                    const MCSubtargetInfo &STI, bool MaskBefore,
118*9880d681SAndroid Build Coastguard Worker                                    bool MaskAfter) {
119*9880d681SAndroid Build Coastguard Worker     EmitBundleLock(false);
120*9880d681SAndroid Build Coastguard Worker     if (MaskBefore) {
121*9880d681SAndroid Build Coastguard Worker       // Sandbox memory access.
122*9880d681SAndroid Build Coastguard Worker       unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
123*9880d681SAndroid Build Coastguard Worker       emitMask(BaseReg, LoadStoreStackMaskReg, STI);
124*9880d681SAndroid Build Coastguard Worker     }
125*9880d681SAndroid Build Coastguard Worker     MipsELFStreamer::EmitInstruction(MI, STI);
126*9880d681SAndroid Build Coastguard Worker     if (MaskAfter) {
127*9880d681SAndroid Build Coastguard Worker       // Sandbox SP change.
128*9880d681SAndroid Build Coastguard Worker       unsigned SPReg = MI.getOperand(0).getReg();
129*9880d681SAndroid Build Coastguard Worker       assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
130*9880d681SAndroid Build Coastguard Worker       emitMask(SPReg, LoadStoreStackMaskReg, STI);
131*9880d681SAndroid Build Coastguard Worker     }
132*9880d681SAndroid Build Coastguard Worker     EmitBundleUnlock();
133*9880d681SAndroid Build Coastguard Worker   }
134*9880d681SAndroid Build Coastguard Worker 
135*9880d681SAndroid Build Coastguard Worker public:
136*9880d681SAndroid Build Coastguard Worker   /// This function is the one used to emit instruction data into the ELF
137*9880d681SAndroid Build Coastguard Worker   /// streamer.  We override it to mask dangerous instructions.
EmitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)138*9880d681SAndroid Build Coastguard Worker   void EmitInstruction(const MCInst &Inst,
139*9880d681SAndroid Build Coastguard Worker                        const MCSubtargetInfo &STI) override {
140*9880d681SAndroid Build Coastguard Worker     // Sandbox indirect jumps.
141*9880d681SAndroid Build Coastguard Worker     if (isIndirectJump(Inst)) {
142*9880d681SAndroid Build Coastguard Worker       if (PendingCall)
143*9880d681SAndroid Build Coastguard Worker         report_fatal_error("Dangerous instruction in branch delay slot!");
144*9880d681SAndroid Build Coastguard Worker       sandboxIndirectJump(Inst, STI);
145*9880d681SAndroid Build Coastguard Worker       return;
146*9880d681SAndroid Build Coastguard Worker     }
147*9880d681SAndroid Build Coastguard Worker 
148*9880d681SAndroid Build Coastguard Worker     // Sandbox loads, stores and SP changes.
149*9880d681SAndroid Build Coastguard Worker     unsigned AddrIdx;
150*9880d681SAndroid Build Coastguard Worker     bool IsStore;
151*9880d681SAndroid Build Coastguard Worker     bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
152*9880d681SAndroid Build Coastguard Worker                                                     &IsStore);
153*9880d681SAndroid Build Coastguard Worker     bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
154*9880d681SAndroid Build Coastguard Worker     if (IsMemAccess || IsSPFirstOperand) {
155*9880d681SAndroid Build Coastguard Worker       bool MaskBefore = (IsMemAccess
156*9880d681SAndroid Build Coastguard Worker                          && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
157*9880d681SAndroid Build Coastguard Worker                                                           .getReg()));
158*9880d681SAndroid Build Coastguard Worker       bool MaskAfter = IsSPFirstOperand && !IsStore;
159*9880d681SAndroid Build Coastguard Worker       if (MaskBefore || MaskAfter) {
160*9880d681SAndroid Build Coastguard Worker         if (PendingCall)
161*9880d681SAndroid Build Coastguard Worker           report_fatal_error("Dangerous instruction in branch delay slot!");
162*9880d681SAndroid Build Coastguard Worker         sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
163*9880d681SAndroid Build Coastguard Worker         return;
164*9880d681SAndroid Build Coastguard Worker       }
165*9880d681SAndroid Build Coastguard Worker       // fallthrough
166*9880d681SAndroid Build Coastguard Worker     }
167*9880d681SAndroid Build Coastguard Worker 
168*9880d681SAndroid Build Coastguard Worker     // Sandbox calls by aligning call and branch delay to the bundle end.
169*9880d681SAndroid Build Coastguard Worker     // For indirect calls, emit the mask before the call.
170*9880d681SAndroid Build Coastguard Worker     bool IsIndirectCall;
171*9880d681SAndroid Build Coastguard Worker     if (isCall(Inst, &IsIndirectCall)) {
172*9880d681SAndroid Build Coastguard Worker       if (PendingCall)
173*9880d681SAndroid Build Coastguard Worker         report_fatal_error("Dangerous instruction in branch delay slot!");
174*9880d681SAndroid Build Coastguard Worker 
175*9880d681SAndroid Build Coastguard Worker       // Start the sandboxing sequence by emitting call.
176*9880d681SAndroid Build Coastguard Worker       EmitBundleLock(true);
177*9880d681SAndroid Build Coastguard Worker       if (IsIndirectCall) {
178*9880d681SAndroid Build Coastguard Worker         unsigned TargetReg = Inst.getOperand(1).getReg();
179*9880d681SAndroid Build Coastguard Worker         emitMask(TargetReg, IndirectBranchMaskReg, STI);
180*9880d681SAndroid Build Coastguard Worker       }
181*9880d681SAndroid Build Coastguard Worker       MipsELFStreamer::EmitInstruction(Inst, STI);
182*9880d681SAndroid Build Coastguard Worker       PendingCall = true;
183*9880d681SAndroid Build Coastguard Worker       return;
184*9880d681SAndroid Build Coastguard Worker     }
185*9880d681SAndroid Build Coastguard Worker     if (PendingCall) {
186*9880d681SAndroid Build Coastguard Worker       // Finish the sandboxing sequence by emitting branch delay.
187*9880d681SAndroid Build Coastguard Worker       MipsELFStreamer::EmitInstruction(Inst, STI);
188*9880d681SAndroid Build Coastguard Worker       EmitBundleUnlock();
189*9880d681SAndroid Build Coastguard Worker       PendingCall = false;
190*9880d681SAndroid Build Coastguard Worker       return;
191*9880d681SAndroid Build Coastguard Worker     }
192*9880d681SAndroid Build Coastguard Worker 
193*9880d681SAndroid Build Coastguard Worker     // None of the sandboxing applies, just emit the instruction.
194*9880d681SAndroid Build Coastguard Worker     MipsELFStreamer::EmitInstruction(Inst, STI);
195*9880d681SAndroid Build Coastguard Worker   }
196*9880d681SAndroid Build Coastguard Worker };
197*9880d681SAndroid Build Coastguard Worker 
198*9880d681SAndroid Build Coastguard Worker } // end anonymous namespace
199*9880d681SAndroid Build Coastguard Worker 
200*9880d681SAndroid Build Coastguard Worker namespace llvm {
201*9880d681SAndroid Build Coastguard Worker 
isBasePlusOffsetMemoryAccess(unsigned Opcode,unsigned * AddrIdx,bool * IsStore)202*9880d681SAndroid Build Coastguard Worker bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
203*9880d681SAndroid Build Coastguard Worker                                   bool *IsStore) {
204*9880d681SAndroid Build Coastguard Worker   if (IsStore)
205*9880d681SAndroid Build Coastguard Worker     *IsStore = false;
206*9880d681SAndroid Build Coastguard Worker 
207*9880d681SAndroid Build Coastguard Worker   switch (Opcode) {
208*9880d681SAndroid Build Coastguard Worker   default:
209*9880d681SAndroid Build Coastguard Worker     return false;
210*9880d681SAndroid Build Coastguard Worker 
211*9880d681SAndroid Build Coastguard Worker   // Load instructions with base address register in position 1.
212*9880d681SAndroid Build Coastguard Worker   case Mips::LB:
213*9880d681SAndroid Build Coastguard Worker   case Mips::LBu:
214*9880d681SAndroid Build Coastguard Worker   case Mips::LH:
215*9880d681SAndroid Build Coastguard Worker   case Mips::LHu:
216*9880d681SAndroid Build Coastguard Worker   case Mips::LW:
217*9880d681SAndroid Build Coastguard Worker   case Mips::LWC1:
218*9880d681SAndroid Build Coastguard Worker   case Mips::LDC1:
219*9880d681SAndroid Build Coastguard Worker   case Mips::LL:
220*9880d681SAndroid Build Coastguard Worker   case Mips::LL_R6:
221*9880d681SAndroid Build Coastguard Worker   case Mips::LWL:
222*9880d681SAndroid Build Coastguard Worker   case Mips::LWR:
223*9880d681SAndroid Build Coastguard Worker     *AddrIdx = 1;
224*9880d681SAndroid Build Coastguard Worker     return true;
225*9880d681SAndroid Build Coastguard Worker 
226*9880d681SAndroid Build Coastguard Worker   // Store instructions with base address register in position 1.
227*9880d681SAndroid Build Coastguard Worker   case Mips::SB:
228*9880d681SAndroid Build Coastguard Worker   case Mips::SH:
229*9880d681SAndroid Build Coastguard Worker   case Mips::SW:
230*9880d681SAndroid Build Coastguard Worker   case Mips::SWC1:
231*9880d681SAndroid Build Coastguard Worker   case Mips::SDC1:
232*9880d681SAndroid Build Coastguard Worker   case Mips::SWL:
233*9880d681SAndroid Build Coastguard Worker   case Mips::SWR:
234*9880d681SAndroid Build Coastguard Worker     *AddrIdx = 1;
235*9880d681SAndroid Build Coastguard Worker     if (IsStore)
236*9880d681SAndroid Build Coastguard Worker       *IsStore = true;
237*9880d681SAndroid Build Coastguard Worker     return true;
238*9880d681SAndroid Build Coastguard Worker 
239*9880d681SAndroid Build Coastguard Worker   // Store instructions with base address register in position 2.
240*9880d681SAndroid Build Coastguard Worker   case Mips::SC:
241*9880d681SAndroid Build Coastguard Worker   case Mips::SC_R6:
242*9880d681SAndroid Build Coastguard Worker     *AddrIdx = 2;
243*9880d681SAndroid Build Coastguard Worker     if (IsStore)
244*9880d681SAndroid Build Coastguard Worker       *IsStore = true;
245*9880d681SAndroid Build Coastguard Worker     return true;
246*9880d681SAndroid Build Coastguard Worker   }
247*9880d681SAndroid Build Coastguard Worker }
248*9880d681SAndroid Build Coastguard Worker 
baseRegNeedsLoadStoreMask(unsigned Reg)249*9880d681SAndroid Build Coastguard Worker bool baseRegNeedsLoadStoreMask(unsigned Reg) {
250*9880d681SAndroid Build Coastguard Worker   // The contents of SP and thread pointer register do not require masking.
251*9880d681SAndroid Build Coastguard Worker   return Reg != Mips::SP && Reg != Mips::T8;
252*9880d681SAndroid Build Coastguard Worker }
253*9880d681SAndroid Build Coastguard Worker 
createMipsNaClELFStreamer(MCContext & Context,MCAsmBackend & TAB,raw_pwrite_stream & OS,MCCodeEmitter * Emitter,bool RelaxAll)254*9880d681SAndroid Build Coastguard Worker MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
255*9880d681SAndroid Build Coastguard Worker                                          raw_pwrite_stream &OS,
256*9880d681SAndroid Build Coastguard Worker                                          MCCodeEmitter *Emitter,
257*9880d681SAndroid Build Coastguard Worker                                          bool RelaxAll) {
258*9880d681SAndroid Build Coastguard Worker   MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
259*9880d681SAndroid Build Coastguard Worker   if (RelaxAll)
260*9880d681SAndroid Build Coastguard Worker     S->getAssembler().setRelaxAll(true);
261*9880d681SAndroid Build Coastguard Worker 
262*9880d681SAndroid Build Coastguard Worker   // Set bundle-alignment as required by the NaCl ABI for the target.
263*9880d681SAndroid Build Coastguard Worker   S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
264*9880d681SAndroid Build Coastguard Worker 
265*9880d681SAndroid Build Coastguard Worker   return S;
266*9880d681SAndroid Build Coastguard Worker }
267*9880d681SAndroid Build Coastguard Worker 
268*9880d681SAndroid Build Coastguard Worker }
269