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