Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //===-- x86_64.h - Generic JITLink x86-64 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 x86-64 objects.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
0014 #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
0015 
0016 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
0017 #include "llvm/ExecutionEngine/JITLink/TableManager.h"
0018 
0019 namespace llvm {
0020 namespace jitlink {
0021 namespace x86_64 {
0022 
0023 /// Represents x86-64 fixups and other x86-64-specific edge kinds.
0024 enum EdgeKind_x86_64 : Edge::Kind {
0025 
0026   /// A plain 64-bit pointer value relocation.
0027   ///
0028   /// Fixup expression:
0029   ///   Fixup <- Target + Addend : uint64
0030   ///
0031   Pointer64 = Edge::FirstRelocation,
0032 
0033   /// A plain 32-bit pointer value relocation.
0034   ///
0035   /// Fixup expression:
0036   ///   Fixup <- Target + Addend : uint32
0037   ///
0038   /// Errors:
0039   ///   - The target must reside in the low 32-bits of the address space,
0040   ///     otherwise an out-of-range error will be returned.
0041   ///
0042   Pointer32,
0043 
0044   /// A signed 32-bit pointer value relocation
0045   ///
0046   /// Fixup expression:
0047   ///   Fixup <- Target + Addend : int32
0048   ///
0049   /// Errors:
0050   ///   - The target must reside in the signed 32-bits([-2**31, 2**32 - 1]) of
0051   ///   the address space, otherwise an out-of-range error will be returned.
0052   Pointer32Signed,
0053 
0054   /// A plain 16-bit pointer value relocation.
0055   ///
0056   /// Fixup expression:
0057   ///   Fixup <- Target + Addend : uint16
0058   ///
0059   /// Errors:
0060   ///   - The target must reside in the low 16-bits of the address space,
0061   ///     otherwise an out-of-range error will be returned.
0062   ///
0063   Pointer16,
0064 
0065   /// A plain 8-bit pointer value relocation.
0066   ///
0067   /// Fixup expression:
0068   ///   Fixup <- Target + Addend : uint8
0069   ///
0070   /// Errors:
0071   ///   - The target must reside in the low 8-bits of the address space,
0072   ///     otherwise an out-of-range error will be returned.
0073   ///
0074   Pointer8,
0075 
0076   /// A 64-bit delta.
0077   ///
0078   /// Delta from the fixup to the target.
0079   ///
0080   /// Fixup expression:
0081   ///   Fixup <- Target - Fixup + Addend : int64
0082   ///
0083   Delta64,
0084 
0085   /// A 32-bit delta.
0086   ///
0087   /// Delta from the fixup to the target.
0088   ///
0089   /// Fixup expression:
0090   ///   Fixup <- Target - Fixup + Addend : int32
0091   ///
0092   /// Errors:
0093   ///   - The result of the fixup expression must fit into an int32, otherwise
0094   ///     an out-of-range error will be returned.
0095   ///
0096   Delta32,
0097 
0098   /// A 16-bit delta.
0099   ///
0100   /// Delta from the fixup to the target.
0101   ///
0102   /// Fixup expression:
0103   ///   Fixup <- Target - Fixup + Addend : int16
0104   ///
0105   /// Errors:
0106   ///   - The result of the fixup expression must fit into an int16, otherwise
0107   ///     an out-of-range error will be returned.
0108   ///
0109   Delta16,
0110 
0111   /// An 8-bit delta.
0112   ///
0113   /// Delta from the fixup to the target.
0114   ///
0115   /// Fixup expression:
0116   ///   Fixup <- Target - Fixup + Addend : int8
0117   ///
0118   /// Errors:
0119   ///   - The result of the fixup expression must fit into an int8, otherwise
0120   ///     an out-of-range error will be returned.
0121   ///
0122   Delta8,
0123 
0124   /// A 64-bit negative delta.
0125   ///
0126   /// Delta from target back to the fixup.
0127   ///
0128   /// Fixup expression:
0129   ///   Fixup <- Fixup - Target + Addend : int64
0130   ///
0131   NegDelta64,
0132 
0133   /// A 32-bit negative delta.
0134   ///
0135   /// Delta from the target back to the fixup.
0136   ///
0137   /// Fixup expression:
0138   ///   Fixup <- Fixup - Target + Addend : int32
0139   ///
0140   /// Errors:
0141   ///   - The result of the fixup expression must fit into an int32, otherwise
0142   ///     an out-of-range error will be returned.
0143   NegDelta32,
0144 
0145   /// A 64-bit size relocation.
0146   ///
0147   /// Fixup expression:
0148   ///   Fixup <- Size + Addend : uint64
0149   ///
0150   Size64,
0151 
0152   /// A 32-bit size relocation.
0153   ///
0154   /// Fixup expression:
0155   ///   Fixup <- Size + Addend : uint32
0156   ///
0157   /// Errors:
0158   ///   - The result of the fixup expression must fit into an uint32, otherwise
0159   ///     an out-of-range error will be returned.
0160   ///
0161   Size32,
0162 
0163   /// A 64-bit GOT delta.
0164   ///
0165   /// Delta from the global offset table to the target
0166   ///
0167   /// Fixup expression:
0168   ///   Fixup <- Target - GOTSymbol + Addend : int64
0169   ///
0170   /// Errors:
0171   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
0172   ///     symbol was not been defined.
0173   Delta64FromGOT,
0174 
0175   /// A 32-bit PC-relative branch.
0176   ///
0177   /// Represents a PC-relative call or branch to a target. This can be used to
0178   /// identify, record, and/or patch call sites.
0179   ///
0180   /// The fixup expression for this kind includes an implicit offset to account
0181   /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target
0182   /// T and addend zero is a call/branch to the start (offset zero) of T.
0183   ///
0184   /// Fixup expression:
0185   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
0186   ///
0187   /// Errors:
0188   ///   - The result of the fixup expression must fit into an int32, otherwise
0189   ///     an out-of-range error will be returned.
0190   ///
0191   BranchPCRel32,
0192 
0193   /// A 32-bit PC-relative relocation.
0194   ///
0195   /// Represents a data/control flow instruction using PC-relative addressing
0196   /// to a target.
0197   ///
0198   /// The fixup expression for this kind includes an implicit offset to account
0199   /// for the PC (unlike the Delta edges) so that a PCRel32 with a target
0200   /// T and addend zero is a call/branch to the start (offset zero) of T.
0201   ///
0202   /// Fixup expression:
0203   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
0204   ///
0205   /// Errors:
0206   ///   - The result of the fixup expression must fit into an int32, otherwise
0207   ///     an out-of-range error will be returned.
0208   ///
0209   PCRel32,
0210 
0211   /// A 32-bit PC-relative branch to a pointer jump stub.
0212   ///
0213   /// The target of this relocation should be a pointer jump stub of the form:
0214   ///
0215   /// \code{.s}
0216   ///   .text
0217   ///   jmpq *tgtptr(%rip)
0218   ///   ; ...
0219   ///
0220   ///   .data
0221   ///   tgtptr:
0222   ///     .quad 0
0223   /// \endcode
0224   ///
0225   /// This edge kind has the same fixup expression as BranchPCRel32, but further
0226   /// identifies the call/branch as being to a pointer jump stub. For edges of
0227   /// this kind the jump stub should not be bypassed (use
0228   /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location
0229   /// target may be recorded to allow manipulation at runtime.
0230   ///
0231   /// Fixup expression:
0232   ///   Fixup <- Target - Fixup + Addend - 4 : int32
0233   ///
0234   /// Errors:
0235   ///   - The result of the fixup expression must fit into an int32, otherwise
0236   ///     an out-of-range error will be returned.
0237   ///
0238   BranchPCRel32ToPtrJumpStub,
0239 
0240   /// A relaxable version of BranchPCRel32ToPtrJumpStub.
0241   ///
0242   /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
0243   /// but identifies the call/branch as being to a pointer jump stub that may be
0244   /// bypassed with a direct jump to the ultimate target if the ultimate target
0245   /// is within range of the fixup location.
0246   ///
0247   /// Fixup expression:
0248   ///   Fixup <- Target - Fixup + Addend - 4: int32
0249   ///
0250   /// Errors:
0251   ///   - The result of the fixup expression must fit into an int32, otherwise
0252   ///     an out-of-range error will be returned.
0253   ///
0254   BranchPCRel32ToPtrJumpStubBypassable,
0255 
0256   /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
0257   /// entry for the original target.
0258   ///
0259   /// Indicates that this edge should be transformed into a Delta32 targeting
0260   /// the GOT entry for the edge's current target, maintaining the same addend.
0261   /// A GOT entry for the target should be created if one does not already
0262   /// exist.
0263   ///
0264   /// Edges of this kind are usually handled by a GOT builder pass inserted by
0265   /// default.
0266   ///
0267   /// Fixup expression:
0268   ///   NONE
0269   ///
0270   /// Errors:
0271   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0272   ///     phase will result in an assert/unreachable during the fixup phase.
0273   ///
0274   RequestGOTAndTransformToDelta32,
0275 
0276   /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
0277   /// entry for the original target.
0278   ///
0279   /// Indicates that this edge should be transformed into a Delta64 targeting
0280   /// the GOT entry for the edge's current target, maintaining the same addend.
0281   /// A GOT entry for the target should be created if one does not already
0282   /// exist.
0283   ///
0284   /// Edges of this kind are usually handled by a GOT builder pass inserted by
0285   /// default.
0286   ///
0287   /// Fixup expression:
0288   ///   NONE
0289   ///
0290   /// Errors:
0291   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0292   ///     phase will result in an assert/unreachable during the fixup phase.
0293   ///
0294   RequestGOTAndTransformToDelta64,
0295 
0296   /// A GOT entry offset within GOT getter/constructor, transformed to
0297   /// Delta64FromGOT
0298   /// pointing at the GOT entry for the original target
0299   ///
0300   /// Indicates that this edge should be transformed into a Delta64FromGOT
0301   /// targeting
0302   /// the GOT entry for the edge's current target, maintaining the same addend.
0303   /// A GOT entry for the target should be created if one does not already
0304   /// exist.
0305   ///
0306   /// Edges of this kind are usually handled by a GOT builder pass inserted by
0307   /// default
0308   ///
0309   /// Fixup expression:
0310   ///   NONE
0311   ///
0312   /// Errors:
0313   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0314   ///     phase will result in an assert/unreachable during the fixup phase
0315   RequestGOTAndTransformToDelta64FromGOT,
0316 
0317   /// A PC-relative load of a GOT entry, relaxable if GOT entry target is
0318   /// in-range of the fixup
0319   ///
0320   /// TODO: Explain the optimization
0321   ///
0322   /// Fixup expression
0323   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
0324   ///
0325   /// Errors:
0326   ///   - The result of the fixup expression must fit into an int32, otherwise
0327   ///     an out-of-range error will be returned.
0328   //
0329   PCRel32GOTLoadRelaxable,
0330 
0331   /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target
0332   /// is in-range of the fixup.
0333   ///
0334   /// If the GOT entry target is in-range of the fixup then the load from the
0335   /// GOT may be replaced with a direct memory address calculation.
0336   ///
0337   /// Fixup expression:
0338   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
0339   ///
0340   /// Errors:
0341   ///   - The result of the fixup expression must fit into an int32, otherwise
0342   ///     an out-of-range error will be returned.
0343   ///
0344   PCRel32GOTLoadREXRelaxable,
0345 
0346   /// A GOT entry getter/constructor, transformed to
0347   /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original
0348   /// target.
0349   ///
0350   /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable
0351   /// targeting the GOT entry for the edge's current target, maintaining the
0352   /// same addend. A GOT entry for the target should be created if one does not
0353   /// already exist.
0354   ///
0355   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
0356   /// default.
0357   ///
0358   /// Fixup expression:
0359   ///   NONE
0360   ///
0361   /// Errors:
0362   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0363   ///     phase will result in an assert/unreachable during the fixup phase.
0364   ///
0365   RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable,
0366 
0367   /// A GOT entry getter/constructor, transformed to
0368   /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original
0369   /// target.
0370   ///
0371   /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable
0372   /// targeting the GOT entry for the edge's current target, maintaining the
0373   /// same addend. A GOT entry for the target should be created if one does not
0374   /// already exist.
0375   ///
0376   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
0377   /// default.
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   RequestGOTAndTransformToPCRel32GOTLoadRelaxable,
0387 
0388   /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry,
0389   /// relaxable if the TLVP entry target is in-range of the fixup.
0390   ///
0391   /// If the TLVP entry target is in-range of the fixup then the load from the
0392   /// TLVP may be replaced with a direct memory address calculation.
0393   ///
0394   /// The target of this edge must be a thread local variable entry of the form
0395   ///   .quad <tlv getter thunk>
0396   ///   .quad <tlv key>
0397   ///   .quad <tlv initializer>
0398   ///
0399   /// Fixup expression:
0400   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
0401   ///
0402   /// Errors:
0403   ///   - The result of the fixup expression must fit into an int32, otherwise
0404   ///     an out-of-range error will be returned.
0405   ///   - The target must be either external, or a TLV entry of the required
0406   ///     form, otherwise a malformed TLV entry error will be returned.
0407   ///
0408   PCRel32TLVPLoadREXRelaxable,
0409 
0410   /// TODO: Explain the generic edge kind
0411   RequestTLSDescInGOTAndTransformToDelta32,
0412 
0413   /// A TLVP entry getter/constructor, transformed to
0414   /// Delta32ToTLVPLoadREXRelaxable.
0415   ///
0416   /// Indicates that this edge should be transformed into a
0417   /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's
0418   /// current target. A TLVP entry for the target should be created if one does
0419   /// not already exist.
0420   ///
0421   /// Fixup expression:
0422   ///   NONE
0423   ///
0424   /// Errors:
0425   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
0426   ///     phase will result in an assert/unreachable during the fixup phase.
0427   ///
0428   RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable,
0429   // First platform specific relocation.
0430   FirstPlatformRelocation
0431 };
0432 
0433 /// Returns a string name for the given x86-64 edge. For debugging purposes
0434 /// only.
0435 const char *getEdgeKindName(Edge::Kind K);
0436 
0437 /// Apply fixup expression for edge to block content.
0438 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
0439                         const Symbol *GOTSymbol) {
0440   using namespace support;
0441 
0442   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
0443   char *FixupPtr = BlockWorkingMem + E.getOffset();
0444   auto FixupAddress = B.getAddress() + E.getOffset();
0445 
0446   switch (E.getKind()) {
0447 
0448   case Pointer64: {
0449     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0450     *(ulittle64_t *)FixupPtr = Value;
0451     break;
0452   }
0453 
0454   case Pointer32: {
0455     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0456     if (LLVM_LIKELY(isUInt<32>(Value)))
0457       *(ulittle32_t *)FixupPtr = Value;
0458     else
0459       return makeTargetOutOfRangeError(G, B, E);
0460     break;
0461   }
0462   case Pointer32Signed: {
0463     int64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0464     if (LLVM_LIKELY(isInt<32>(Value)))
0465       *(little32_t *)FixupPtr = Value;
0466     else
0467       return makeTargetOutOfRangeError(G, B, E);
0468     break;
0469   }
0470 
0471   case Pointer16: {
0472     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0473     if (LLVM_LIKELY(isUInt<16>(Value)))
0474       *(ulittle16_t *)FixupPtr = Value;
0475     else
0476       return makeTargetOutOfRangeError(G, B, E);
0477     break;
0478   }
0479 
0480   case Pointer8: {
0481     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
0482     if (LLVM_LIKELY(isUInt<8>(Value)))
0483       *(uint8_t *)FixupPtr = Value;
0484     else
0485       return makeTargetOutOfRangeError(G, B, E);
0486     break;
0487   }
0488 
0489   case PCRel32:
0490   case BranchPCRel32:
0491   case BranchPCRel32ToPtrJumpStub:
0492   case BranchPCRel32ToPtrJumpStubBypassable:
0493   case PCRel32GOTLoadRelaxable:
0494   case PCRel32GOTLoadREXRelaxable:
0495   case PCRel32TLVPLoadREXRelaxable: {
0496     int64_t Value =
0497         E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
0498     if (LLVM_LIKELY(isInt<32>(Value)))
0499       *(little32_t *)FixupPtr = Value;
0500     else
0501       return makeTargetOutOfRangeError(G, B, E);
0502     break;
0503   }
0504 
0505   case Delta64: {
0506     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
0507     *(little64_t *)FixupPtr = Value;
0508     break;
0509   }
0510 
0511   case Delta32: {
0512     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
0513     if (LLVM_LIKELY(isInt<32>(Value)))
0514       *(little32_t *)FixupPtr = Value;
0515     else
0516       return makeTargetOutOfRangeError(G, B, E);
0517     break;
0518   }
0519 
0520   case Delta16: {
0521     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
0522     if (LLVM_LIKELY(isInt<16>(Value)))
0523       *(little16_t *)FixupPtr = Value;
0524     else
0525       return makeTargetOutOfRangeError(G, B, E);
0526     break;
0527   }
0528 
0529   case Delta8: {
0530     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
0531     if (LLVM_LIKELY(isInt<8>(Value)))
0532       *FixupPtr = Value;
0533     else
0534       return makeTargetOutOfRangeError(G, B, E);
0535     break;
0536   }
0537 
0538   case NegDelta64: {
0539     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
0540     *(little64_t *)FixupPtr = Value;
0541     break;
0542   }
0543 
0544   case NegDelta32: {
0545     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
0546     if (LLVM_LIKELY(isInt<32>(Value)))
0547       *(little32_t *)FixupPtr = Value;
0548     else
0549       return makeTargetOutOfRangeError(G, B, E);
0550     break;
0551   }
0552 
0553   case Size64: {
0554     uint64_t Value = E.getTarget().getSize() + E.getAddend();
0555     *(ulittle64_t *)FixupPtr = Value;
0556     break;
0557   }
0558 
0559   case Size32: {
0560     uint64_t Value = E.getTarget().getSize() + E.getAddend();
0561     if (LLVM_LIKELY(isUInt<32>(Value)))
0562       *(ulittle32_t *)FixupPtr = Value;
0563     else
0564       return makeTargetOutOfRangeError(G, B, E);
0565     break;
0566   }
0567 
0568   case Delta64FromGOT: {
0569     assert(GOTSymbol && "No GOT section symbol");
0570     int64_t Value =
0571         E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
0572     *(little64_t *)FixupPtr = Value;
0573     break;
0574   }
0575 
0576   default:
0577     return make_error<JITLinkError>(
0578         "In graph " + G.getName() + ", section " + B.getSection().getName() +
0579         " unsupported edge kind " + getEdgeKindName(E.getKind()));
0580   }
0581 
0582   return Error::success();
0583 }
0584 
0585 /// x86_64 pointer size.
0586 constexpr uint64_t PointerSize = 8;
0587 
0588 /// x86-64 null pointer content.
0589 extern const char NullPointerContent[PointerSize];
0590 
0591 /// x86-64 pointer jump stub content.
0592 ///
0593 /// Contains the instruction sequence for an indirect jump via an in-memory
0594 /// pointer:
0595 ///   jmpq *ptr(%rip)
0596 extern const char PointerJumpStubContent[6];
0597 
0598 /// Creates a new pointer block in the given section and returns an anonymous
0599 /// symbol pointing to it.
0600 ///
0601 /// If InitialTarget is given then an Pointer64 relocation will be added to the
0602 /// block pointing at InitialTarget.
0603 ///
0604 /// The pointer block will have the following default values:
0605 ///   alignment: 64-bit
0606 ///   alignment-offset: 0
0607 ///   address: highest allowable (~7U)
0608 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
0609                                       Symbol *InitialTarget = nullptr,
0610                                       uint64_t InitialAddend = 0) {
0611   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
0612                                  orc::ExecutorAddr(~uint64_t(7)), 8, 0);
0613   if (InitialTarget)
0614     B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
0615   return G.addAnonymousSymbol(B, 0, 8, false, false);
0616 }
0617 
0618 /// Create a jump stub block that jumps via the pointer at the given symbol.
0619 ///
0620 /// The stub block will have the following default values:
0621 ///   alignment: 8-bit
0622 ///   alignment-offset: 0
0623 ///   address: highest allowable: (~5U)
0624 inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
0625                                          Symbol &PointerSymbol) {
0626   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
0627                                  orc::ExecutorAddr(~uint64_t(5)), 1, 0);
0628   B.addEdge(BranchPCRel32, 2, PointerSymbol, 0);
0629   return B;
0630 }
0631 
0632 /// Create a jump stub that jumps via the pointer at the given symbol and
0633 /// an anonymous symbol pointing to it. Return the anonymous symbol.
0634 ///
0635 /// The stub block will be created by createPointerJumpStubBlock.
0636 inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
0637                                               Section &StubSection,
0638                                               Symbol &PointerSymbol) {
0639   return G.addAnonymousSymbol(
0640       createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
0641       false);
0642 }
0643 
0644 /// x86-64 reentry trampoline.
0645 ///
0646 /// Contains the instruction sequence for a trampoline that stores its return
0647 /// address on the stack and calls <reentry-symbol>:
0648 ///   call  <reentry-symbol>
0649 extern const char ReentryTrampolineContent[5];
0650 
0651 /// Create a block of N reentry trampolines.
0652 inline Block &createReentryTrampolineBlock(LinkGraph &G,
0653                                            Section &TrampolineSection,
0654                                            Symbol &ReentrySymbol) {
0655   auto &B = G.createContentBlock(TrampolineSection, ReentryTrampolineContent,
0656                                  orc::ExecutorAddr(~uint64_t(7)), 1, 0);
0657   B.addEdge(BranchPCRel32, 1, ReentrySymbol, 0);
0658   return B;
0659 }
0660 
0661 inline Symbol &createAnonymousReentryTrampoline(LinkGraph &G,
0662                                                 Section &TrampolineSection,
0663                                                 Symbol &ReentrySymbol) {
0664   return G.addAnonymousSymbol(
0665       createReentryTrampolineBlock(G, TrampolineSection, ReentrySymbol), 0,
0666       sizeof(ReentryTrampolineContent), true, false);
0667 }
0668 
0669 /// Global Offset Table Builder.
0670 class GOTTableManager : public TableManager<GOTTableManager> {
0671 public:
0672   static StringRef getSectionName() { return "$__GOT"; }
0673 
0674   GOTTableManager(LinkGraph &G) {
0675     if ((GOTSection = G.findSectionByName(getSectionName())))
0676       registerExistingEntries();
0677   }
0678 
0679   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
0680     Edge::Kind KindToSet = Edge::Invalid;
0681     switch (E.getKind()) {
0682     case x86_64::Delta64FromGOT: {
0683       // we need to make sure that the GOT section exists, but don't otherwise
0684       // need to fix up this edge
0685       getGOTSection(G);
0686       return false;
0687     }
0688     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
0689       KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
0690       break;
0691     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
0692       KindToSet = x86_64::PCRel32GOTLoadRelaxable;
0693       break;
0694     case x86_64::RequestGOTAndTransformToDelta64:
0695       KindToSet = x86_64::Delta64;
0696       break;
0697     case x86_64::RequestGOTAndTransformToDelta64FromGOT:
0698       KindToSet = x86_64::Delta64FromGOT;
0699       break;
0700     case x86_64::RequestGOTAndTransformToDelta32:
0701       KindToSet = x86_64::Delta32;
0702       break;
0703     default:
0704       return false;
0705     }
0706     assert(KindToSet != Edge::Invalid &&
0707            "Fell through switch, but no new kind to set");
0708     DEBUG_WITH_TYPE("jitlink", {
0709       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
0710              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
0711              << formatv("{0:x}", E.getOffset()) << ")\n";
0712     });
0713     E.setKind(KindToSet);
0714     E.setTarget(getEntryForTarget(G, E.getTarget()));
0715     return true;
0716   }
0717 
0718   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
0719     return createAnonymousPointer(G, getGOTSection(G), &Target);
0720   }
0721 
0722 private:
0723   Section &getGOTSection(LinkGraph &G) {
0724     if (!GOTSection)
0725       GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
0726     return *GOTSection;
0727   }
0728 
0729   void registerExistingEntries();
0730 
0731   Section *GOTSection = nullptr;
0732 };
0733 
0734 /// Procedure Linkage Table Builder.
0735 class PLTTableManager : public TableManager<PLTTableManager> {
0736 public:
0737   static StringRef getSectionName() { return "$__STUBS"; }
0738 
0739   PLTTableManager(LinkGraph &G, GOTTableManager &GOT) : GOT(GOT) {
0740     if ((StubsSection = G.findSectionByName(getSectionName())))
0741       registerExistingEntries();
0742   }
0743 
0744   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
0745     if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
0746       DEBUG_WITH_TYPE("jitlink", {
0747         dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
0748                << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
0749                << formatv("{0:x}", E.getOffset()) << ")\n";
0750       });
0751       // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
0752       // be optimized when the target is in-range.
0753       E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
0754       E.setTarget(getEntryForTarget(G, E.getTarget()));
0755       return true;
0756     }
0757     return false;
0758   }
0759 
0760   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
0761     return createAnonymousPointerJumpStub(G, getStubsSection(G),
0762                                           GOT.getEntryForTarget(G, Target));
0763   }
0764 
0765 public:
0766   Section &getStubsSection(LinkGraph &G) {
0767     if (!StubsSection)
0768       StubsSection = &G.createSection(getSectionName(),
0769                                       orc::MemProt::Read | orc::MemProt::Exec);
0770     return *StubsSection;
0771   }
0772 
0773   void registerExistingEntries();
0774 
0775   GOTTableManager &GOT;
0776   Section *StubsSection = nullptr;
0777 };
0778 
0779 /// Optimize the GOT and Stub relocations if the edge target address is in range
0780 /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
0781 /// then replace GOT load with lea
0782 /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
0783 /// in range, replace a indirect jump by plt stub with a direct jump to the
0784 /// target
0785 Error optimizeGOTAndStubAccesses(LinkGraph &G);
0786 
0787 } // namespace x86_64
0788 } // end namespace jitlink
0789 } // end namespace llvm
0790 
0791 #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H