LLVM 23.0.0git
AArch64MCLFIRewriter.cpp
Go to the documentation of this file.
1//===- AArch64MCLFIRewriter.cpp ---------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the AArch64MCLFIRewriter class, the AArch64 specific
10// subclass of MCLFIRewriter.
11//
12//===----------------------------------------------------------------------===//
13
18
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCStreamer.h"
22
23using namespace llvm;
24
25// LFI reserved registers.
26static constexpr MCRegister LFIBaseReg = AArch64::X27;
27static constexpr MCRegister LFIAddrReg = AArch64::X28;
28static constexpr MCRegister LFIScratchReg = AArch64::X26;
29static constexpr MCRegister LFICtxReg = AArch64::X25;
30
31// Offset into the context register block (pointed to by LFICtxReg) where the
32// thread pointer is stored. This is a scaled offset (multiplied by 8 for
33// 64-bit loads), so a value of 2 means an actual byte offset of 16.
34static constexpr unsigned LFITPOffset = 2;
35
36// Byte offset from the sandbox base register where the syscall handler address
37// is stored (negative because it is below the sandbox base).
38static constexpr int LFISyscallOffset = -8;
39
40static bool isSyscall(const MCInst &Inst) {
41 return Inst.getOpcode() == AArch64::SVC;
42}
43
44static bool isPrivilegedTP(int64_t Reg) {
45 return Reg == AArch64SysReg::TPIDR_EL1 || Reg == AArch64SysReg::TPIDR_EL2 ||
46 Reg == AArch64SysReg::TPIDR_EL3;
47}
48
49static bool isTPRead(const MCInst &Inst) {
50 return Inst.getOpcode() == AArch64::MRS &&
51 Inst.getOperand(1).getImm() == AArch64SysReg::TPIDR_EL0;
52}
53
54static bool isTPWrite(const MCInst &Inst) {
55 return Inst.getOpcode() == AArch64::MSR &&
56 Inst.getOperand(0).getImm() == AArch64SysReg::TPIDR_EL0;
57}
58
59static bool isPrivilegedTPAccess(const MCInst &Inst) {
60 if (Inst.getOpcode() == AArch64::MRS)
61 return isPrivilegedTP(Inst.getOperand(1).getImm());
62 if (Inst.getOpcode() == AArch64::MSR)
63 return isPrivilegedTP(Inst.getOperand(0).getImm());
64 return false;
65}
66
67bool AArch64MCLFIRewriter::mayModifyReserved(const MCInst &Inst) const {
68 return mayModifyRegister(Inst, LFIAddrReg) ||
71}
72
73void AArch64MCLFIRewriter::emitInst(const MCInst &Inst, MCStreamer &Out,
74 const MCSubtargetInfo &STI) {
75 Out.emitInstruction(Inst, STI);
76}
77
78void AArch64MCLFIRewriter::emitAddMask(MCRegister Dest, MCRegister Src,
79 MCStreamer &Out,
80 const MCSubtargetInfo &STI) {
81 // add Dest, LFIBaseReg, W(Src), uxtw
82 MCInst Inst;
83 Inst.setOpcode(AArch64::ADDXrx);
87 Inst.addOperand(
89 emitInst(Inst, Out, STI);
90}
91
92void AArch64MCLFIRewriter::emitBranch(unsigned Opcode, MCRegister Target,
93 MCStreamer &Out,
94 const MCSubtargetInfo &STI) {
95 MCInst Branch;
96 Branch.setOpcode(Opcode);
97 Branch.addOperand(MCOperand::createReg(Target));
98 emitInst(Branch, Out, STI);
99}
100
101void AArch64MCLFIRewriter::emitMov(MCRegister Dest, MCRegister Src,
102 MCStreamer &Out,
103 const MCSubtargetInfo &STI) {
104 // orr Dest, xzr, Src
105 MCInst Inst;
106 Inst.setOpcode(AArch64::ORRXrs);
108 Inst.addOperand(MCOperand::createReg(AArch64::XZR));
111 emitInst(Inst, Out, STI);
112}
113
114// svc #0
115// ->
116// mov x26, x30
117// ldur x30, [x27, #-8]
118// blr x30
119// add x30, x27, w26, uxtw
120void AArch64MCLFIRewriter::rewriteSyscall(const MCInst &, MCStreamer &Out,
121 const MCSubtargetInfo &STI) {
122 // Save LR to scratch.
123 emitMov(LFIScratchReg, AArch64::LR, Out, STI);
124
125 // Load syscall handler address from negative offset from sandbox base.
126 MCInst Load;
127 Load.setOpcode(AArch64::LDURXi);
128 Load.addOperand(MCOperand::createReg(AArch64::LR));
131 emitInst(Load, Out, STI);
132
133 // Call the runtime.
134 emitBranch(AArch64::BLR, AArch64::LR, Out, STI);
135
136 // Restore LR with guard.
137 emitAddMask(AArch64::LR, LFIScratchReg, Out, STI);
138}
139
140// mrs xN, tpidr_el0
141// ->
142// ldr xN, [x25, #16]
143void AArch64MCLFIRewriter::rewriteTPRead(const MCInst &Inst, MCStreamer &Out,
144 const MCSubtargetInfo &STI) {
145 MCRegister DestReg = Inst.getOperand(0).getReg();
146
147 MCInst Load;
148 Load.setOpcode(AArch64::LDRXui);
149 Load.addOperand(MCOperand::createReg(DestReg));
152 emitInst(Load, Out, STI);
153}
154
155// msr tpidr_el0, xN
156// ->
157// str xN, [x25, #16]
158void AArch64MCLFIRewriter::rewriteTPWrite(const MCInst &Inst, MCStreamer &Out,
159 const MCSubtargetInfo &STI) {
160 MCRegister SrcReg = Inst.getOperand(1).getReg();
161
162 MCInst Store;
163 Store.setOpcode(AArch64::STRXui);
164 Store.addOperand(MCOperand::createReg(SrcReg));
167 emitInst(Store, Out, STI);
168}
169
170// NOTE: when adding new rewrites, the size estimates in
171// AArch64InstrInfo::getLFIInstSizeInBytes must be updated to match.
172void AArch64MCLFIRewriter::doRewriteInst(const MCInst &Inst, MCStreamer &Out,
173 const MCSubtargetInfo &STI) {
174 // Reserved register modification is an error.
175 if (mayModifyReserved(Inst)) {
176 error(Inst, "illegal modification of reserved LFI register");
177 return;
178 }
179
180 // System instructions.
181 if (isSyscall(Inst))
182 return rewriteSyscall(Inst, Out, STI);
183
184 if (isTPRead(Inst))
185 return rewriteTPRead(Inst, Out, STI);
186
187 if (isTPWrite(Inst))
188 return rewriteTPWrite(Inst, Out, STI);
189
190 if (isPrivilegedTPAccess(Inst)) {
191 error(Inst, "illegal access to privileged thread pointer register");
192 return;
193 }
194
195 emitInst(Inst, Out, STI);
196}
197
199 const MCSubtargetInfo &STI) {
200 // The guard prevents rewrite-recursion when we emit instructions from inside
201 // the rewriter (such instructions should not be rewritten).
202 if (!Enabled || Guard)
203 return false;
204 Guard = true;
205
206 doRewriteInst(Inst, Out, STI);
207
208 Guard = false;
209 return true;
210}
static constexpr unsigned LFITPOffset
static constexpr MCRegister LFIScratchReg
static bool isPrivilegedTPAccess(const MCInst &Inst)
static constexpr MCRegister LFICtxReg
static bool isPrivilegedTP(int64_t Reg)
static bool isTPRead(const MCInst &Inst)
static bool isSyscall(const MCInst &Inst)
static constexpr MCRegister LFIAddrReg
static constexpr MCRegister LFIBaseReg
static constexpr int LFISyscallOffset
static bool isTPWrite(const MCInst &Inst)
Register Reg
#define error(X)
bool rewriteInst(const MCInst &Inst, MCStreamer &Out, const MCSubtargetInfo &STI) override
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
unsigned getOpcode() const
Definition MCInst.h:202
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
const MCOperand & getOperand(unsigned i) const
Definition MCInst.h:210
LLVM_ABI bool mayModifyRegister(const MCInst &Inst, MCRegister Reg) const
int64_t getImm() const
Definition MCInst.h:84
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
MCRegister getReg() const
Returns the register number.
Definition MCInst.h:73
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
Generic base class for all target subtargets.
Target - Wrapper for Target specific information.
static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)
getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...
This is an optimization pass for GlobalISel generic memory operations.
static MCRegister getWRegFromXReg(MCRegister Reg)