xref: /openbsd-src/gnu/llvm/llvm/lib/Target/AArch64/AArch64ReturnProtectorLowering.cpp (revision 7ad5461f799970718c4793a8bad4551354110c5a)
1 //===-- AArch64ReturnProtectorLowering.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 AArch64 implementation of ReturnProtectorLowering
11 // class.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "AArch64InstrInfo.h"
16 #include "AArch64MachineFunctionInfo.h"
17 #include "AArch64RegisterInfo.h"
18 #include "AArch64ReturnProtectorLowering.h"
19 #include "AArch64Subtarget.h"
20 #include "AArch64TargetMachine.h"
21 #include "llvm/CodeGen/MachineFunction.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/MachineModuleInfo.h"
24 #include "llvm/CodeGen/MachineRegisterInfo.h"
25 #include "llvm/IR/Function.h"
26 #include "llvm/MC/MCAsmInfo.h"
27 #include "llvm/MC/MCSymbol.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Target/TargetOptions.h"
30 #include <cstdlib>
31 
32 using namespace llvm;
33 
insertReturnProtectorPrologue(MachineFunction & MF,MachineBasicBlock & MBB,GlobalVariable * cookie) const34 void AArch64ReturnProtectorLowering::insertReturnProtectorPrologue(
35     MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const {
36 
37   MachineBasicBlock::instr_iterator MI = MBB.instr_begin();
38   DebugLoc MBBDL = MBB.findDebugLoc(MI);
39   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
40   unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
41 
42   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ADRP), REG)
43       .addGlobalAddress(cookie, 0, AArch64II::MO_PAGE);
44   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::LDRXui), REG)
45       .addReg(REG)
46       .addGlobalAddress(cookie, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
47   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::EORXrr), REG)
48       .addReg(REG)
49       .addReg(AArch64::LR);
50 }
51 
insertReturnProtectorEpilogue(MachineFunction & MF,MachineInstr & MI,GlobalVariable * cookie) const52 void AArch64ReturnProtectorLowering::insertReturnProtectorEpilogue(
53     MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const {
54 
55   MachineBasicBlock &MBB = *MI.getParent();
56   DebugLoc MBBDL = MI.getDebugLoc();
57   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
58   unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
59 
60   MBB.addLiveIn(AArch64::X9);
61   // REG holds the cookie we calculated in prologue. We use X9 as a
62   // scratch reg to pull the random data. XOR REG with LR should yield
63   // the random data again. Compare REG with X9 to check.
64   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::EORXrr), REG)
65       .addReg(REG)
66       .addReg(AArch64::LR);
67   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ADRP), AArch64::X9)
68       .addGlobalAddress(cookie, 0, AArch64II::MO_PAGE);
69   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::LDRXui), AArch64::X9)
70       .addReg(AArch64::X9)
71       .addGlobalAddress(cookie, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
72   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::SUBSXrr), REG)
73       .addReg(REG)
74       .addReg(AArch64::X9);
75   BuildMI(MBB, MI, MBBDL, TII->get(AArch64::RETGUARD_JMP_TRAP)).addReg(REG);
76 }
77 
opcodeIsReturn(unsigned opcode) const78 bool AArch64ReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const {
79   switch (opcode) {
80   case AArch64::RET:
81   case AArch64::RET_ReallyLR:
82     return true;
83   default:
84     return false;
85   }
86 }
87 
fillTempRegisters(MachineFunction & MF,std::vector<unsigned> & TempRegs) const88 void AArch64ReturnProtectorLowering::fillTempRegisters(
89     MachineFunction &MF, std::vector<unsigned> &TempRegs) const {
90 
91   TempRegs.push_back(AArch64::X15);
92   TempRegs.push_back(AArch64::X14);
93   TempRegs.push_back(AArch64::X13);
94   TempRegs.push_back(AArch64::X12);
95   TempRegs.push_back(AArch64::X11);
96   TempRegs.push_back(AArch64::X10);
97 }
98 
saveReturnProtectorRegister(MachineFunction & MF,std::vector<CalleeSavedInfo> & CSI) const99 void AArch64ReturnProtectorLowering::saveReturnProtectorRegister(
100     MachineFunction &MF, std::vector<CalleeSavedInfo> &CSI) const {
101 
102   const MachineFrameInfo &MFI = MF.getFrameInfo();
103   if (!MFI.getReturnProtectorNeeded())
104     return;
105 
106   if (!MFI.hasReturnProtectorRegister())
107     llvm_unreachable("Saving unset return protector register");
108 
109   unsigned Reg = MFI.getReturnProtectorRegister();
110   if (!MFI.getReturnProtectorNeedsStore()) {
111     for (auto &MBB : MF) {
112       if (!MBB.isLiveIn(Reg))
113         MBB.addLiveIn(Reg);
114     }
115     return;
116   }
117 
118   // CSI Reg order is important for pairing registers later.
119   // The expected order of the CSI is given by getCalleeSavedRegs(),
120   // which for us returns a list of GPRs and FPRs in ascending
121   // order. Since our temp regs are all before the usual callee
122   // saved regs, we can just insert our reg first.
123   CSI.insert(CSI.begin(), CalleeSavedInfo(MFI.getReturnProtectorRegister()));
124 }
125