xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp (revision 5ab43c3e7d9b5dc0ca4fffa58c65fc6f7283d3c0)
12ed91da0SStefan Gränitz //===---- aarch64.cpp - Generic JITLink aarch64 edge kinds, utilities -----===//
22ed91da0SStefan Gränitz //
32ed91da0SStefan Gränitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42ed91da0SStefan Gränitz // See https://llvm.org/LICENSE.txt for license information.
52ed91da0SStefan Gränitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62ed91da0SStefan Gränitz //
72ed91da0SStefan Gränitz //===----------------------------------------------------------------------===//
82ed91da0SStefan Gränitz //
92ed91da0SStefan Gränitz // Generic utilities for graphs representing aarch64 objects.
102ed91da0SStefan Gränitz //
112ed91da0SStefan Gränitz //===----------------------------------------------------------------------===//
122ed91da0SStefan Gränitz 
132ed91da0SStefan Gränitz #include "llvm/ExecutionEngine/JITLink/aarch64.h"
142ed91da0SStefan Gränitz 
15a432f11aSLang Hames #include "llvm/Support/BinaryStreamWriter.h"
16a432f11aSLang Hames 
172ed91da0SStefan Gränitz #define DEBUG_TYPE "jitlink"
182ed91da0SStefan Gränitz 
192ed91da0SStefan Gränitz namespace llvm {
202ed91da0SStefan Gränitz namespace jitlink {
212ed91da0SStefan Gränitz namespace aarch64 {
222ed91da0SStefan Gränitz 
23b5d58137SLang Hames const char NullPointerContent[8] = {0x00, 0x00, 0x00, 0x00,
24db372258SSunho Kim                                     0x00, 0x00, 0x00, 0x00};
25db372258SSunho Kim 
265af9e648SLang Hames const char PointerJumpStubContent[12] = {
275af9e648SLang Hames     0x10, 0x00, 0x00, (char)0x90u, // ADRP x16, <imm>@page21
285af9e648SLang Hames     0x10, 0x02, 0x40, (char)0xf9u, // LDR x16, [x16, <imm>@pageoff12]
295af9e648SLang Hames     0x00, 0x02, 0x1f, (char)0xd6u  // BR  x16
30db372258SSunho Kim };
31db372258SSunho Kim 
32f2d18a4dSLang Hames const char ReentryTrampolineContent[8] = {
33f2d18a4dSLang Hames     (char)0xfd, 0x7b, (char)0xbf, (char)0xa9, // STP x30, [sp, #-8]
34f2d18a4dSLang Hames     0x00,       0x00, 0x00,       (char)0x94  // BL
35f2d18a4dSLang Hames };
36f2d18a4dSLang Hames 
37b6553f59SSunho Kim const char *getEdgeKindName(Edge::Kind R) {
38b6553f59SSunho Kim   switch (R) {
39b6553f59SSunho Kim   case Pointer64:
40b6553f59SSunho Kim     return "Pointer64";
419c1d2f84SLang Hames   case Pointer64Authenticated:
429c1d2f84SLang Hames     return "Pointer64Authenticated";
43cb33ef7cSLang Hames   case Pointer32:
44cb33ef7cSLang Hames     return "Pointer32";
45cb33ef7cSLang Hames   case Delta64:
46cb33ef7cSLang Hames     return "Delta64";
47cb33ef7cSLang Hames   case Delta32:
48cb33ef7cSLang Hames     return "Delta32";
49cb33ef7cSLang Hames   case NegDelta64:
50cb33ef7cSLang Hames     return "NegDelta64";
51cb33ef7cSLang Hames   case NegDelta32:
52cb33ef7cSLang Hames     return "NegDelta32";
53cb33ef7cSLang Hames   case Branch26PCRel:
54cb33ef7cSLang Hames     return "Branch26PCRel";
55cb33ef7cSLang Hames   case MoveWide16:
56cb33ef7cSLang Hames     return "MoveWide16";
57cb33ef7cSLang Hames   case LDRLiteral19:
58cb33ef7cSLang Hames     return "LDRLiteral19";
59a9a2eb81SJob Noorman   case TestAndBranch14PCRel:
60a9a2eb81SJob Noorman     return "TestAndBranch14PCRel";
61193a8092SJob Noorman   case CondBranch19PCRel:
62193a8092SJob Noorman     return "CondBranch19PCRel";
63e9676389SJob Noorman   case ADRLiteral21:
64e9676389SJob Noorman     return "ADRLiteral21";
65b6553f59SSunho Kim   case Page21:
66b6553f59SSunho Kim     return "Page21";
67b6553f59SSunho Kim   case PageOffset12:
68b6553f59SSunho Kim     return "PageOffset12";
69199c4003SVladislav Khmelevsky   case GotPageOffset15:
70199c4003SVladislav Khmelevsky     return "GotPageOffset15";
71cb33ef7cSLang Hames   case RequestGOTAndTransformToPage21:
72cb33ef7cSLang Hames     return "RequestGOTAndTransformToPage21";
73cb33ef7cSLang Hames   case RequestGOTAndTransformToPageOffset12:
74cb33ef7cSLang Hames     return "RequestGOTAndTransformToPageOffset12";
75199c4003SVladislav Khmelevsky   case RequestGOTAndTransformToPageOffset15:
76199c4003SVladislav Khmelevsky     return "RequestGOTAndTransformToPageOffset15";
77cb33ef7cSLang Hames   case RequestGOTAndTransformToDelta32:
78cb33ef7cSLang Hames     return "RequestGOTAndTransformToDelta32";
79cb33ef7cSLang Hames   case RequestTLVPAndTransformToPage21:
80cb33ef7cSLang Hames     return "RequestTLVPAndTransformToPage21";
81cb33ef7cSLang Hames   case RequestTLVPAndTransformToPageOffset12:
82cb33ef7cSLang Hames     return "RequestTLVPAndTransformToPageOffset12";
83cb33ef7cSLang Hames   case RequestTLSDescEntryAndTransformToPage21:
84cb33ef7cSLang Hames     return "RequestTLSDescEntryAndTransformToPage21";
85cb33ef7cSLang Hames   case RequestTLSDescEntryAndTransformToPageOffset12:
86cb33ef7cSLang Hames     return "RequestTLSDescEntryAndTransformToPageOffset12";
87b6553f59SSunho Kim   default:
88b6553f59SSunho Kim     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
89b6553f59SSunho Kim   }
90b6553f59SSunho Kim }
91b6553f59SSunho Kim 
92a432f11aSLang Hames // Write a 64-bit GPR -> GPR move.
93a432f11aSLang Hames template <typename AppendFtor>
94a432f11aSLang Hames static Error writeMovRegRegSeq(AppendFtor &Append, uint64_t DstReg,
95a432f11aSLang Hames                                uint64_t SrcReg) {
96a432f11aSLang Hames   assert(DstReg < 32 && "Dst reg out of range");
97a432f11aSLang Hames   assert(SrcReg < 32 && "Src reg out of range");
98a432f11aSLang Hames 
99a432f11aSLang Hames   if (DstReg == SrcReg)
100a432f11aSLang Hames     return Error::success();
101a432f11aSLang Hames 
102a432f11aSLang Hames   constexpr uint32_t MOVGPR64Template = 0xaa0003e0;
103a432f11aSLang Hames   constexpr uint32_t DstRegIndex = 0;
104a432f11aSLang Hames   constexpr uint32_t SrcRegIndex = 16;
105a432f11aSLang Hames   uint32_t Instr = MOVGPR64Template;
106a432f11aSLang Hames   Instr |= DstReg << DstRegIndex;
107a432f11aSLang Hames   Instr |= SrcReg << SrcRegIndex;
108a432f11aSLang Hames   return Append(Instr);
109a432f11aSLang Hames }
110a432f11aSLang Hames 
111a432f11aSLang Hames // Generate a sequence of imm writes to assign the given value.
112a432f11aSLang Hames template <typename AppendFtor>
113a432f11aSLang Hames static Error writeMovRegImm64Seq(AppendFtor &Append, uint64_t Reg,
114a432f11aSLang Hames                                  uint64_t Imm) {
115a432f11aSLang Hames   assert(Reg < 32 && "Invalid register number");
116a432f11aSLang Hames 
117a432f11aSLang Hames   constexpr uint32_t MovRegImm64Template = 0xd2800000;
118a432f11aSLang Hames   constexpr unsigned PreserveBitIndex = 29;
119a432f11aSLang Hames   constexpr unsigned ShiftBitsIndex = 21;
120a432f11aSLang Hames   constexpr unsigned ImmBitsIndex = 5;
121a432f11aSLang Hames 
122a432f11aSLang Hames   bool PreserveRegValue = false;
123a432f11aSLang Hames   for (unsigned I = 0; I != 4; ++I) {
124a432f11aSLang Hames     uint32_t ImmBits = Imm & 0xffff;
125a432f11aSLang Hames     Imm >>= 16;
126a432f11aSLang Hames 
127a432f11aSLang Hames     // Skip any all-zero immediates after the first one.
128a432f11aSLang Hames     if (PreserveRegValue && !ImmBits)
129a432f11aSLang Hames       continue;
130a432f11aSLang Hames 
131a432f11aSLang Hames     uint32_t Instr = MovRegImm64Template;
132a432f11aSLang Hames     Instr |= PreserveRegValue << PreserveBitIndex;
133a432f11aSLang Hames     Instr |= (I << ShiftBitsIndex);
134a432f11aSLang Hames     Instr |= ImmBits << ImmBitsIndex;
135a432f11aSLang Hames     Instr |= Reg;
136a432f11aSLang Hames     if (auto Err = Append(Instr))
137a432f11aSLang Hames       return Err;
138a432f11aSLang Hames     PreserveRegValue = true;
139a432f11aSLang Hames   }
140a432f11aSLang Hames 
141a432f11aSLang Hames   return Error::success();
142a432f11aSLang Hames }
143a432f11aSLang Hames 
144a432f11aSLang Hames template <typename AppendFtor>
145a432f11aSLang Hames static Error
146a432f11aSLang Hames writePACSignSeq(AppendFtor &Append, unsigned DstReg, orc::ExecutorAddr RawAddr,
147a432f11aSLang Hames                 unsigned RawAddrReg, unsigned DiscriminatorReg, unsigned Key,
148a432f11aSLang Hames                 uint64_t EncodedDiscriminator, bool AddressDiversify) {
149a432f11aSLang Hames   assert(DstReg < 32 && "DstReg out of range");
150a432f11aSLang Hames   assert(RawAddrReg < 32 && "AddrReg out of range");
151a432f11aSLang Hames   assert(DiscriminatorReg < 32 && "DiscriminatorReg out of range");
152a432f11aSLang Hames   assert(EncodedDiscriminator < 0x10000 && "EncodedDiscriminator out of range");
153a432f11aSLang Hames 
154a432f11aSLang Hames   if (AddressDiversify) {
155a432f11aSLang Hames     // Move the address into the discriminator register.
156a432f11aSLang Hames     if (auto Err = writeMovRegRegSeq(Append, DiscriminatorReg, RawAddrReg))
157a432f11aSLang Hames       return Err;
158a432f11aSLang Hames     // Blend encoded discriminator if there is one.
159a432f11aSLang Hames     if (EncodedDiscriminator) {
160a432f11aSLang Hames       constexpr uint32_t MOVKTemplate = 0xf2e00000;
161a432f11aSLang Hames       constexpr unsigned ImmIndex = 5;
162a432f11aSLang Hames       uint32_t BlendInstr = MOVKTemplate;
163a432f11aSLang Hames       BlendInstr |= EncodedDiscriminator << ImmIndex;
164a432f11aSLang Hames       BlendInstr |= DiscriminatorReg;
165a432f11aSLang Hames       if (auto Err = Append(BlendInstr))
166a432f11aSLang Hames         return Err;
167a432f11aSLang Hames     }
168a432f11aSLang Hames   } else if (EncodedDiscriminator) {
169a432f11aSLang Hames     // Move the encoded discriminator into the discriminator register.
170a432f11aSLang Hames     if (auto Err =
171a432f11aSLang Hames             writeMovRegImm64Seq(Append, DiscriminatorReg, EncodedDiscriminator))
172a432f11aSLang Hames       return Err;
173a432f11aSLang Hames   } else
174a432f11aSLang Hames     DiscriminatorReg = 31; // WZR
175a432f11aSLang Hames 
176a432f11aSLang Hames   constexpr uint32_t PACTemplate = 0xdac10000;
177a432f11aSLang Hames   constexpr unsigned ZBitIndex = 13;
178a432f11aSLang Hames   constexpr unsigned KeyIndex = 10;
179a432f11aSLang Hames   constexpr unsigned DiscriminatorRegIndex = 5;
180a432f11aSLang Hames 
181a432f11aSLang Hames   uint32_t Instr = PACTemplate;
182a432f11aSLang Hames   Instr |= (DiscriminatorReg == 31) << ZBitIndex;
183a432f11aSLang Hames   Instr |= Key << KeyIndex;
184a432f11aSLang Hames   Instr |= DiscriminatorReg << DiscriminatorRegIndex;
185a432f11aSLang Hames   Instr |= DstReg;
186a432f11aSLang Hames 
187a432f11aSLang Hames   return Append(Instr);
188a432f11aSLang Hames }
189a432f11aSLang Hames 
190a432f11aSLang Hames template <typename AppendFtor>
191a432f11aSLang Hames static Error writeStoreRegSeq(AppendFtor &Append, unsigned DstLocReg,
192a432f11aSLang Hames                               unsigned SrcReg) {
193a432f11aSLang Hames   assert(DstLocReg < 32 && "DstLocReg out of range");
194a432f11aSLang Hames   assert(SrcReg < 32 && "SrcReg out of range");
195a432f11aSLang Hames 
196a432f11aSLang Hames   constexpr uint32_t STRTemplate = 0xf9000000;
197a432f11aSLang Hames   constexpr unsigned DstLocRegIndex = 5;
198a432f11aSLang Hames   constexpr unsigned SrcRegIndex = 0;
199a432f11aSLang Hames 
200a432f11aSLang Hames   uint32_t Instr = STRTemplate;
201a432f11aSLang Hames   Instr |= DstLocReg << DstLocRegIndex;
202a432f11aSLang Hames   Instr |= SrcReg << SrcRegIndex;
203a432f11aSLang Hames 
204a432f11aSLang Hames   return Append(Instr);
205a432f11aSLang Hames }
206a432f11aSLang Hames 
20742595bdaSLang Hames void GOTTableManager::registerExistingEntries() {
20842595bdaSLang Hames   for (auto *EntrySym : GOTSection->symbols()) {
20942595bdaSLang Hames     assert(EntrySym->getBlock().edges_size() == 1 &&
21042595bdaSLang Hames            "GOT block edge count != 1");
21142595bdaSLang Hames     registerPreExistingEntry(EntrySym->getBlock().edges().begin()->getTarget(),
21242595bdaSLang Hames                              *EntrySym);
21342595bdaSLang Hames   }
21442595bdaSLang Hames }
21542595bdaSLang Hames 
21642595bdaSLang Hames void PLTTableManager::registerExistingEntries() {
21742595bdaSLang Hames   for (auto *EntrySym : StubsSection->symbols()) {
21842595bdaSLang Hames     assert(EntrySym->getBlock().edges_size() == 2 &&
21942595bdaSLang Hames            "PLT block edge count != 2");
22042595bdaSLang Hames     auto &GOTSym = EntrySym->getBlock().edges().begin()->getTarget();
22142595bdaSLang Hames     assert(GOTSym.getBlock().edges_size() == 1 && "GOT block edge count != 1");
22242595bdaSLang Hames     registerPreExistingEntry(GOTSym.getBlock().edges().begin()->getTarget(),
22342595bdaSLang Hames                              *EntrySym);
22442595bdaSLang Hames   }
22542595bdaSLang Hames }
22642595bdaSLang Hames 
227a432f11aSLang Hames const char *getPointerSigningFunctionSectionName() { return "$__ptrauth_sign"; }
228a432f11aSLang Hames 
229a432f11aSLang Hames /// Creates a pointer signing function section, block, and symbol to reserve
230a432f11aSLang Hames /// space for a signing function for this LinkGraph. Clients should insert this
231a432f11aSLang Hames /// pass in the post-prune phase, and add the paired
232a432f11aSLang Hames /// lowerPointer64AuthEdgesToSigningFunction pass to the pre-fixup phase.
233a432f11aSLang Hames Error createEmptyPointerSigningFunction(LinkGraph &G) {
234a432f11aSLang Hames   LLVM_DEBUG({
235a432f11aSLang Hames     dbgs() << "Creating empty pointer signing function for " << G.getName()
236a432f11aSLang Hames            << "\n";
237a432f11aSLang Hames   });
238a432f11aSLang Hames 
239a432f11aSLang Hames   // FIXME: We could put a tighter bound on this if we inspected the ptrauth
240a432f11aSLang Hames   // info encoded in the addend -- the only actually unknown quantity is the
241a432f11aSLang Hames   // fixup location, and we can probably put constraints even on that.
242a432f11aSLang Hames   size_t NumPtrAuthFixupLocations = 0;
243a432f11aSLang Hames   for (auto *B : G.blocks())
244a432f11aSLang Hames     for (auto &E : B->edges())
245a432f11aSLang Hames       NumPtrAuthFixupLocations +=
246a432f11aSLang Hames           E.getKind() == aarch64::Pointer64Authenticated;
247a432f11aSLang Hames 
248a432f11aSLang Hames   constexpr size_t MaxPtrSignSeqLength =
249a432f11aSLang Hames       4 + // To materialize the value to sign.
250a432f11aSLang Hames       4 + // To materialize the fixup location.
251a432f11aSLang Hames       3 + // To copy, blend discriminator, and sign
252a432f11aSLang Hames       1;  // To store the result.
253a432f11aSLang Hames 
254a432f11aSLang Hames   // The maximum number of signing instructions required is the maximum per
255a432f11aSLang Hames   // location, times the number of locations, plus three instructions to
256a432f11aSLang Hames   // materialize the return value and return.
257a432f11aSLang Hames   size_t NumSigningInstrs = NumPtrAuthFixupLocations * MaxPtrSignSeqLength + 3;
258a432f11aSLang Hames 
259a432f11aSLang Hames   // Create signing function section.
260a432f11aSLang Hames   auto &SigningSection =
261a432f11aSLang Hames       G.createSection(getPointerSigningFunctionSectionName(),
262a432f11aSLang Hames                       orc::MemProt::Read | orc::MemProt::Exec);
263a432f11aSLang Hames   SigningSection.setMemLifetime(orc::MemLifetime::Finalize);
264a432f11aSLang Hames 
265a432f11aSLang Hames   size_t SigningFunctionSize = NumSigningInstrs * 4;
266a432f11aSLang Hames   auto &SigningFunctionBlock = G.createMutableContentBlock(
267a432f11aSLang Hames       SigningSection, G.allocateBuffer(SigningFunctionSize),
268a432f11aSLang Hames       orc::ExecutorAddr(), 4, 0);
269a432f11aSLang Hames   G.addAnonymousSymbol(SigningFunctionBlock, 0, SigningFunctionBlock.getSize(),
270a432f11aSLang Hames                        true, true);
271a432f11aSLang Hames 
272a432f11aSLang Hames   LLVM_DEBUG({
273a432f11aSLang Hames     dbgs() << "  " << NumPtrAuthFixupLocations << " location(s) to sign, up to "
274a432f11aSLang Hames            << NumSigningInstrs << " instructions required ("
275a432f11aSLang Hames            << formatv("{0:x}", SigningFunctionBlock.getSize()) << " bytes)\n";
276a432f11aSLang Hames   });
277a432f11aSLang Hames 
278a432f11aSLang Hames   return Error::success();
279a432f11aSLang Hames }
280a432f11aSLang Hames 
281a432f11aSLang Hames /// Given a LinkGraph containing Pointer64Auth edges, transform those edges to
282a432f11aSLang Hames /// Pointer64 and add code to sign the pointers in the executor.
283a432f11aSLang Hames ///
284a432f11aSLang Hames /// This function will add a $__ptrauth_sign section with finalization-lifetime
285a432f11aSLang Hames /// containing an anonymous function that will sign all pointers in the graph.
286a432f11aSLang Hames /// An allocation action will be added to run this function during finalization.
287a432f11aSLang Hames Error lowerPointer64AuthEdgesToSigningFunction(LinkGraph &G) {
288a432f11aSLang Hames   LLVM_DEBUG({
289a432f11aSLang Hames     dbgs() << "Writing pointer signing function for " << G.getName() << "\n";
290a432f11aSLang Hames   });
291a432f11aSLang Hames 
292a432f11aSLang Hames   constexpr unsigned Reg1 = 8;  // Holds pointer value to sign.
293a432f11aSLang Hames   constexpr unsigned Reg2 = 9;  // Holds fixup address.
294a432f11aSLang Hames   constexpr unsigned Reg3 = 10; // Temporary for discriminator value if needed.
295a432f11aSLang Hames 
296a432f11aSLang Hames   // Find the signing function.
297a432f11aSLang Hames   auto *SigningSection =
298a432f11aSLang Hames       G.findSectionByName(getPointerSigningFunctionSectionName());
299a432f11aSLang Hames   assert(SigningSection && "Siging section missing");
300a432f11aSLang Hames   assert(SigningSection->blocks_size() == 1 &&
301a432f11aSLang Hames          "Unexpected number of blocks in signing section");
302a432f11aSLang Hames   assert(SigningSection->symbols_size() == 1 &&
303a432f11aSLang Hames          "Unexpected number of symbols in signing section");
304a432f11aSLang Hames 
305a432f11aSLang Hames   auto &SigningFunctionSym = **SigningSection->symbols().begin();
306a432f11aSLang Hames   auto &SigningFunctionBlock = SigningFunctionSym.getBlock();
307a432f11aSLang Hames   auto SigningFunctionBuf = SigningFunctionBlock.getAlreadyMutableContent();
308a432f11aSLang Hames 
309a432f11aSLang Hames   // Write the instructions to the block content.
310a432f11aSLang Hames   BinaryStreamWriter InstrWriter(
311a432f11aSLang Hames       {reinterpret_cast<uint8_t *>(SigningFunctionBuf.data()),
312a432f11aSLang Hames        SigningFunctionBuf.size()},
313a432f11aSLang Hames       G.getEndianness());
314a432f11aSLang Hames 
315a432f11aSLang Hames   auto AppendInstr = [&](uint32_t Instr) {
316a432f11aSLang Hames     return InstrWriter.writeInteger(Instr);
317a432f11aSLang Hames   };
318a432f11aSLang Hames 
319a432f11aSLang Hames   for (auto *B : G.blocks()) {
32079685b59SLang Hames     for (auto &E : B->edges()) {
321*5ab43c3eSLang Hames       // We're only concerned with Pointer64Authenticated edges here.
322*5ab43c3eSLang Hames       if (E.getKind() != aarch64::Pointer64Authenticated)
323*5ab43c3eSLang Hames         continue;
324*5ab43c3eSLang Hames 
325a432f11aSLang Hames       uint64_t EncodedInfo = E.getAddend();
326a432f11aSLang Hames       int32_t RealAddend = (uint32_t)(EncodedInfo & 0xffffffff);
327a432f11aSLang Hames       uint32_t InitialDiscriminator = (EncodedInfo >> 32) & 0xffff;
328a432f11aSLang Hames       bool AddressDiversify = (EncodedInfo >> 48) & 0x1;
329a432f11aSLang Hames       uint32_t Key = (EncodedInfo >> 49) & 0x3;
330a432f11aSLang Hames       uint32_t HighBits = EncodedInfo >> 51;
331a432f11aSLang Hames       auto ValueToSign = E.getTarget().getAddress() + RealAddend;
332a432f11aSLang Hames 
333a432f11aSLang Hames       if (HighBits != 0x1000)
334a432f11aSLang Hames         return make_error<JITLinkError>(
335a432f11aSLang Hames             "Pointer64Auth edge at " +
336a432f11aSLang Hames             formatv("{0:x}", B->getFixupAddress(E).getValue()) +
337a432f11aSLang Hames             " has invalid encoded addend  " + formatv("{0:x}", EncodedInfo));
338a432f11aSLang Hames 
339a432f11aSLang Hames       LLVM_DEBUG({
3408b29c5ccSLang Hames         const char *const KeyNames[] = {"IA", "IB", "DA", "DB"};
341a432f11aSLang Hames         dbgs() << "  " << B->getFixupAddress(E) << " <- " << ValueToSign
342a432f11aSLang Hames                << " : key = " << KeyNames[Key] << ", discriminator = "
343a432f11aSLang Hames                << formatv("{0:x4}", InitialDiscriminator)
344a432f11aSLang Hames                << ", address diversified = "
345a432f11aSLang Hames                << (AddressDiversify ? "yes" : "no") << "\n";
346a432f11aSLang Hames       });
347a432f11aSLang Hames 
348a432f11aSLang Hames       // Materialize pointer value.
349*5ab43c3eSLang Hames       cantFail(writeMovRegImm64Seq(AppendInstr, Reg1, ValueToSign.getValue()));
350a432f11aSLang Hames 
351a432f11aSLang Hames       // Materialize fixup pointer.
352a432f11aSLang Hames       cantFail(writeMovRegImm64Seq(AppendInstr, Reg2,
353a432f11aSLang Hames                                    B->getFixupAddress(E).getValue()));
354a432f11aSLang Hames 
355a432f11aSLang Hames       // Write signing instruction(s).
356*5ab43c3eSLang Hames       cantFail(writePACSignSeq(AppendInstr, Reg1, ValueToSign, Reg2, Reg3, Key,
357*5ab43c3eSLang Hames                                InitialDiscriminator, AddressDiversify));
358a432f11aSLang Hames 
359a432f11aSLang Hames       // Store signed pointer.
360a432f11aSLang Hames       cantFail(writeStoreRegSeq(AppendInstr, Reg2, Reg1));
361a432f11aSLang Hames 
36279685b59SLang Hames       // Replace edge with a keep-alive to preserve dependence info.
36379685b59SLang Hames       E.setKind(Edge::KeepAlive);
36479685b59SLang Hames     }
365a432f11aSLang Hames   }
366a432f11aSLang Hames 
367a432f11aSLang Hames   // Write epilogue. x0 = 0, x1 = 1 is an SPS serialized Error::success value.
368a432f11aSLang Hames   constexpr uint32_t RETInstr = 0xd65f03c0;
369a432f11aSLang Hames   cantFail(writeMovRegImm64Seq(AppendInstr, 0, 0)); // mov x0, #0
370a432f11aSLang Hames   cantFail(writeMovRegImm64Seq(AppendInstr, 1, 1)); // mov x1, #1
371a432f11aSLang Hames   cantFail(AppendInstr(RETInstr));                  // ret
372a432f11aSLang Hames 
373a432f11aSLang Hames   // Add an allocation action to call the signing function.
374a432f11aSLang Hames   using namespace orc::shared;
375a432f11aSLang Hames   G.allocActions().push_back(
376a432f11aSLang Hames       {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(
377a432f11aSLang Hames            SigningFunctionSym.getAddress())),
378a432f11aSLang Hames        {}});
379a432f11aSLang Hames 
380a432f11aSLang Hames   return Error::success();
381a432f11aSLang Hames }
382a432f11aSLang Hames 
3832ed91da0SStefan Gränitz } // namespace aarch64
3842ed91da0SStefan Gränitz } // namespace jitlink
3852ed91da0SStefan Gränitz } // namespace llvm
386