Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:49

0001 //=== aarch64.h - Generic JITLink aarch64 edge kinds, utilities -*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Generic utilities for graphs representing aarch64 objects.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_JITLINK_AARCH64_H
0014 #define LLVM_EXECUTIONENGINE_JITLINK_AARCH64_H
0015 
0016 #include "TableManager.h"
0017 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
0018 #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
0019 
0020 namespace llvm {
0021 namespace jitlink {
0022 namespace aarch64 {
0023 
0024 /// Represents aarch64 fixups and other aarch64-specific edge kinds.
0025 enum EdgeKind_aarch64 : Edge::Kind {
0026 
0027   /// A plain 64-bit pointer value relocation.
0028   ///
0029   /// Fixup expression:
0030   ///   Fixup <- Target + Addend : uint64
0031   ///
0032   Pointer64 = Edge::FirstRelocation,
0033 
0034   /// An arm64e authenticated pointer relocation. The addend contains a 64-bit
0035   /// struct containing the authentication parameters:
0036   ///
0037   ///   Addend encoding:
0038   ///     int32_t  addend;
0039   ///     uint16_t diversityData;
0040   ///     uint16_t hasAddressDiversity : 1;
0041   ///     uint16_t key : 2;
0042   ///     uint16_t zeroes : 12;
0043   ///     uint16_t authenticated : 1;
0044   ///
0045   /// Note: This means that the addend cannot be interpreted as a plain offset
0046   ///       prior to lowering.
0047   ///
0048   /// Authenticated pointer edges cannot be fixed up directly by JITLink as the
0049   /// signing keys are held in the executing process. They can be removed from
0050   /// the graph by a combination of the createEmptyPointerSigningFunction pass
0051   /// (post-prune) and the lowerPointer64AuthEdgesToSigningFunction pass
0052   /// (pre-fixup). Together these passes construct a signing function that will
0053   /// be run in the executing process to write the signed pointers to the fixup
0054   /// locations.
0055   ///
0056   /// Fixup expression:
0057   ///   NONE
0058   ///
0059   /// Errors:
0060   ///   - Failure to handle edges of this kind prior to the fixup phase will
0061   ///     result in an unsupported error during the fixup phase.
0062   Pointer64Authenticated,
0063 
0064   /// A plain 32-bit pointer value relocation.
0065   ///
0066   /// Fixup expression:
0067   ///   Fixup <- Target + Addend : uint32
0068   ///
0069   /// Errors:
0070   ///   - The target must reside in the low 32-bits of the address space,
0071   ///     otherwise an out-of-range error will be returned.
0072   ///
0073   Pointer32,
0074 
0075   /// A 64-bit delta.
0076   ///
0077   /// Delta from the fixup to the target.
0078   ///
0079   /// Fixup expression:
0080   ///   Fixup <- Target - Fixup + Addend : int64
0081   ///
0082   Delta64,
0083 
0084   /// A 32-bit delta.
0085   ///
0086   /// Delta from the fixup to the target.
0087   ///
0088   /// Fixup expression:
0089   ///   Fixup <- Target - Fixup + Addend : int64
0090   ///
0091   /// Errors:
0092   ///   - The result of the fixup expression must fit into an int32, otherwise
0093   ///     an out-of-range error will be returned.
0094   ///
0095   Delta32,
0096 
0097   /// A 64-bit negative delta.
0098   ///
0099   /// Delta from target back to the fixup.
0100   ///
0101   /// Fixup expression:
0102   ///   Fixup <- Fixup - Target + Addend : int64
0103   ///
0104   NegDelta64,
0105 
0106   /// A 32-bit negative delta.
0107   ///
0108   /// Delta from the target back to the fixup.
0109   ///
0110   /// Fixup expression:
0111   ///   Fixup <- Fixup - Target + Addend : int32
0112   ///
0113   /// Errors:
0114   ///   - The result of the fixup expression must fit into an int32, otherwise
0115   ///     an out-of-range error will be returned.
0116   NegDelta32,
0117 
0118   /// A 26-bit PC-relative branch.
0119   ///
0120   /// Represents a PC-relative call or branch to a target within +/-128Mb. The
0121   /// target must be 32-bit aligned.
0122   ///
0123   /// Fixup expression:
0124   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int26
0125   ///
0126   /// Notes:
0127   ///   The '26' in the name refers to the number operand bits and follows the
0128   /// naming convention used by the corresponding ELF and MachO relocations.
0129   /// Since the low two bits must be zero (because of the 32-bit alignment of
0130   /// the target) the operand is effectively a signed 28-bit number.
0131   ///
0132   ///
0133   /// Errors:
0134   ///   - The result of the unshifted part of the fixup expression must be
0135   ///     32-bit aligned otherwise an alignment error will be returned.
0136   ///   - The result of the fixup expression must fit into an int26 otherwise an
0137   ///     out-of-range error will be returned.
0138   Branch26PCRel,
0139 
0140   /// A 14-bit PC-relative test and branch.
0141   ///
0142   /// Represents a PC-relative test and branch to a target within +/-32Kb. The
0143   /// target must be 32-bit aligned.
0144   ///
0145   /// Fixup expression:
0146   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int14
0147   ///
0148   /// Notes:
0149   ///   The '14' in the name refers to the number operand bits and follows the
0150   /// naming convention used by the corresponding ELF relocation.
0151   /// Since the low two bits must be zero (because of the 32-bit alignment of
0152   /// the target) the operand is effectively a signed 16-bit number.
0153   ///
0154   ///
0155   /// Errors:
0156   ///   - The result of the unshifted part of the fixup expression must be
0157   ///     32-bit aligned otherwise an alignment error will be returned.
0158   ///   - The result of the fixup expression must fit into an int14 otherwise an
0159   ///     out-of-range error will be returned.
0160   TestAndBranch14PCRel,
0161 
0162   /// A 19-bit PC-relative conditional branch.
0163   ///
0164   /// Represents a PC-relative conditional branch to a target within +/-1Mb. The
0165   /// target must be 32-bit aligned.
0166   ///
0167   /// Fixup expression:
0168   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int19
0169   ///
0170   /// Notes:
0171   ///   The '19' in the name refers to the number operand bits and follows the
0172   /// naming convention used by the corresponding ELF relocation.
0173   /// Since the low two bits must be zero (because of the 32-bit alignment of
0174   /// the target) the operand is effectively a signed 21-bit number.
0175   ///
0176   ///
0177   /// Errors:
0178   ///   - The result of the unshifted part of the fixup expression must be
0179   ///     32-bit aligned otherwise an alignment error will be returned.
0180   ///   - The result of the fixup expression must fit into an int19 otherwise an
0181   ///     out-of-range error will be returned.
0182   CondBranch19PCRel,
0183 
0184   /// A 16-bit slice of the target address (which slice depends on the
0185   /// instruction at the fixup location).
0186   ///
0187   /// Used to fix up MOVK/MOVN/MOVZ instructions.
0188   ///
0189   /// Fixup expression:
0190   ///
0191   ///   Fixup <- (Target + Addend) >> Shift : uint16
0192   ///
0193   ///   where Shift is encoded in the instruction at the fixup location.
0194   ///
0195   MoveWide16,
0196 
0197   /// The signed 21-bit delta from the fixup to the target.
0198   ///
0199   /// Typically used to load a pointers at a PC-relative offset of +/- 1Mb. The
0200   /// target must be 32-bit aligned.
0201   ///
0202   /// Fixup expression:
0203   ///
0204   ///   Fixup <- (Target - Fixup + Addend) >> 2 : int19
0205   ///
0206   /// Notes:
0207   ///   The '19' in the name refers to the number operand bits and follows the
0208   /// naming convention used by the corresponding ELF relocation.
0209   /// Since the low two bits must be zero (because of the 32-bit alignment of
0210   /// the target) the operand is effectively a signed 21-bit number.
0211   ///
0212   ///
0213   /// Errors:
0214   ///   - The result of the unshifted part of the fixup expression must be
0215   ///     32-bit aligned otherwise an alignment error will be returned.
0216   ///   - The result of the fixup expression must fit into an int19 or an
0217   ///     out-of-range error will be returned.
0218   LDRLiteral19,
0219 
0220   /// The signed 21-bit delta from the fixup to the target.
0221   ///
0222   /// Fixup expression:
0223   ///
0224   ///   Fixup <- Target - Fixup + Addend : int21
0225   ///
0226   /// Notes:
0227   ///   For ADR fixups.
0228   ///
0229   /// Errors:
0230   ///   - The result of the fixup expression must fit into an int21 otherwise an
0231   ///     out-of-range error will be returned.
0232   ADRLiteral21,
0233 
0234   /// The signed 21-bit delta from the fixup page to the page containing the
0235   /// target.
0236   ///
0237   /// Fixup expression:
0238   ///
0239   ///   Fixup <- (((Target + Addend) & ~0xfff) - (Fixup & ~0xfff)) >> 12 : int21
0240   ///
0241   /// Notes:
0242   ///   For ADRP fixups.
0243   ///
0244   /// Errors:
0245   ///   - The result of the fixup expression must fit into an int21 otherwise an
0246   ///     out-of-range error will be returned.
0247   Page21,
0248 
0249   /// The 12-bit (potentially shifted) offset of the target within its page.
0250   ///
0251   /// Typically used to fix up LDR immediates.
0252   ///
0253   /// Fixup expression:
0254   ///
0255   ///   Fixup <- ((Target + Addend) >> Shift) & 0xfff : uint12
0256   ///
0257   ///   where Shift is encoded in the size field of the instruction.
0258   ///
0259   /// Errors:
0260   ///   - The result of the unshifted part of the fixup expression must be
0261   ///     aligned otherwise an alignment error will be returned.
0262   ///   - The result of the fixup expression must fit into a uint12 otherwise an
0263   ///     out-of-range error will be returned.
0264   PageOffset12,
0265 
0266   /// The 15-bit offset of the GOT entry from the GOT table.
0267   ///
0268   /// Used for load/store instructions addressing a GOT entry.
0269   ///
0270   /// Fixup expression:
0271   ///
0272   ///   Fixup <- ((Target + Addend - Page(GOT))) & 0x7fff) >> 3 : uint12
0273   ///
0274   /// Errors:
0275   ///   - The result of the unshifted part of the fixup expression must be
0276   ///     aligned otherwise an alignment error will be returned.
0277   ///   - The result of the fixup expression must fit into a uint12 otherwise an
0278   ///     out-of-range error will be returned.
0279   GotPageOffset15,
0280 
0281   /// A GOT entry getter/constructor, transformed to Page21 pointing at the GOT
0282   /// entry for the original target.
0283   ///
0284   /// Indicates that this edge should be transformed into a Page21 targeting
0285   /// the GOT entry for the edge's current target, maintaining the same addend.
0286   /// A GOT entry for the target should be created if one does not already
0287   /// exist.
0288   ///
0289   /// Edges of this kind are usually handled by a GOT builder pass inserted by
0290   /// default.
0291   ///
0292   /// Fixup expression:
0293   ///   NONE
0294   ///
0295   /// Errors:
0296   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0297   ///     phase will result in an assert/unreachable during the fixup phase.
0298   ///
0299   RequestGOTAndTransformToPage21,
0300 
0301   /// A GOT entry getter/constructor, transformed to Pageoffset12 pointing at
0302   /// the GOT entry for the original target.
0303   ///
0304   /// Indicates that this edge should be transformed into a PageOffset12
0305   /// targeting the GOT entry for the edge's current target, maintaining the
0306   /// same addend. A GOT entry for the target should be created if one does not
0307   /// already exist.
0308   ///
0309   /// Edges of this kind are usually handled by a GOT builder pass inserted by
0310   /// default.
0311   ///
0312   /// Fixup expression:
0313   ///   NONE
0314   ///
0315   /// Errors:
0316   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0317   ///     phase will result in an assert/unreachable during the fixup phase.
0318   ///
0319   RequestGOTAndTransformToPageOffset12,
0320 
0321   /// A GOT entry getter/constructor, transformed to Pageoffset15 pointing at
0322   /// the GOT entry for the original target.
0323   ///
0324   /// Indicates that this edge should be transformed into a GotPageOffset15
0325   /// targeting the GOT entry for the edge's current target, maintaining the
0326   /// same addend. A GOT entry for the target should be created if one does not
0327   /// already exist.
0328   ///
0329   /// Fixup expression:
0330   ///   NONE
0331   ///
0332   /// Errors:
0333   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0334   ///     phase will result in an assert/unreachable during the fixup phase.
0335   ///
0336   RequestGOTAndTransformToPageOffset15,
0337 
0338   /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
0339   /// entry for the original target.
0340   ///
0341   /// Indicates that this edge should be transformed into a Delta32/ targeting
0342   /// the GOT entry for the edge's current target, maintaining the same addend.
0343   /// A GOT entry for the target should be created if one does not already
0344   /// exist.
0345   ///
0346   /// Edges of this kind are usually handled by a GOT builder pass inserted by
0347   /// default.
0348   ///
0349   /// Fixup expression:
0350   ///   NONE
0351   ///
0352   /// Errors:
0353   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0354   ///     phase will result in an assert/unreachable during the fixup phase.
0355   ///
0356   RequestGOTAndTransformToDelta32,
0357 
0358   /// A TLVP entry getter/constructor, transformed to Page21.
0359   ///
0360   /// Indicates that this edge should be transformed into a Page21 targeting the
0361   /// TLVP entry for the edge's current target. A TLVP entry for the target
0362   /// should be created if one does not already exist.
0363   ///
0364   /// Fixup expression:
0365   ///   NONE
0366   ///
0367   /// Errors:
0368   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0369   ///     phase will result in an assert/unreachable during the fixup phase.
0370   ///
0371   RequestTLVPAndTransformToPage21,
0372 
0373   /// A TLVP entry getter/constructor, transformed to PageOffset12.
0374   ///
0375   /// Indicates that this edge should be transformed into a PageOffset12
0376   /// targeting the TLVP entry for the edge's current target. A TLVP entry for
0377   /// the target should be created if one does not already exist.
0378   ///
0379   /// Fixup expression:
0380   ///   NONE
0381   ///
0382   /// Errors:
0383   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0384   ///     phase will result in an assert/unreachable during the fixup phase.
0385   ///
0386   RequestTLVPAndTransformToPageOffset12,
0387 
0388   /// A TLSDesc entry getter/constructor, transformed to Page21.
0389   ///
0390   /// Indicates that this edge should be transformed into a Page21 targeting the
0391   /// TLSDesc entry for the edge's current target. A TLSDesc entry for the
0392   /// target should be created if one does not already exist.
0393   ///
0394   /// Fixup expression:
0395   ///   NONE
0396   ///
0397   /// Errors:
0398   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0399   ///     phase will result in an assert/unreachable during the fixup phase.
0400   ///
0401   RequestTLSDescEntryAndTransformToPage21,
0402 
0403   /// A TLSDesc entry getter/constructor, transformed to PageOffset12.
0404   ///
0405   /// Indicates that this edge should be transformed into a PageOffset12
0406   /// targeting the TLSDesc entry for the edge's current target. A TLSDesc entry
0407   /// for the target should be created if one does not already exist.
0408   ///
0409   /// Fixup expression:
0410   ///   NONE
0411   ///
0412   /// Errors:
0413   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0414   ///     phase will result in an assert/unreachable during the fixup phase.
0415   ///
0416   RequestTLSDescEntryAndTransformToPageOffset12,
0417 };
0418 
0419 /// Returns a string name for the given aarch64 edge. For debugging purposes
0420 /// only
0421 const char *getEdgeKindName(Edge::Kind K);
0422 
0423 // Returns whether the Instr is LD/ST (imm12)
0424 inline bool isLoadStoreImm12(uint32_t Instr) {
0425   constexpr uint32_t LoadStoreImm12Mask = 0x3b000000;
0426   return (Instr & LoadStoreImm12Mask) == 0x39000000;
0427 }
0428 
0429 inline bool isTestAndBranchImm14(uint32_t Instr) {
0430   constexpr uint32_t TestAndBranchImm14Mask = 0x7e000000;
0431   return (Instr & TestAndBranchImm14Mask) == 0x36000000;
0432 }
0433 
0434 inline bool isCondBranchImm19(uint32_t Instr) {
0435   constexpr uint32_t CondBranchImm19Mask = 0xfe000000;
0436   return (Instr & CondBranchImm19Mask) == 0x54000000;
0437 }
0438 
0439 inline bool isCompAndBranchImm19(uint32_t Instr) {
0440   constexpr uint32_t CompAndBranchImm19Mask = 0x7e000000;
0441   return (Instr & CompAndBranchImm19Mask) == 0x34000000;
0442 }
0443 
0444 inline bool isADR(uint32_t Instr) {
0445   constexpr uint32_t ADRMask = 0x9f000000;
0446   return (Instr & ADRMask) == 0x10000000;
0447 }
0448 
0449 inline bool isLDRLiteral(uint32_t Instr) {
0450   constexpr uint32_t LDRLitMask = 0x3b000000;
0451   return (Instr & LDRLitMask) == 0x18000000;
0452 }
0453 
0454 // Returns the amount the address operand of LD/ST (imm12)
0455 // should be shifted right by.
0456 //
0457 // The shift value varies by the data size of LD/ST instruction.
0458 // For instance, LDH instructoin needs the address to be shifted
0459 // right by 1.
0460 inline unsigned getPageOffset12Shift(uint32_t Instr) {
0461   constexpr uint32_t Vec128Mask = 0x04800000;
0462 
0463   if (isLoadStoreImm12(Instr)) {
0464     uint32_t ImplicitShift = Instr >> 30;
0465     if (ImplicitShift == 0)
0466       if ((Instr & Vec128Mask) == Vec128Mask)
0467         ImplicitShift = 4;
0468 
0469     return ImplicitShift;
0470   }
0471 
0472   return 0;
0473 }
0474 
0475 // Returns whether the Instr is MOVK/MOVZ (imm16) with a zero immediate field
0476 inline bool isMoveWideImm16(uint32_t Instr) {
0477   constexpr uint32_t MoveWideImm16Mask = 0x5f9fffe0;
0478   return (Instr & MoveWideImm16Mask) == 0x52800000;
0479 }
0480 
0481 // Returns the amount the address operand of MOVK/MOVZ (imm16)
0482 // should be shifted right by.
0483 //
0484 // The shift value is specfied in the assembly as LSL #<shift>.
0485 inline unsigned getMoveWide16Shift(uint32_t Instr) {
0486   if (isMoveWideImm16(Instr)) {
0487     uint32_t ImplicitShift = (Instr >> 21) & 0b11;
0488     return ImplicitShift << 4;
0489   }
0490 
0491   return 0;
0492 }
0493 
0494 /// Apply fixup expression for edge to block content.
0495 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
0496                         const Symbol *GOTSymbol) {
0497   using namespace support;
0498 
0499   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
0500   char *FixupPtr = BlockWorkingMem + E.getOffset();
0501   orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
0502 
0503   switch (E.getKind()) {
0504   case Pointer64: {
0505     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0506     *(ulittle64_t *)FixupPtr = Value;
0507     break;
0508   }
0509   case Pointer32: {
0510     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0511     if (Value > std::numeric_limits<uint32_t>::max())
0512       return makeTargetOutOfRangeError(G, B, E);
0513     *(ulittle32_t *)FixupPtr = Value;
0514     break;
0515   }
0516   case Delta32:
0517   case Delta64:
0518   case NegDelta32:
0519   case NegDelta64: {
0520     int64_t Value;
0521     if (E.getKind() == Delta32 || E.getKind() == Delta64)
0522       Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
0523     else
0524       Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
0525 
0526     if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
0527       if (Value < std::numeric_limits<int32_t>::min() ||
0528           Value > std::numeric_limits<int32_t>::max())
0529         return makeTargetOutOfRangeError(G, B, E);
0530       *(little32_t *)FixupPtr = Value;
0531     } else
0532       *(little64_t *)FixupPtr = Value;
0533     break;
0534   }
0535   case Branch26PCRel: {
0536     assert((FixupAddress.getValue() & 0x3) == 0 &&
0537            "Branch-inst is not 32-bit aligned");
0538 
0539     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
0540 
0541     if (static_cast<uint64_t>(Value) & 0x3)
0542       return make_error<JITLinkError>("BranchPCRel26 target is not 32-bit "
0543                                       "aligned");
0544 
0545     if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
0546       return makeTargetOutOfRangeError(G, B, E);
0547 
0548     uint32_t RawInstr = *(little32_t *)FixupPtr;
0549     assert((RawInstr & 0x7fffffff) == 0x14000000 &&
0550            "RawInstr isn't a B or BR immediate instruction");
0551     uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
0552     uint32_t FixedInstr = RawInstr | Imm;
0553     *(little32_t *)FixupPtr = FixedInstr;
0554     break;
0555   }
0556   case MoveWide16: {
0557     uint64_t TargetOffset =
0558         (E.getTarget().getAddress() + E.getAddend()).getValue();
0559 
0560     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0561     assert(isMoveWideImm16(RawInstr) &&
0562            "RawInstr isn't a MOVK/MOVZ instruction");
0563 
0564     unsigned ImmShift = getMoveWide16Shift(RawInstr);
0565     uint32_t Imm = (TargetOffset >> ImmShift) & 0xffff;
0566     uint32_t FixedInstr = RawInstr | (Imm << 5);
0567     *(ulittle32_t *)FixupPtr = FixedInstr;
0568     break;
0569   }
0570   case LDRLiteral19: {
0571     assert((FixupAddress.getValue() & 0x3) == 0 && "LDR is not 32-bit aligned");
0572     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0573     assert(isLDRLiteral(RawInstr) && "RawInstr is not an LDR Literal");
0574     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
0575     if (Delta & 0x3)
0576       return make_error<JITLinkError>("LDR literal target is not 32-bit "
0577                                       "aligned");
0578     if (!isInt<21>(Delta))
0579       return makeTargetOutOfRangeError(G, B, E);
0580     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
0581     uint32_t FixedInstr = RawInstr | EncodedImm;
0582     *(ulittle32_t *)FixupPtr = FixedInstr;
0583     break;
0584   }
0585   case ADRLiteral21: {
0586     assert((FixupAddress.getValue() & 0x3) == 0 && "ADR is not 32-bit aligned");
0587     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0588     assert(isADR(RawInstr) && "RawInstr is not an ADR");
0589     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
0590     if (!isInt<21>(Delta))
0591       return makeTargetOutOfRangeError(G, B, E);
0592     auto UDelta = static_cast<uint32_t>(Delta);
0593     uint32_t EncodedImmHi = ((UDelta >> 2) & 0x7ffff) << 5;
0594     uint32_t EncodedImmLo = (UDelta & 0x3) << 29;
0595     uint32_t FixedInstr = RawInstr | EncodedImmHi | EncodedImmLo;
0596     *(ulittle32_t *)FixupPtr = FixedInstr;
0597     break;
0598   }
0599   case TestAndBranch14PCRel: {
0600     assert((FixupAddress.getValue() & 0x3) == 0 &&
0601            "Test and branch is not 32-bit aligned");
0602     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0603     assert(isTestAndBranchImm14(RawInstr) &&
0604            "RawInstr is not a test and branch");
0605     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
0606     if (Delta & 0x3)
0607       return make_error<JITLinkError>(
0608           "Test and branch literal target is not 32-bit aligned");
0609     if (!isInt<16>(Delta))
0610       return makeTargetOutOfRangeError(G, B, E);
0611     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x3fff) << 5;
0612     uint32_t FixedInstr = RawInstr | EncodedImm;
0613     *(ulittle32_t *)FixupPtr = FixedInstr;
0614     break;
0615   }
0616   case CondBranch19PCRel: {
0617     assert((FixupAddress.getValue() & 0x3) == 0 &&
0618            "Conditional branch is not 32-bit aligned");
0619     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0620     assert((isCondBranchImm19(RawInstr) || isCompAndBranchImm19(RawInstr)) &&
0621            "RawInstr is not a conditional branch");
0622     int64_t Delta = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
0623     if (Delta & 0x3)
0624       return make_error<JITLinkError>(
0625           "Conditional branch literal target is not 32-bit "
0626           "aligned");
0627     if (!isInt<21>(Delta))
0628       return makeTargetOutOfRangeError(G, B, E);
0629     uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
0630     uint32_t FixedInstr = RawInstr | EncodedImm;
0631     *(ulittle32_t *)FixupPtr = FixedInstr;
0632     break;
0633   }
0634   case Page21: {
0635     uint64_t TargetPage =
0636         (E.getTarget().getAddress().getValue() + E.getAddend()) &
0637         ~static_cast<uint64_t>(4096 - 1);
0638     uint64_t PCPage =
0639         FixupAddress.getValue() & ~static_cast<uint64_t>(4096 - 1);
0640 
0641     int64_t PageDelta = TargetPage - PCPage;
0642     if (!isInt<33>(PageDelta))
0643       return makeTargetOutOfRangeError(G, B, E);
0644 
0645     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0646     assert((RawInstr & 0xffffffe0) == 0x90000000 &&
0647            "RawInstr isn't an ADRP instruction");
0648     uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
0649     uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
0650     uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
0651     *(ulittle32_t *)FixupPtr = FixedInstr;
0652     break;
0653   }
0654   case PageOffset12: {
0655     uint64_t TargetOffset =
0656         (E.getTarget().getAddress() + E.getAddend()).getValue() & 0xfff;
0657 
0658     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0659     unsigned ImmShift = getPageOffset12Shift(RawInstr);
0660 
0661     if (TargetOffset & ((1 << ImmShift) - 1))
0662       return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
0663 
0664     uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
0665     uint32_t FixedInstr = RawInstr | EncodedImm;
0666     *(ulittle32_t *)FixupPtr = FixedInstr;
0667     break;
0668   }
0669   case GotPageOffset15: {
0670     assert(GOTSymbol && "No GOT section symbol");
0671     uint64_t TargetOffset =
0672         (E.getTarget().getAddress() + E.getAddend()).getValue() -
0673         (GOTSymbol->getAddress().getValue() & ~static_cast<uint64_t>(4096 - 1));
0674     if (TargetOffset > 0x7fff)
0675       return make_error<JITLinkError>("PAGEOFF15 target is out of range");
0676 
0677     uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0678     const unsigned ImmShift = 3;
0679     if (TargetOffset & ((1 << ImmShift) - 1))
0680       return make_error<JITLinkError>("PAGEOFF15 target is not aligned");
0681 
0682     uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
0683     uint32_t FixedInstr = RawInstr | EncodedImm;
0684     *(ulittle32_t *)FixupPtr = FixedInstr;
0685     break;
0686   }
0687   default:
0688     return make_error<JITLinkError>(
0689         "In graph " + G.getName() + ", section " + B.getSection().getName() +
0690         " unsupported edge kind " + getEdgeKindName(E.getKind()));
0691   }
0692 
0693   return Error::success();
0694 }
0695 
0696 /// aarch64 pointer size.
0697 constexpr uint64_t PointerSize = 8;
0698 
0699 /// AArch64 null pointer content.
0700 extern const char NullPointerContent[PointerSize];
0701 
0702 /// AArch64 pointer jump stub content.
0703 ///
0704 /// Contains the instruction sequence for an indirect jump via an in-memory
0705 /// pointer:
0706 ///   ADRP x16, ptr@page21
0707 ///   LDR  x16, [x16, ptr@pageoff12]
0708 ///   BR   x16
0709 extern const char PointerJumpStubContent[12];
0710 
0711 /// Creates a new pointer block in the given section and returns an
0712 /// Anonymous symbol pointing to it.
0713 ///
0714 /// If InitialTarget is given then an Pointer64 relocation will be added to the
0715 /// block pointing at InitialTarget.
0716 ///
0717 /// The pointer block will have the following default values:
0718 ///   alignment: 64-bit
0719 ///   alignment-offset: 0
0720 ///   address: highest allowable (~7U)
0721 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
0722                                       Symbol *InitialTarget = nullptr,
0723                                       uint64_t InitialAddend = 0) {
0724   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
0725                                  orc::ExecutorAddr(~uint64_t(7)), 8, 0);
0726   if (InitialTarget)
0727     B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
0728   return G.addAnonymousSymbol(B, 0, 8, false, false);
0729 }
0730 
0731 /// Create a jump stub block that jumps via the pointer at the given symbol.
0732 ///
0733 /// The stub block will have the following default values:
0734 ///   alignment: 32-bit
0735 ///   alignment-offset: 0
0736 ///   address: highest allowable: (~11U)
0737 inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
0738                                          Symbol &PointerSymbol) {
0739   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
0740                                  orc::ExecutorAddr(~uint64_t(11)), 4, 0);
0741   B.addEdge(Page21, 0, PointerSymbol, 0);
0742   B.addEdge(PageOffset12, 4, PointerSymbol, 0);
0743   return B;
0744 }
0745 
0746 /// Create a jump stub that jumps via the pointer at the given symbol and
0747 /// an anonymous symbol pointing to it. Return the anonymous symbol.
0748 ///
0749 /// The stub block will be created by createPointerJumpStubBlock.
0750 inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
0751                                               Section &StubSection,
0752                                               Symbol &PointerSymbol) {
0753   return G.addAnonymousSymbol(
0754       createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0,
0755       sizeof(PointerJumpStubContent), true, false);
0756 }
0757 
0758 /// AArch64 reentry trampoline.
0759 ///
0760 /// Contains the instruction sequence for a trampoline that stores its return
0761 /// address (and stack pointer) on the stack and calls the given reentry symbol:
0762 ///   STP  x29, x30, [sp, #-16]!
0763 ///   BL   <reentry-symbol>
0764 extern const char ReentryTrampolineContent[8];
0765 
0766 /// Create a block of N reentry trampolines.
0767 inline Block &createReentryTrampolineBlock(LinkGraph &G,
0768                                            Section &TrampolineSection,
0769                                            Symbol &ReentrySymbol) {
0770   auto &B = G.createContentBlock(TrampolineSection, ReentryTrampolineContent,
0771                                  orc::ExecutorAddr(~uint64_t(7)), 4, 0);
0772   B.addEdge(Branch26PCRel, 4, ReentrySymbol, 0);
0773   return B;
0774 }
0775 
0776 inline Symbol &createAnonymousReentryTrampoline(LinkGraph &G,
0777                                                 Section &TrampolineSection,
0778                                                 Symbol &ReentrySymbol) {
0779   return G.addAnonymousSymbol(
0780       createReentryTrampolineBlock(G, TrampolineSection, ReentrySymbol), 0,
0781       sizeof(ReentryTrampolineContent), true, false);
0782 }
0783 
0784 /// Global Offset Table Builder.
0785 class GOTTableManager : public TableManager<GOTTableManager> {
0786 public:
0787   static StringRef getSectionName() { return "$__GOT"; }
0788 
0789   GOTTableManager(LinkGraph &G) {
0790     if ((GOTSection = G.findSectionByName(getSectionName())))
0791       registerExistingEntries();
0792   }
0793 
0794   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
0795     Edge::Kind KindToSet = Edge::Invalid;
0796     const char *BlockWorkingMem = B->getContent().data();
0797     const char *FixupPtr = BlockWorkingMem + E.getOffset();
0798 
0799     switch (E.getKind()) {
0800     case aarch64::RequestGOTAndTransformToPage21:
0801     case aarch64::RequestTLVPAndTransformToPage21: {
0802       KindToSet = aarch64::Page21;
0803       break;
0804     }
0805     case aarch64::RequestGOTAndTransformToPageOffset12:
0806     case aarch64::RequestTLVPAndTransformToPageOffset12: {
0807       KindToSet = aarch64::PageOffset12;
0808       uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
0809       (void)RawInstr;
0810       assert(E.getAddend() == 0 &&
0811              "GOTPageOffset12/TLVPageOffset12 with non-zero addend");
0812       assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
0813              "RawInstr isn't a 64-bit LDR immediate");
0814       break;
0815     }
0816     case aarch64::RequestGOTAndTransformToPageOffset15: {
0817       KindToSet = aarch64::GotPageOffset15;
0818       uint32_t RawInstr = *(const support::ulittle32_t *)FixupPtr;
0819       (void)RawInstr;
0820       assert(E.getAddend() == 0 && "GOTPageOffset15 with non-zero addend");
0821       assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
0822              "RawInstr isn't a 64-bit LDR immediate");
0823       break;
0824     }
0825     case aarch64::RequestGOTAndTransformToDelta32: {
0826       KindToSet = aarch64::Delta32;
0827       break;
0828     }
0829     default:
0830       return false;
0831     }
0832     assert(KindToSet != Edge::Invalid &&
0833            "Fell through switch, but no new kind to set");
0834     DEBUG_WITH_TYPE("jitlink", {
0835       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
0836              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
0837              << formatv("{0:x}", E.getOffset()) << ")\n";
0838     });
0839     E.setKind(KindToSet);
0840     E.setTarget(getEntryForTarget(G, E.getTarget()));
0841     return true;
0842   }
0843 
0844   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
0845     return createAnonymousPointer(G, getGOTSection(G), &Target);
0846   }
0847 
0848 private:
0849   Section &getGOTSection(LinkGraph &G) {
0850     if (!GOTSection)
0851       GOTSection = &G.createSection(getSectionName(),
0852                                     orc::MemProt::Read | orc::MemProt::Exec);
0853     return *GOTSection;
0854   }
0855 
0856   void registerExistingEntries();
0857 
0858   Section *GOTSection = nullptr;
0859 };
0860 
0861 /// Procedure Linkage Table Builder.
0862 class PLTTableManager : public TableManager<PLTTableManager> {
0863 public:
0864   static StringRef getSectionName() { return "$__STUBS"; }
0865 
0866   PLTTableManager(LinkGraph &G, GOTTableManager &GOT) : GOT(GOT) {
0867     if ((StubsSection = G.findSectionByName(getSectionName())))
0868       registerExistingEntries();
0869   }
0870 
0871   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
0872     if (E.getKind() == aarch64::Branch26PCRel && !E.getTarget().isDefined()) {
0873       DEBUG_WITH_TYPE("jitlink", {
0874         dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
0875                << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
0876                << formatv("{0:x}", E.getOffset()) << ")\n";
0877       });
0878       E.setTarget(getEntryForTarget(G, E.getTarget()));
0879       return true;
0880     }
0881     return false;
0882   }
0883 
0884   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
0885     return createAnonymousPointerJumpStub(G, getStubsSection(G),
0886                                           GOT.getEntryForTarget(G, Target));
0887   }
0888 
0889 public:
0890   Section &getStubsSection(LinkGraph &G) {
0891     if (!StubsSection)
0892       StubsSection = &G.createSection(getSectionName(),
0893                                       orc::MemProt::Read | orc::MemProt::Exec);
0894     return *StubsSection;
0895   }
0896 
0897   void registerExistingEntries();
0898 
0899   GOTTableManager &GOT;
0900   Section *StubsSection = nullptr;
0901 };
0902 
0903 /// Returns the name of the pointer signing function section.
0904 const char *getPointerSigningFunctionSectionName();
0905 
0906 /// Creates a pointer signing function section, block, and symbol to reserve
0907 /// space for a signing function for this LinkGraph. Clients should insert this
0908 /// pass in the post-prune phase, and add the paired
0909 /// lowerPointer64AuthEdgesToSigningFunction pass to the pre-fixup phase.
0910 ///
0911 /// No new Pointer64Auth edges can be inserted into the graph between when this
0912 /// pass is run and when the pass below runs (since there will not be sufficient
0913 /// space reserved in the signing function to write the signing code for them).
0914 Error createEmptyPointerSigningFunction(LinkGraph &G);
0915 
0916 /// Given a LinkGraph containing Pointer64Authenticated edges, transform those
0917 /// edges to Pointer64 and add signing code to the pointer signing function
0918 /// (which must already have been created by the
0919 /// createEmptyPointerSigningFunction pass above).
0920 ///
0921 /// This function will add a $__ptrauth_sign section with finalization-lifetime
0922 /// containing an anonymous function that will sign all pointers in the graph.
0923 /// An allocation action will be added to run this function during finalization.
0924 Error lowerPointer64AuthEdgesToSigningFunction(LinkGraph &G);
0925 
0926 } // namespace aarch64
0927 } // namespace jitlink
0928 } // namespace llvm
0929 
0930 #endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH64_H