xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //=== aarch64.h - Generic JITLink aarch64 edge kinds, utilities -*- 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 // Generic utilities for graphs representing aarch64 objects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_JITLINK_AARCH64_H
14 #define LLVM_EXECUTIONENGINE_JITLINK_AARCH64_H
15 
16 #include "TableManager.h"
17 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
19 #include "llvm/Support/Compiler.h"
20 
21 namespace llvm {
22 namespace jitlink {
23 namespace aarch64 {
24 
25 /// Represents aarch64 fixups and other aarch64-specific edge kinds.
26 enum EdgeKind_aarch64 : Edge::Kind {
27 
28   /// A plain 64-bit pointer value relocation.
29   ///
30   /// Fixup expression:
31   ///   Fixup <- Target + Addend : uint64
32   ///
33   Pointer64 = Edge::FirstRelocation,
34 
35   /// An arm64e authenticated pointer relocation. The addend contains a 64-bit
36   /// struct containing the authentication parameters:
37   ///
38   ///   Addend encoding:
39   ///     int32_t  addend;
40   ///     uint16_t diversityData;
41   ///     uint16_t hasAddressDiversity : 1;
42   ///     uint16_t key : 2;
43   ///     uint16_t zeroes : 12;
44   ///     uint16_t authenticated : 1;
45   ///
46   /// Note: This means that the addend cannot be interpreted as a plain offset
47   ///       prior to lowering.
48   ///
49   /// Authenticated pointer edges cannot be fixed up directly by JITLink as the
50   /// signing keys are held in the executing process. They can be removed from
51   /// the graph by a combination of the createEmptyPointerSigningFunction pass
52   /// (post-prune) and the lowerPointer64AuthEdgesToSigningFunction pass
53   /// (pre-fixup). Together these passes construct a signing function that will
54   /// be run in the executing process to write the signed pointers to the fixup
55   /// locations.
56   ///
57   /// Fixup expression:
58   ///   NONE
59   ///
60   /// Errors:
61   ///   - Failure to handle edges of this kind prior to the fixup phase will
62   ///     result in an unsupported error during the fixup phase.
63   Pointer64Authenticated,
64 
65   /// A plain 32-bit pointer value relocation.
66   ///
67   /// Fixup expression:
68   ///   Fixup <- Target + Addend : uint32
69   ///
70   /// Errors:
71   ///   - The target must reside in the low 32-bits of the address space,
72   ///     otherwise an out-of-range error will be returned.
73   ///
74   Pointer32,
75 
76   /// A 64-bit delta.
77   ///
78   /// Delta from the fixup to the target.
79   ///
80   /// Fixup expression:
81   ///   Fixup <- Target - Fixup + Addend : int64
82   ///
83   Delta64,
84 
85   /// A 32-bit delta.
86   ///
87   /// Delta from the fixup to the target.
88   ///
89   /// Fixup expression:
90   ///   Fixup <- Target - Fixup + Addend : int64
91   ///
92   /// Errors:
93   ///   - The result of the fixup expression must fit into an int32, otherwise
94   ///     an out-of-range error will be returned.
95   ///
96   Delta32,
97 
98   /// A 64-bit negative delta.
99   ///
100   /// Delta from target back to the fixup.
101   ///
102   /// Fixup expression:
103   ///   Fixup <- Fixup - Target + Addend : int64
104   ///
105   NegDelta64,
106 
107   /// A 32-bit negative delta.
108   ///
109   /// Delta from the target back to the fixup.
110   ///
111   /// Fixup expression:
112   ///   Fixup <- Fixup - Target + Addend : int32
113   ///
114   /// Errors:
115   ///   - The result of the fixup expression must fit into an int32, otherwise
116   ///     an out-of-range error will be returned.
117   NegDelta32,
118 
119   /// A 26-bit PC-relative branch.
120   ///
121   /// Represents a PC-relative call or branch to a target within +/-128Mb. The
122   /// target must be 32-bit aligned.
123   ///
124   /// Fixup expression:
125   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int26
126   ///
127   /// Notes:
128   ///   The '26' in the name refers to the number operand bits and follows the
129   /// naming convention used by the corresponding ELF and MachO relocations.
130   /// Since the low two bits must be zero (because of the 32-bit alignment of
131   /// the target) the operand is effectively a signed 28-bit number.
132   ///
133   ///
134   /// Errors:
135   ///   - The result of the unshifted part of the fixup expression must be
136   ///     32-bit aligned otherwise an alignment error will be returned.
137   ///   - The result of the fixup expression must fit into an int26 otherwise an
138   ///     out-of-range error will be returned.
139   Branch26PCRel,
140 
141   /// A 14-bit PC-relative test and branch.
142   ///
143   /// Represents a PC-relative test and branch to a target within +/-32Kb. The
144   /// target must be 32-bit aligned.
145   ///
146   /// Fixup expression:
147   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int14
148   ///
149   /// Notes:
150   ///   The '14' in the name refers to the number operand bits and follows the
151   /// naming convention used by the corresponding ELF relocation.
152   /// Since the low two bits must be zero (because of the 32-bit alignment of
153   /// the target) the operand is effectively a signed 16-bit number.
154   ///
155   ///
156   /// Errors:
157   ///   - The result of the unshifted part of the fixup expression must be
158   ///     32-bit aligned otherwise an alignment error will be returned.
159   ///   - The result of the fixup expression must fit into an int14 otherwise an
160   ///     out-of-range error will be returned.
161   TestAndBranch14PCRel,
162 
163   /// A 19-bit PC-relative conditional branch.
164   ///
165   /// Represents a PC-relative conditional branch to a target within +/-1Mb. The
166   /// target must be 32-bit aligned.
167   ///
168   /// Fixup expression:
169   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int19
170   ///
171   /// Notes:
172   ///   The '19' in the name refers to the number operand bits and follows the
173   /// naming convention used by the corresponding ELF relocation.
174   /// Since the low two bits must be zero (because of the 32-bit alignment of
175   /// the target) the operand is effectively a signed 21-bit number.
176   ///
177   ///
178   /// Errors:
179   ///   - The result of the unshifted part of the fixup expression must be
180   ///     32-bit aligned otherwise an alignment error will be returned.
181   ///   - The result of the fixup expression must fit into an int19 otherwise an
182   ///     out-of-range error will be returned.
183   CondBranch19PCRel,
184 
185   /// A 16-bit slice of the target address (which slice depends on the
186   /// instruction at the fixup location).
187   ///
188   /// Used to fix up MOVK/MOVN/MOVZ instructions.
189   ///
190   /// Fixup expression:
191   ///
192   ///   Fixup <- (Target + Addend) >> Shift : uint16
193   ///
194   ///   where Shift is encoded in the instruction at the fixup location.
195   ///
196   MoveWide16,
197 
198   /// The signed 21-bit delta from the fixup to the target.
199   ///
200   /// Typically used to load a pointers at a PC-relative offset of +/- 1Mb. The
201   /// target must be 32-bit aligned.
202   ///
203   /// Fixup expression:
204   ///
205   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int19
206   ///
207   /// Notes:
208   ///   The '19' in the name refers to the number operand bits and follows the
209   /// naming convention used by the corresponding ELF relocation.
210   /// Since the low two bits must be zero (because of the 32-bit alignment of
211   /// the target) the operand is effectively a signed 21-bit number.
212   ///
213   ///
214   /// Errors:
215   ///   - The result of the unshifted part of the fixup expression must be
216   ///     32-bit aligned otherwise an alignment error will be returned.
217   ///   - The result of the fixup expression must fit into an int19 or an
218   ///     out-of-range error will be returned.
219   LDRLiteral19,
220 
221   /// The signed 21-bit delta from the fixup to the target.
222   ///
223   /// Fixup expression:
224   ///
225   ///   Fixup <- Target - Fixup + Addend : int21
226   ///
227   /// Notes:
228   ///   For ADR fixups.
229   ///
230   /// Errors:
231   ///   - The result of the fixup expression must fit into an int21 otherwise an
232   ///     out-of-range error will be returned.
233   ADRLiteral21,
234 
235   /// The signed 21-bit delta from the fixup page to the page containing the
236   /// target.
237   ///
238   /// Fixup expression:
239   ///
240   ///   Fixup <- (((Target + Addend) & ~0xfff) - (Fixup & ~0xfff)) >> 12 : int21
241   ///
242   /// Notes:
243   ///   For ADRP fixups.
244   ///
245   /// Errors:
246   ///   - The result of the fixup expression must fit into an int21 otherwise an
247   ///     out-of-range error will be returned.
248   Page21,
249 
250   /// The 12-bit (potentially shifted) offset of the target within its page.
251   ///
252   /// Typically used to fix up LDR immediates.
253   ///
254   /// Fixup expression:
255   ///
256   ///   Fixup <- ((Target + Addend) >> Shift) & 0xfff : uint12
257   ///
258   ///   where Shift is encoded in the size field of the instruction.
259   ///
260   /// Errors:
261   ///   - The result of the unshifted part of the fixup expression must be
262   ///     aligned otherwise an alignment error will be returned.
263   ///   - The result of the fixup expression must fit into a uint12 otherwise an
264   ///     out-of-range error will be returned.
265   PageOffset12,
266 
267   /// The 15-bit offset of the GOT entry from the GOT table.
268   ///
269   /// Used for load/store instructions addressing a GOT entry.
270   ///
271   /// Fixup expression:
272   ///
273   ///   Fixup <- ((Target + Addend - Page(GOT))) & 0x7fff) >> 3 : uint12
274   ///
275   /// Errors:
276   ///   - The result of the unshifted part of the fixup expression must be
277   ///     aligned otherwise an alignment error will be returned.
278   ///   - The result of the fixup expression must fit into a uint12 otherwise an
279   ///     out-of-range error will be returned.
280   GotPageOffset15,
281 
282   /// A GOT entry getter/constructor, transformed to Page21 pointing at the GOT
283   /// entry for the original target.
284   ///
285   /// Indicates that this edge should be transformed into a Page21 targeting
286   /// the GOT entry for the edge's current target, maintaining the same addend.
287   /// A GOT entry for the target should be created if one does not already
288   /// exist.
289   ///
290   /// Edges of this kind are usually handled by a GOT builder pass inserted by
291   /// default.
292   ///
293   /// Fixup expression:
294   ///   NONE
295   ///
296   /// Errors:
297   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
298   ///     phase will result in an assert/unreachable during the fixup phase.
299   ///
300   RequestGOTAndTransformToPage21,
301 
302   /// A GOT entry getter/constructor, transformed to Pageoffset12 pointing at
303   /// the GOT entry for the original target.
304   ///
305   /// Indicates that this edge should be transformed into a PageOffset12
306   /// targeting the GOT entry for the edge's current target, maintaining the
307   /// same addend. A GOT entry for the target should be created if one does not
308   /// already exist.
309   ///
310   /// Edges of this kind are usually handled by a GOT builder pass inserted by
311   /// default.
312   ///
313   /// Fixup expression:
314   ///   NONE
315   ///
316   /// Errors:
317   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
318   ///     phase will result in an assert/unreachable during the fixup phase.
319   ///
320   RequestGOTAndTransformToPageOffset12,
321 
322   /// A GOT entry getter/constructor, transformed to Pageoffset15 pointing at
323   /// the GOT entry for the original target.
324   ///
325   /// Indicates that this edge should be transformed into a GotPageOffset15
326   /// targeting the GOT entry for the edge's current target, maintaining the
327   /// same addend. A GOT entry for the target should be created if one does not
328   /// already exist.
329   ///
330   /// Fixup expression:
331   ///   NONE
332   ///
333   /// Errors:
334   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
335   ///     phase will result in an assert/unreachable during the fixup phase.
336   ///
337   RequestGOTAndTransformToPageOffset15,
338 
339   /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
340   /// entry for the original target.
341   ///
342   /// Indicates that this edge should be transformed into a Delta32/ targeting
343   /// the GOT entry for the edge's current target, maintaining the same addend.
344   /// A GOT entry for the target should be created if one does not already
345   /// exist.
346   ///
347   /// Edges of this kind are usually handled by a GOT builder pass inserted by
348   /// default.
349   ///
350   /// Fixup expression:
351   ///   NONE
352   ///
353   /// Errors:
354   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
355   ///     phase will result in an assert/unreachable during the fixup phase.
356   ///
357   RequestGOTAndTransformToDelta32,
358 
359   /// A TLVP entry getter/constructor, transformed to Page21.
360   ///
361   /// Indicates that this edge should be transformed into a Page21 targeting the
362   /// TLVP entry for the edge's current target. A TLVP entry for the target
363   /// should be created if one does not already exist.
364   ///
365   /// Fixup expression:
366   ///   NONE
367   ///
368   /// Errors:
369   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
370   ///     phase will result in an assert/unreachable during the fixup phase.
371   ///
372   RequestTLVPAndTransformToPage21,
373 
374   /// A TLVP entry getter/constructor, transformed to PageOffset12.
375   ///
376   /// Indicates that this edge should be transformed into a PageOffset12
377   /// targeting the TLVP entry for the edge's current target. A TLVP entry for
378   /// the target should be created if one does not already exist.
379   ///
380   /// Fixup expression:
381   ///   NONE
382   ///
383   /// Errors:
384   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
385   ///     phase will result in an assert/unreachable during the fixup phase.
386   ///
387   RequestTLVPAndTransformToPageOffset12,
388 
389   /// A TLSDesc entry getter/constructor, transformed to Page21.
390   ///
391   /// Indicates that this edge should be transformed into a Page21 targeting the
392   /// TLSDesc entry for the edge's current target. A TLSDesc entry for the
393   /// target should be created if one does not already exist.
394   ///
395   /// Fixup expression:
396   ///   NONE
397   ///
398   /// Errors:
399   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
400   ///     phase will result in an assert/unreachable during the fixup phase.
401   ///
402   RequestTLSDescEntryAndTransformToPage21,
403 
404   /// A TLSDesc entry getter/constructor, transformed to PageOffset12.
405   ///
406   /// Indicates that this edge should be transformed into a PageOffset12
407   /// targeting the TLSDesc entry for the edge's current target. A TLSDesc entry
408   /// for the target should be created if one does not already exist.
409   ///
410   /// Fixup expression:
411   ///   NONE
412   ///
413   /// Errors:
414   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
415   ///     phase will result in an assert/unreachable during the fixup phase.
416   ///
417   RequestTLSDescEntryAndTransformToPageOffset12,
418 };
419 
420 /// Returns a string name for the given aarch64 edge. For debugging purposes
421 /// only
422 LLVM_ABI const char *getEdgeKindName(Edge::Kind K);
423 
424 // Returns whether the Instr is LD/ST (imm12)
isLoadStoreImm12(uint32_t Instr)425 inline bool isLoadStoreImm12(uint32_t Instr) {
426   constexpr uint32_t LoadStoreImm12Mask = 0x3b000000;
427   return (Instr & LoadStoreImm12Mask) == 0x39000000;
428 }
429 
isTestAndBranchImm14(uint32_t Instr)430 inline bool isTestAndBranchImm14(uint32_t Instr) {
431   constexpr uint32_t TestAndBranchImm14Mask = 0x7e000000;
432   return (Instr & TestAndBranchImm14Mask) == 0x36000000;
433 }
434 
isCondBranchImm19(uint32_t Instr)435 inline bool isCondBranchImm19(uint32_t Instr) {
436   constexpr uint32_t CondBranchImm19Mask = 0xfe000000;
437   return (Instr & CondBranchImm19Mask) == 0x54000000;
438 }
439 
isCompAndBranchImm19(uint32_t Instr)440 inline bool isCompAndBranchImm19(uint32_t Instr) {
441   constexpr uint32_t CompAndBranchImm19Mask = 0x7e000000;
442   return (Instr & CompAndBranchImm19Mask) == 0x34000000;
443 }
444 
isADR(uint32_t Instr)445 inline bool isADR(uint32_t Instr) {
446   constexpr uint32_t ADRMask = 0x9f000000;
447   return (Instr & ADRMask) == 0x10000000;
448 }
449 
isLDRLiteral(uint32_t Instr)450 inline bool isLDRLiteral(uint32_t Instr) {
451   constexpr uint32_t LDRLitMask = 0x3b000000;
452   return (Instr & LDRLitMask) == 0x18000000;
453 }
454 
455 // Returns the amount the address operand of LD/ST (imm12)
456 // should be shifted right by.
457 //
458 // The shift value varies by the data size of LD/ST instruction.
459 // For instance, LDH instructoin needs the address to be shifted
460 // right by 1.
getPageOffset12Shift(uint32_t Instr)461 inline unsigned getPageOffset12Shift(uint32_t Instr) {
462   constexpr uint32_t Vec128Mask = 0x04800000;
463 
464   if (isLoadStoreImm12(Instr)) {
465     uint32_t ImplicitShift = Instr >> 30;
466     if (ImplicitShift == 0)
467       if ((Instr & Vec128Mask) == Vec128Mask)
468         ImplicitShift = 4;
469 
470     return ImplicitShift;
471   }
472 
473   return 0;
474 }
475 
476 // Returns whether the Instr is MOVK/MOVZ (imm16) with a zero immediate field
isMoveWideImm16(uint32_t Instr)477 inline bool isMoveWideImm16(uint32_t Instr) {
478   constexpr uint32_t MoveWideImm16Mask = 0x5f9fffe0;
479   return (Instr & MoveWideImm16Mask) == 0x52800000;
480 }
481 
482 // Returns the amount the address operand of MOVK/MOVZ (imm16)
483 // should be shifted right by.
484 //
485 // The shift value is specfied in the assembly as LSL #<shift>.
getMoveWide16Shift(uint32_t Instr)486 inline unsigned getMoveWide16Shift(uint32_t Instr) {
487   if (isMoveWideImm16(Instr)) {
488     uint32_t ImplicitShift = (Instr >> 21) & 0b11;
489     return ImplicitShift << 4;
490   }
491 
492   return 0;
493 }
494 
495 /// Apply fixup expression for edge to block content.
applyFixup(LinkGraph & G,Block & B,const Edge & E,const Symbol * GOTSymbol)496 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
497                         const Symbol *GOTSymbol) {
498   using namespace support;
499 
500   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
501   char *FixupPtr = BlockWorkingMem + E.getOffset();
502   orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
503 
504   switch (E.getKind()) {
505   case Pointer64: {
506     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
507     *(ulittle64_t *)FixupPtr = Value;
508     break;
509   }
510   case Pointer32: {
511     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
512     if (Value > std::numeric_limits<uint32_t>::max())
513       return makeTargetOutOfRangeError(G, B, E);
514     *(ulittle32_t *)FixupPtr = Value;
515     break;
516   }
517   case Delta32:
518   case Delta64:
519   case NegDelta32:
520   case NegDelta64: {
521     int64_t Value;
522     if (E.getKind() == Delta32 || E.getKind() == Delta64)
523       Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
524     else
525       Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
526 
527     if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
528       if (Value < std::numeric_limits<int32_t>::min() ||
529           Value > std::numeric_limits<int32_t>::max())
530         return makeTargetOutOfRangeError(G, B, E);
531       *(little32_t *)FixupPtr = Value;
532     } else
533       *(little64_t *)FixupPtr = Value;
534     break;
535   }
536   case Branch26PCRel: {
537     assert((FixupAddress.getValue() & 0x3) == 0 &&
538            "Branch-inst is not 32-bit aligned");
539 
540     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
541 
542     if (static_cast<uint64_t>(Value) & 0x3)
543       return make_error<JITLinkError>("BranchPCRel26 target is not 32-bit "
544                                       "aligned");
545 
546     if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
547       return makeTargetOutOfRangeError(G, B, E);
548 
549     uint32_t RawInstr = *(little32_t *)FixupPtr;
550     assert((RawInstr & 0x7fffffff) == 0x14000000 &&
551            "RawInstr isn't a B or BR immediate instruction");
552     uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
553     uint32_t FixedInstr = RawInstr | Imm;
554     *(little32_t *)FixupPtr = FixedInstr;
555     break;
556   }
557   case MoveWide16: {
558     uint64_t TargetOffset =
559         (E.getTarget().getAddress() + E.getAddend()).getValue();
560 
561     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
562     assert(isMoveWideImm16(RawInstr) &&
563            "RawInstr isn't a MOVK/MOVZ instruction");
564 
565     unsigned ImmShift = getMoveWide16Shift(RawInstr);
566     uint32_t Imm = (TargetOffset >> ImmShift) & 0xffff;
567     uint32_t FixedInstr = RawInstr | (Imm << 5);
568     *(ulittle32_t *)FixupPtr = FixedInstr;
569     break;
570   }
571   case LDRLiteral19: {
572     assert((FixupAddress.getValue() & 0x3) == 0 && "LDR is not 32-bit aligned");
573     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
574     assert(isLDRLiteral(RawInstr) && "RawInstr is not an LDR Literal");
575     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
576     if (Delta & 0x3)
577       return make_error<JITLinkError>("LDR literal target is not 32-bit "
578                                       "aligned");
579     if (!isInt<21>(Delta))
580       return makeTargetOutOfRangeError(G, B, E);
581     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
582     uint32_t FixedInstr = RawInstr | EncodedImm;
583     *(ulittle32_t *)FixupPtr = FixedInstr;
584     break;
585   }
586   case ADRLiteral21: {
587     assert((FixupAddress.getValue() & 0x3) == 0 && "ADR is not 32-bit aligned");
588     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
589     assert(isADR(RawInstr) && "RawInstr is not an ADR");
590     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
591     if (!isInt<21>(Delta))
592       return makeTargetOutOfRangeError(G, B, E);
593     auto UDelta = static_cast<uint32_t>(Delta);
594     uint32_t EncodedImmHi = ((UDelta >> 2) & 0x7ffff) << 5;
595     uint32_t EncodedImmLo = (UDelta & 0x3) << 29;
596     uint32_t FixedInstr = RawInstr | EncodedImmHi | EncodedImmLo;
597     *(ulittle32_t *)FixupPtr = FixedInstr;
598     break;
599   }
600   case TestAndBranch14PCRel: {
601     assert((FixupAddress.getValue() & 0x3) == 0 &&
602            "Test and branch is not 32-bit aligned");
603     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
604     assert(isTestAndBranchImm14(RawInstr) &&
605            "RawInstr is not a test and branch");
606     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
607     if (Delta & 0x3)
608       return make_error<JITLinkError>(
609           "Test and branch literal target is not 32-bit aligned");
610     if (!isInt<16>(Delta))
611       return makeTargetOutOfRangeError(G, B, E);
612     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x3fff) << 5;
613     uint32_t FixedInstr = RawInstr | EncodedImm;
614     *(ulittle32_t *)FixupPtr = FixedInstr;
615     break;
616   }
617   case CondBranch19PCRel: {
618     assert((FixupAddress.getValue() & 0x3) == 0 &&
619            "Conditional branch is not 32-bit aligned");
620     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
621     assert((isCondBranchImm19(RawInstr) || isCompAndBranchImm19(RawInstr)) &&
622            "RawInstr is not a conditional branch");
623     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
624     if (Delta & 0x3)
625       return make_error<JITLinkError>(
626           "Conditional branch literal target is not 32-bit "
627           "aligned");
628     if (!isInt<21>(Delta))
629       return makeTargetOutOfRangeError(G, B, E);
630     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
631     uint32_t FixedInstr = RawInstr | EncodedImm;
632     *(ulittle32_t *)FixupPtr = FixedInstr;
633     break;
634   }
635   case Page21: {
636     uint64_t TargetPage =
637         (E.getTarget().getAddress().getValue() + E.getAddend()) &
638         ~static_cast<uint64_t>(4096 - 1);
639     uint64_t PCPage =
640         FixupAddress.getValue() & ~static_cast<uint64_t>(4096 - 1);
641 
642     int64_t PageDelta = TargetPage - PCPage;
643     if (!isInt<33>(PageDelta))
644       return makeTargetOutOfRangeError(G, B, E);
645 
646     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
647     assert((RawInstr & 0xffffffe0) == 0x90000000 &&
648            "RawInstr isn't an ADRP instruction");
649     uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
650     uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
651     uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
652     *(ulittle32_t *)FixupPtr = FixedInstr;
653     break;
654   }
655   case PageOffset12: {
656     uint64_t TargetOffset =
657         (E.getTarget().getAddress() + E.getAddend()).getValue() & 0xfff;
658 
659     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
660     unsigned ImmShift = getPageOffset12Shift(RawInstr);
661 
662     if (TargetOffset & ((1 << ImmShift) - 1))
663       return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
664 
665     uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
666     uint32_t FixedInstr = RawInstr | EncodedImm;
667     *(ulittle32_t *)FixupPtr = FixedInstr;
668     break;
669   }
670   case GotPageOffset15: {
671     assert(GOTSymbol && "No GOT section symbol");
672     uint64_t TargetOffset =
673         (E.getTarget().getAddress() + E.getAddend()).getValue() -
674         (GOTSymbol->getAddress().getValue() & ~static_cast<uint64_t>(4096 - 1));
675     if (TargetOffset > 0x7fff)
676       return make_error<JITLinkError>("PAGEOFF15 target is out of range");
677 
678     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
679     const unsigned ImmShift = 3;
680     if (TargetOffset & ((1 << ImmShift) - 1))
681       return make_error<JITLinkError>("PAGEOFF15 target is not aligned");
682 
683     uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
684     uint32_t FixedInstr = RawInstr | EncodedImm;
685     *(ulittle32_t *)FixupPtr = FixedInstr;
686     break;
687   }
688   default:
689     return make_error<JITLinkError>(
690         "In graph " + G.getName() + ", section " + B.getSection().getName() +
691         " unsupported edge kind " + getEdgeKindName(E.getKind()));
692   }
693 
694   return Error::success();
695 }
696 
697 /// aarch64 pointer size.
698 constexpr uint64_t PointerSize = 8;
699 
700 /// AArch64 null pointer content.
701 LLVM_ABI extern const char NullPointerContent[PointerSize];
702 
703 /// AArch64 pointer jump stub content.
704 ///
705 /// Contains the instruction sequence for an indirect jump via an in-memory
706 /// pointer:
707 ///   ADRP x16, ptr@page21
708 ///   LDR  x16, [x16, ptr@pageoff12]
709 ///   BR   x16
710 LLVM_ABI extern const char PointerJumpStubContent[12];
711 
712 /// Creates a new pointer block in the given section and returns an
713 /// Anonymous symbol pointing to it.
714 ///
715 /// If InitialTarget is given then an Pointer64 relocation will be added to the
716 /// block pointing at InitialTarget.
717 ///
718 /// The pointer block will have the following default values:
719 ///   alignment: 64-bit
720 ///   alignment-offset: 0
721 ///   address: highest allowable (~7U)
722 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
723                                       Symbol *InitialTarget = nullptr,
724                                       uint64_t InitialAddend = 0) {
725   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
726                                  orc::ExecutorAddr(~uint64_t(7)), 8, 0);
727   if (InitialTarget)
728     B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
729   return G.addAnonymousSymbol(B, 0, 8, false, false);
730 }
731 
732 /// Create a jump stub block that jumps via the pointer at the given symbol.
733 ///
734 /// The stub block will have the following default values:
735 ///   alignment: 32-bit
736 ///   alignment-offset: 0
737 ///   address: highest allowable: (~11U)
createPointerJumpStubBlock(LinkGraph & G,Section & StubSection,Symbol & PointerSymbol)738 inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
739                                          Symbol &PointerSymbol) {
740   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
741                                  orc::ExecutorAddr(~uint64_t(11)), 4, 0);
742   B.addEdge(Page21, 0, PointerSymbol, 0);
743   B.addEdge(PageOffset12, 4, PointerSymbol, 0);
744   return B;
745 }
746 
747 /// Create a jump stub that jumps via the pointer at the given symbol and
748 /// an anonymous symbol pointing to it. Return the anonymous symbol.
749 ///
750 /// The stub block will be created by createPointerJumpStubBlock.
createAnonymousPointerJumpStub(LinkGraph & G,Section & StubSection,Symbol & PointerSymbol)751 inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
752                                               Section &StubSection,
753                                               Symbol &PointerSymbol) {
754   return G.addAnonymousSymbol(
755       createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0,
756       sizeof(PointerJumpStubContent), true, false);
757 }
758 
759 /// AArch64 reentry trampoline.
760 ///
761 /// Contains the instruction sequence for a trampoline that stores its return
762 /// address (and stack pointer) on the stack and calls the given reentry symbol:
763 ///   STP  x29, x30, [sp, #-16]!
764 ///   BL   <reentry-symbol>
765 LLVM_ABI extern const char ReentryTrampolineContent[8];
766 
767 /// Create a block of N reentry trampolines.
createReentryTrampolineBlock(LinkGraph & G,Section & TrampolineSection,Symbol & ReentrySymbol)768 inline Block &createReentryTrampolineBlock(LinkGraph &G,
769                                            Section &TrampolineSection,
770                                            Symbol &ReentrySymbol) {
771   auto &B = G.createContentBlock(TrampolineSection, ReentryTrampolineContent,
772                                  orc::ExecutorAddr(~uint64_t(7)), 4, 0);
773   B.addEdge(Branch26PCRel, 4, ReentrySymbol, 0);
774   return B;
775 }
776 
createAnonymousReentryTrampoline(LinkGraph & G,Section & TrampolineSection,Symbol & ReentrySymbol)777 inline Symbol &createAnonymousReentryTrampoline(LinkGraph &G,
778                                                 Section &TrampolineSection,
779                                                 Symbol &ReentrySymbol) {
780   return G.addAnonymousSymbol(
781       createReentryTrampolineBlock(G, TrampolineSection, ReentrySymbol), 0,
782       sizeof(ReentryTrampolineContent), true, false);
783 }
784 
785 /// Global Offset Table Builder.
786 class GOTTableManager : public TableManager<GOTTableManager> {
787 public:
getSectionName()788   static StringRef getSectionName() { return "$__GOT"; }
789 
GOTTableManager(LinkGraph & G)790   GOTTableManager(LinkGraph &G) {
791     if ((GOTSection = G.findSectionByName(getSectionName())))
792       registerExistingEntries();
793   }
794 
visitEdge(LinkGraph & G,Block * B,Edge & E)795   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
796     Edge::Kind KindToSet = Edge::Invalid;
797     const char *BlockWorkingMem = B->getContent().data();
798     const char *FixupPtr = BlockWorkingMem + E.getOffset();
799 
800     switch (E.getKind()) {
801     case aarch64::RequestGOTAndTransformToPage21:
802     case aarch64::RequestTLVPAndTransformToPage21: {
803       KindToSet = aarch64::Page21;
804       break;
805     }
806     case aarch64::RequestGOTAndTransformToPageOffset12:
807     case aarch64::RequestTLVPAndTransformToPageOffset12: {
808       KindToSet = aarch64::PageOffset12;
809       uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
810       (void)RawInstr;
811       assert(E.getAddend() == 0 &&
812              "GOTPageOffset12/TLVPageOffset12 with non-zero addend");
813       assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
814              "RawInstr isn't a 64-bit LDR immediate");
815       break;
816     }
817     case aarch64::RequestGOTAndTransformToPageOffset15: {
818       KindToSet = aarch64::GotPageOffset15;
819       uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
820       (void)RawInstr;
821       assert(E.getAddend() == 0 && "GOTPageOffset15 with non-zero addend");
822       assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
823              "RawInstr isn't a 64-bit LDR immediate");
824       break;
825     }
826     case aarch64::RequestGOTAndTransformToDelta32: {
827       KindToSet = aarch64::Delta32;
828       break;
829     }
830     default:
831       return false;
832     }
833     assert(KindToSet != Edge::Invalid &&
834            "Fell through switch, but no new kind to set");
835     DEBUG_WITH_TYPE("jitlink", {
836       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
837              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
838              << formatv("{0:x}", E.getOffset()) << ")\n";
839     });
840     E.setKind(KindToSet);
841     E.setTarget(getEntryForTarget(G, E.getTarget()));
842     return true;
843   }
844 
createEntry(LinkGraph & G,Symbol & Target)845   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
846     return createAnonymousPointer(G, getGOTSection(G), &Target);
847   }
848 
849 private:
getGOTSection(LinkGraph & G)850   Section &getGOTSection(LinkGraph &G) {
851     if (!GOTSection)
852       GOTSection = &G.createSection(getSectionName(),
853                                     orc::MemProt::Read | orc::MemProt::Exec);
854     return *GOTSection;
855   }
856 
857   LLVM_ABI void registerExistingEntries();
858 
859   Section *GOTSection = nullptr;
860 };
861 
862 /// Procedure Linkage Table Builder.
863 class PLTTableManager : public TableManager<PLTTableManager> {
864 public:
getSectionName()865   static StringRef getSectionName() { return "$__STUBS"; }
866 
PLTTableManager(LinkGraph & G,GOTTableManager & GOT)867   PLTTableManager(LinkGraph &G, GOTTableManager &GOT) : GOT(GOT) {
868     if ((StubsSection = G.findSectionByName(getSectionName())))
869       registerExistingEntries();
870   }
871 
visitEdge(LinkGraph & G,Block * B,Edge & E)872   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
873     if (E.getKind() == aarch64::Branch26PCRel && !E.getTarget().isDefined()) {
874       DEBUG_WITH_TYPE("jitlink", {
875         dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
876                << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
877                << formatv("{0:x}", E.getOffset()) << ")\n";
878       });
879       E.setTarget(getEntryForTarget(G, E.getTarget()));
880       return true;
881     }
882     return false;
883   }
884 
createEntry(LinkGraph & G,Symbol & Target)885   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
886     return createAnonymousPointerJumpStub(G, getStubsSection(G),
887                                           GOT.getEntryForTarget(G, Target));
888   }
889 
890 public:
getStubsSection(LinkGraph & G)891   Section &getStubsSection(LinkGraph &G) {
892     if (!StubsSection)
893       StubsSection = &G.createSection(getSectionName(),
894                                       orc::MemProt::Read | orc::MemProt::Exec);
895     return *StubsSection;
896   }
897 
898   LLVM_ABI void registerExistingEntries();
899 
900   GOTTableManager &GOT;
901   Section *StubsSection = nullptr;
902 };
903 
904 /// Returns the name of the pointer signing function section.
905 LLVM_ABI const char *getPointerSigningFunctionSectionName();
906 
907 /// Creates a pointer signing function section, block, and symbol to reserve
908 /// space for a signing function for this LinkGraph. Clients should insert this
909 /// pass in the post-prune phase, and add the paired
910 /// lowerPointer64AuthEdgesToSigningFunction pass to the pre-fixup phase.
911 ///
912 /// No new Pointer64Auth edges can be inserted into the graph between when this
913 /// pass is run and when the pass below runs (since there will not be sufficient
914 /// space reserved in the signing function to write the signing code for them).
915 LLVM_ABI Error createEmptyPointerSigningFunction(LinkGraph &G);
916 
917 /// Given a LinkGraph containing Pointer64Authenticated edges, transform those
918 /// edges to Pointer64 and add signing code to the pointer signing function
919 /// (which must already have been created by the
920 /// createEmptyPointerSigningFunction pass above).
921 ///
922 /// This function will add a $__ptrauth_sign section with finalization-lifetime
923 /// containing an anonymous function that will sign all pointers in the graph.
924 /// An allocation action will be added to run this function during finalization.
925 LLVM_ABI Error lowerPointer64AuthEdgesToSigningFunction(LinkGraph &G);
926 
927 } // namespace aarch64
928 } // namespace jitlink
929 } // namespace llvm
930 
931 #endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH64_H
932