1//===- AArch64MCLFIRewriter.h -----------------------------------*- 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 declares the AArch64MCLFIRewriter class, the AArch64 specific
10// subclass of MCLFIRewriter.
11//
12//===----------------------------------------------------------------------===//
13#ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64MCLFIREWRITER_H
14#define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64MCLFIREWRITER_H
15
16#include "AArch64AddressingModes.h"
17#include "llvm/MC/MCInstrInfo.h"
18#include "llvm/MC/MCLFIRewriter.h"
19#include "llvm/MC/MCRegister.h"
20#include "llvm/MC/MCRegisterInfo.h"
21
22#include <optional>
23
24namespace llvm {
25class MCContext;
26class MCExpr;
27class MCInst;
28class MCOperand;
29class MCStreamer;
30class MCSubtargetInfo;
31class MCSymbol;
32
33/// Rewrites AArch64 instructions for LFI sandboxing.
34///
35/// This class implements the LFI (Lightweight Fault Isolation) rewriting
36/// for AArch64 instructions. It transforms instructions to ensure memory
37/// accesses and control flow are confined within the sandbox region.
38///
39/// Reserved registers:
40/// - X27: Sandbox base address (always holds the base)
41/// - X28: Safe address register (always within sandbox)
42/// - X26: Scratch register for intermediate calculations
43/// - X25: context register (points to thread-local runtime data)
44/// - SP: Stack pointer (always within sandbox)
45/// - X30: Link register (always within sandbox)
46class AArch64MCLFIRewriter : public MCLFIRewriter {
47public:
48 AArch64MCLFIRewriter(MCContext &Ctx, std::unique_ptr<MCRegisterInfo> &&RI,
49 std::unique_ptr<MCInstrInfo> &&II)
50 : MCLFIRewriter(Ctx, std::move(RI), std::move(II)) {}
51
52 bool rewriteInst(const MCInst &Inst, MCStreamer &Out,
53 const MCSubtargetInfo &STI) override;
54
55 void onLabel(const MCSymbol *Symbol, MCStreamer &Out) override;
56 void finish(MCStreamer &Out) override;
57
58private:
59 /// Recursion guard to prevent infinite loops when emitting instructions.
60 bool Guard = false;
61
62 /// When set, an instruction has modified the link register but its guard
63 /// (`add x30, x27, w30, uxtw`) has not been emitted yet. The guard is
64 /// deferred until the next control-flow instruction so that pointer
65 /// authentication can run on the signed value before the mask overwrites the
66 /// upper bits of the pointer.
67 bool DeferredLRGuard = false;
68
69 /// Most recently seen MCSubtargetInfo.
70 const MCSubtargetInfo *LastSTI = nullptr;
71
72 /// Deferred `.tlsdesccall` symbol. The directive attaches a
73 /// R_AARCH64_TLSDESC_CALL relocation to the following BLR. Since LFI inserts
74 /// a guard before that BLR, the marker is deferred and re-emitted between
75 /// the guard and the branch so the relocation stays on the BLR.
76 const MCExpr *PendingTLSDescCall = nullptr;
77
78 /// Rewriter state for implementing the guard-elimination optimization, which
79 /// allows redundant add masks to be skipped. When it holds a value, x28 is
80 /// known to already hold the guarded value of that register.
81 std::optional<MCRegister> ActiveGuardReg;
82
83 // Instruction classification. Returns the reserved register that may be
84 // modified, or an invalid register if no reserved register is touched.
85 MCRegister mayModifyReserved(const MCInst &Inst) const;
86 bool mayModifySP(const MCInst &Inst) const;
87
88 // Instruction emission.
89 void emitInst(const MCInst &Inst, MCStreamer &Out,
90 const MCSubtargetInfo &STI);
91 void emitAddMask(MCRegister Dest, MCRegister Src, MCStreamer &Out,
92 const MCSubtargetInfo &STI);
93 void emitBranch(unsigned Opcode, MCRegister Target, MCStreamer &Out,
94 const MCSubtargetInfo &STI);
95 void emitPendingTLSDescCall(MCStreamer &Out, const MCSubtargetInfo &STI);
96 void emitMov(MCRegister Dest, MCRegister Src, MCStreamer &Out,
97 const MCSubtargetInfo &STI);
98 void emitAddImm(MCRegister Dest, MCRegister Src, int64_t Imm, MCStreamer &Out,
99 const MCSubtargetInfo &STI);
100 void emitAddReg(MCRegister Dest, MCRegister Src1, MCRegister Src2,
101 unsigned Shift, MCStreamer &Out, const MCSubtargetInfo &STI);
102 void emitAddRegExtend(MCRegister Dest, MCRegister Src1, MCRegister Src2,
103 AArch64_AM::ShiftExtendType ExtType, unsigned Shift,
104 MCStreamer &Out, const MCSubtargetInfo &STI);
105 void emitMemRoW(unsigned Opcode, const MCOperand &DataOp, MCRegister BaseReg,
106 MCStreamer &Out, const MCSubtargetInfo &STI);
107
108 // Rewriting logic.
109 void doRewriteInst(const MCInst &Inst, MCStreamer &Out,
110 const MCSubtargetInfo &STI);
111
112 // Control flow.
113 void rewriteIndirectBranch(const MCInst &Inst, MCStreamer &Out,
114 const MCSubtargetInfo &STI);
115 void rewriteReturn(const MCInst &Inst, MCStreamer &Out,
116 const MCSubtargetInfo &STI);
117
118 // Memory access.
119 void rewriteLoadStore(const MCInst &Inst, MCStreamer &Out,
120 const MCSubtargetInfo &STI);
121 void rewriteLoadStoreBase(const MCInst &Inst, MCStreamer &Out,
122 const MCSubtargetInfo &STI);
123 bool rewriteLoadStoreRoW(const MCInst &Inst, MCStreamer &Out,
124 const MCSubtargetInfo &STI);
125
126 // SP register modification.
127 void rewriteSPModification(const MCInst &Inst, MCStreamer &Out,
128 const MCSubtargetInfo &STI);
129
130 // Link register modification.
131 void rewriteLRModification(const MCInst &Inst, MCStreamer &Out,
132 const MCSubtargetInfo &STI);
133
134 // PAC instructions.
135 void rewriteAuthenticatedReturn(const MCInst &Inst, MCStreamer &Out,
136 const MCSubtargetInfo &STI);
137 void rewriteAuthenticatedBranchOrCall(const MCInst &Inst,
138 unsigned BranchOpcode, MCStreamer &Out,
139 const MCSubtargetInfo &STI);
140
141 // System instructions.
142 void rewriteSyscall(const MCInst &Inst, MCStreamer &Out,
143 const MCSubtargetInfo &STI);
144 void rewriteTPRead(const MCInst &Inst, MCStreamer &Out,
145 const MCSubtargetInfo &STI);
146 void rewriteTPWrite(const MCInst &Inst, MCStreamer &Out,
147 const MCSubtargetInfo &STI);
148 void rewriteVASysOp(const MCInst &Inst, MCStreamer &Out,
149 const MCSubtargetInfo &STI);
150};
151
152/// Returns true if \p Opcode is a pre- or post-indexed memory access that the
153/// LFI rewriter expands with a base-register update (i.e. an extra
154/// instruction beyond the guard + access pair).
155bool isLFIPrePostMemAccess(unsigned Opcode);
156
157} // namespace llvm
158
159#endif // LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64MCLFIREWRITER_H
160