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
22namespace llvm {
23class MCContext;
24class MCExpr;
25class MCInst;
26class MCOperand;
27class MCStreamer;
28class MCSubtargetInfo;
29
30/// Rewrites AArch64 instructions for LFI sandboxing.
31///
32/// This class implements the LFI (Lightweight Fault Isolation) rewriting
33/// for AArch64 instructions. It transforms instructions to ensure memory
34/// accesses and control flow are confined within the sandbox region.
35///
36/// Reserved registers:
37/// - X27: Sandbox base address (always holds the base)
38/// - X28: Safe address register (always within sandbox)
39/// - X26: Scratch register for intermediate calculations
40/// - X25: context register (points to thread-local runtime data)
41/// - SP: Stack pointer (always within sandbox)
42/// - X30: Link register (always within sandbox)
43class AArch64MCLFIRewriter : public MCLFIRewriter {
44public:
45 AArch64MCLFIRewriter(MCContext &Ctx, std::unique_ptr<MCRegisterInfo> &&RI,
46 std::unique_ptr<MCInstrInfo> &&II)
47 : MCLFIRewriter(Ctx, std::move(RI), std::move(II)) {}
48
49 bool rewriteInst(const MCInst &Inst, MCStreamer &Out,
50 const MCSubtargetInfo &STI) override;
51
52private:
53 /// Recursion guard to prevent infinite loops when emitting instructions.
54 bool Guard = false;
55
56 /// Deferred `.tlsdesccall` symbol. The directive attaches a
57 /// R_AARCH64_TLSDESC_CALL relocation to the following BLR. Since LFI inserts
58 /// a guard before that BLR, the marker is deferred and re-emitted between
59 /// the guard and the branch so the relocation stays on the BLR.
60 const MCExpr *PendingTLSDescCall = nullptr;
61
62 // Instruction classification. Returns the reserved register that may be
63 // modified, or an invalid register if no reserved register is touched.
64 MCRegister mayModifyReserved(const MCInst &Inst) const;
65 bool mayModifySP(const MCInst &Inst) const;
66
67 // Instruction emission.
68 void emitInst(const MCInst &Inst, MCStreamer &Out,
69 const MCSubtargetInfo &STI);
70 void emitAddMask(MCRegister Dest, MCRegister Src, MCStreamer &Out,
71 const MCSubtargetInfo &STI);
72 void emitBranch(unsigned Opcode, MCRegister Target, MCStreamer &Out,
73 const MCSubtargetInfo &STI);
74 void emitPendingTLSDescCall(MCStreamer &Out, const MCSubtargetInfo &STI);
75 void emitMov(MCRegister Dest, MCRegister Src, MCStreamer &Out,
76 const MCSubtargetInfo &STI);
77 void emitAddImm(MCRegister Dest, MCRegister Src, int64_t Imm, MCStreamer &Out,
78 const MCSubtargetInfo &STI);
79 void emitAddReg(MCRegister Dest, MCRegister Src1, MCRegister Src2,
80 unsigned Shift, MCStreamer &Out, const MCSubtargetInfo &STI);
81 void emitAddRegExtend(MCRegister Dest, MCRegister Src1, MCRegister Src2,
82 AArch64_AM::ShiftExtendType ExtType, unsigned Shift,
83 MCStreamer &Out, const MCSubtargetInfo &STI);
84 void emitMemRoW(unsigned Opcode, const MCOperand &DataOp, MCRegister BaseReg,
85 MCStreamer &Out, const MCSubtargetInfo &STI);
86
87 // Rewriting logic.
88 void doRewriteInst(const MCInst &Inst, MCStreamer &Out,
89 const MCSubtargetInfo &STI);
90
91 // Control flow.
92 void rewriteIndirectBranch(const MCInst &Inst, MCStreamer &Out,
93 const MCSubtargetInfo &STI);
94 void rewriteReturn(const MCInst &Inst, MCStreamer &Out,
95 const MCSubtargetInfo &STI);
96
97 // Memory access.
98 void rewriteLoadStore(const MCInst &Inst, MCStreamer &Out,
99 const MCSubtargetInfo &STI);
100 void rewriteLoadStoreBase(const MCInst &Inst, MCStreamer &Out,
101 const MCSubtargetInfo &STI);
102 bool rewriteLoadStoreRoW(const MCInst &Inst, MCStreamer &Out,
103 const MCSubtargetInfo &STI);
104
105 // SP register modification.
106 void rewriteSPModification(const MCInst &Inst, MCStreamer &Out,
107 const MCSubtargetInfo &STI);
108
109 // Link register modification.
110 void rewriteLRModification(const MCInst &Inst, MCStreamer &Out,
111 const MCSubtargetInfo &STI);
112
113 // System instructions.
114 void rewriteSyscall(const MCInst &Inst, MCStreamer &Out,
115 const MCSubtargetInfo &STI);
116 void rewriteTPRead(const MCInst &Inst, MCStreamer &Out,
117 const MCSubtargetInfo &STI);
118 void rewriteTPWrite(const MCInst &Inst, MCStreamer &Out,
119 const MCSubtargetInfo &STI);
120 void rewriteVASysOp(const MCInst &Inst, MCStreamer &Out,
121 const MCSubtargetInfo &STI);
122};
123
124/// Returns true if \p Opcode is a pre- or post-indexed memory access that the
125/// LFI rewriter expands with a base-register update (i.e. an extra
126/// instruction beyond the guard + access pair).
127bool isLFIPrePostMemAccess(unsigned Opcode);
128
129} // namespace llvm
130
131#endif // LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64MCLFIREWRITER_H
132