xref: /openbsd-src/gnu/llvm/llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp (revision 09467b48e8bc8b4905716062da846024139afbf2)
1 //===-- MipsReturnProtectorLowering.cpp --------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains the Mips implementation of ReturnProtectorLowering
11 // class.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "MCTargetDesc/MipsBaseInfo.h"
16 #include "MipsInstrInfo.h"
17 #include "MipsMachineFunction.h"
18 #include "MipsReturnProtectorLowering.h"
19 #include "llvm/CodeGen/MachineFrameInfo.h"
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineModuleInfo.h"
23 #include "llvm/CodeGen/MachineRegisterInfo.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/MC/MCSymbol.h"
26 #include "llvm/Support/Debug.h"
27 #include "llvm/Target/TargetOptions.h"
28 #include <cstdlib>
29 
30 using namespace llvm;
31 
insertReturnProtectorPrologue(MachineFunction & MF,MachineBasicBlock & MBB,GlobalVariable * cookie) const32 void MipsReturnProtectorLowering::insertReturnProtectorPrologue(
33     MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const {
34 
35   MachineBasicBlock::instr_iterator MI = MBB.instr_begin();
36   DebugLoc MBBDL = MBB.findDebugLoc(MI);
37   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
38   const TargetMachine &TM = MF.getTarget();
39   unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
40 
41   const GlobalValue *FName = &MF.getFunction();
42 
43   // Select some scratch registers
44   unsigned TempReg1 = Mips::AT_64;
45   unsigned TempReg2 = Mips::V0_64;
46   if (!MBB.isLiveIn(TempReg1))
47     MBB.addLiveIn(TempReg1);
48   if (!MBB.isLiveIn(TempReg2))
49     MBB.addLiveIn(TempReg2);
50 
51   if (TM.isPositionIndependent()) {
52 
53     if (!MBB.isLiveIn(Mips::T9_64))
54       MBB.addLiveIn(Mips::T9_64);
55 
56     // TempReg1 loads the GOT pointer
57     // TempReg2 load the offset from GOT to random cookie pointer
58     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
59       .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
60     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
61       .addGlobalAddress(cookie, 0, MipsII::MO_GOT_HI16);
62     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
63       .addReg(TempReg1)
64       .addReg(Mips::T9_64);
65     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg2)
66       .addReg(TempReg2)
67       .addGlobalAddress(cookie, 0, MipsII::MO_GOT_LO16);
68     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
69       .addReg(TempReg1)
70       .addReg(TempReg2);
71     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG)
72       .addReg(TempReg1)
73       .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
74     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG)
75       .addReg(REG)
76       .addImm(0);
77   } else {
78     // TempReg1 loads the high 32 bits
79     // TempReg2 loads the low 32 bits
80     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
81       .addGlobalAddress(cookie, 0, MipsII::MO_HIGHEST);
82     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
83       .addGlobalAddress(cookie, 0, MipsII::MO_ABS_HI);
84     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg1)
85       .addReg(TempReg1)
86       .addGlobalAddress(cookie, 0, MipsII::MO_HIGHER);
87     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DSLL), TempReg1)
88       .addReg(TempReg1)
89       .addImm(32);
90     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
91       .addReg(TempReg1)
92       .addReg(TempReg2);
93     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG)
94       .addReg(TempReg1)
95       .addGlobalAddress(cookie, 0, MipsII::MO_ABS_LO);
96   }
97 
98   BuildMI(MBB, MI, MBBDL, TII->get(Mips::XOR64), REG)
99     .addReg(REG)
100     .addReg(Mips::RA_64);
101 }
102 
insertReturnProtectorEpilogue(MachineFunction & MF,MachineInstr & MI,GlobalVariable * cookie) const103 void MipsReturnProtectorLowering::insertReturnProtectorEpilogue(
104     MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const {
105 
106 
107   MachineBasicBlock &MBB = *MI.getParent();
108   DebugLoc MBBDL = MI.getDebugLoc();
109   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
110   const TargetMachine &TM = MF.getTarget();
111   unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
112 
113   const GlobalValue *FName = &MF.getFunction();
114   const unsigned TRAPCODE = 0x52;
115 
116   // Select some scratch registers
117   unsigned TempReg1 = Mips::T7_64;
118   unsigned TempReg2 = Mips::T8_64;
119   if (REG == Mips::T7_64 || REG == Mips::T8_64) {
120     TempReg1 = Mips::T5_64;
121     TempReg2 = Mips::T6_64;
122   }
123   if (!MBB.isLiveIn(TempReg1))
124     MBB.addLiveIn(TempReg1);
125   if (!MBB.isLiveIn(TempReg2))
126     MBB.addLiveIn(TempReg2);
127 
128   // Undo the XOR to retrieve the random cookie
129   BuildMI(MBB, MI, MBBDL, TII->get(Mips::XOR64), REG)
130     .addReg(REG)
131     .addReg(Mips::RA_64);
132 
133   // Load the random cookie
134   if (TM.isPositionIndependent()) {
135 
136     if (!MBB.isLiveIn(Mips::T9_64))
137       MBB.addLiveIn(Mips::T9_64);
138 
139     // T9 is trashed by this point, and we cannot trust saving
140     // the value from function entry on the stack, so calculate
141     // the address of the function entry using a pseudo
142     MCSymbol *BALTarget = MF.getContext().createTempSymbol();
143     BuildMI(MBB, MI, MBBDL, TII->get(Mips::RETGUARD_GET_FUNCTION_ADDR), Mips::T9_64)
144       .addReg(TempReg1)
145       .addReg(TempReg2)
146       .addSym(BALTarget);
147 
148     // TempReg1 loads the GOT pointer
149     // TempReg2 load the offset from GOT to random cookie pointer
150     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
151       .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
152     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
153       .addGlobalAddress(cookie, 0, MipsII::MO_GOT_HI16);
154     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
155       .addReg(TempReg1)
156       .addReg(Mips::T9_64);
157     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg2)
158       .addReg(TempReg2)
159       .addGlobalAddress(cookie, 0, MipsII::MO_GOT_LO16);
160     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
161       .addReg(TempReg1)
162       .addReg(TempReg2);
163     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1)
164       .addReg(TempReg1)
165       .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
166     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1)
167       .addReg(TempReg1)
168       .addImm(0);
169     // Verify the random cookie
170     BuildMI(MBB, MI, MBBDL, TII->get(Mips::TNE))
171       .addReg(TempReg1)
172       .addReg(REG)
173       .addImm(TRAPCODE);
174     // Emit the BAL target symbol from above
175     BuildMI(MBB, MI, MBBDL, TII->get(Mips::RETGUARD_EMIT_SYMBOL))
176       .addSym(BALTarget);
177   } else {
178     // TempReg1 loads the high 32 bits
179     // TempReg2 loads the low 32 bits
180     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
181       .addGlobalAddress(cookie, 0, MipsII::MO_HIGHEST);
182     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
183       .addGlobalAddress(cookie, 0, MipsII::MO_ABS_HI);
184     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg1)
185       .addReg(TempReg1)
186       .addGlobalAddress(cookie, 0, MipsII::MO_HIGHER);
187     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DSLL), TempReg1)
188       .addReg(TempReg1)
189       .addImm(32);
190     BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
191       .addReg(TempReg1)
192       .addReg(TempReg2);
193     BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1)
194       .addReg(TempReg1)
195       .addGlobalAddress(cookie, 0, MipsII::MO_ABS_LO);
196     // Verify the random cookie
197     BuildMI(MBB, MI, MBBDL, TII->get(Mips::TNE))
198       .addReg(TempReg1)
199       .addReg(REG)
200       .addImm(TRAPCODE);
201   }
202 }
203 
opcodeIsReturn(unsigned opcode) const204 bool MipsReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const {
205   switch (opcode) {
206     case Mips::RetRA:
207       return true;
208     default:
209       return false;
210   }
211 }
212 
fillTempRegisters(MachineFunction & MF,std::vector<unsigned> & TempRegs) const213 void MipsReturnProtectorLowering::fillTempRegisters(
214     MachineFunction &MF, std::vector<unsigned> &TempRegs) const {
215 
216   const Function &F = MF.getFunction();
217 
218   // long double arguments (f128) occupy two arg registers, so shift
219   // subsequent arguments down by one register
220   size_t shift_reg = 0;
221   for (const auto &arg : F.args()) {
222     if (arg.getType()->isFP128Ty())
223       shift_reg += 1;
224   }
225 
226   if (!F.isVarArg()) {
227     // We can use any of the caller saved unused arg registers
228     switch (F.arg_size() + shift_reg) {
229       case 0:
230         // A0 is used to return f128 values in soft float
231       case 1:
232         TempRegs.push_back(Mips::A1_64);
233         LLVM_FALLTHROUGH;
234       case 2:
235         TempRegs.push_back(Mips::A2_64);
236         LLVM_FALLTHROUGH;
237       case 3:
238         TempRegs.push_back(Mips::A3_64);
239         LLVM_FALLTHROUGH;
240       case 4:
241         TempRegs.push_back(Mips::T0_64);
242         LLVM_FALLTHROUGH;
243       case 5:
244         TempRegs.push_back(Mips::T1_64);
245         LLVM_FALLTHROUGH;
246       case 6:
247         TempRegs.push_back(Mips::T2_64);
248         LLVM_FALLTHROUGH;
249       case 7:
250         TempRegs.push_back(Mips::T3_64);
251         LLVM_FALLTHROUGH;
252       case 8:
253         TempRegs.push_back(Mips::T4_64);
254         LLVM_FALLTHROUGH;
255       case 9:
256         TempRegs.push_back(Mips::T5_64);
257         LLVM_FALLTHROUGH;
258       case 10:
259         TempRegs.push_back(Mips::T6_64);
260         LLVM_FALLTHROUGH;
261       case 11:
262         TempRegs.push_back(Mips::T7_64);
263         LLVM_FALLTHROUGH;
264       case 12:
265         TempRegs.push_back(Mips::T8_64);
266         LLVM_FALLTHROUGH;
267       default:
268         break;
269     }
270   }
271   // For FastCC this is the only scratch reg that isn't V0 or T9
272   TempRegs.push_back(Mips::AT_64);
273 }
274