Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===-- x86_64.h - Generic JITLink x86-64 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 x86-64 objects.
  10. //
  11. //===----------------------------------------------------------------------===//
  12.  
  13. #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
  14. #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
  15.  
  16. #include "llvm/ExecutionEngine/JITLink/JITLink.h"
  17. #include "llvm/ExecutionEngine/JITLink/TableManager.h"
  18.  
  19. #include <limits>
  20.  
  21. namespace llvm {
  22. namespace jitlink {
  23. namespace x86_64 {
  24.  
  25. /// Represents x86-64 fixups and other x86-64-specific edge kinds.
  26. enum EdgeKind_x86_64 : 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.   /// A plain 32-bit pointer value relocation.
  36.   ///
  37.   /// Fixup expression:
  38.   ///   Fixup <- Target + Addend : uint32
  39.   ///
  40.   /// Errors:
  41.   ///   - The target must reside in the low 32-bits of the address space,
  42.   ///     otherwise an out-of-range error will be returned.
  43.   ///
  44.   Pointer32,
  45.  
  46.   /// A signed 32-bit pointer value relocation
  47.   ///
  48.   /// Fixup expression:
  49.   ///   Fixup <- Target + Addend : int32
  50.   ///
  51.   /// Errors:
  52.   ///   - The target must reside in the signed 32-bits([-2**31, 2**32 - 1]) of
  53.   ///   the address space, otherwise an out-of-range error will be returned.
  54.   Pointer32Signed,
  55.  
  56.   /// A plain 16-bit pointer value relocation.
  57.   ///
  58.   /// Fixup expression:
  59.   ///   Fixup <- Target + Addend : uint16
  60.   ///
  61.   /// Errors:
  62.   ///   - The target must reside in the low 16-bits of the address space,
  63.   ///     otherwise an out-of-range error will be returned.
  64.   ///
  65.   Pointer16,
  66.  
  67.   /// A 64-bit delta.
  68.   ///
  69.   /// Delta from the fixup to the target.
  70.   ///
  71.   /// Fixup expression:
  72.   ///   Fixup <- Target - Fixup + Addend : int64
  73.   ///
  74.   Delta64,
  75.  
  76.   /// A 32-bit delta.
  77.   ///
  78.   /// Delta from the fixup to the target.
  79.   ///
  80.   /// Fixup expression:
  81.   ///   Fixup <- Target - Fixup + Addend : int64
  82.   ///
  83.   /// Errors:
  84.   ///   - The result of the fixup expression must fit into an int32, otherwise
  85.   ///     an out-of-range error will be returned.
  86.   ///
  87.   Delta32,
  88.  
  89.   /// A 64-bit negative delta.
  90.   ///
  91.   /// Delta from target back to the fixup.
  92.   ///
  93.   /// Fixup expression:
  94.   ///   Fixup <- Fixup - Target + Addend : int64
  95.   ///
  96.   NegDelta64,
  97.  
  98.   /// A 32-bit negative delta.
  99.   ///
  100.   /// Delta from the target back to the fixup.
  101.   ///
  102.   /// Fixup expression:
  103.   ///   Fixup <- Fixup - Target + Addend : int32
  104.   ///
  105.   /// Errors:
  106.   ///   - The result of the fixup expression must fit into an int32, otherwise
  107.   ///     an out-of-range error will be returned.
  108.   NegDelta32,
  109.  
  110.   /// A 64-bit GOT delta.
  111.   ///
  112.   /// Delta from the global offset table to the target
  113.   ///
  114.   /// Fixup expression:
  115.   ///   Fixup <- Target - GOTSymbol + Addend : int64
  116.   ///
  117.   /// Errors:
  118.   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
  119.   ///     symbol was not been defined.
  120.   Delta64FromGOT,
  121.  
  122.   /// A 32-bit PC-relative branch.
  123.   ///
  124.   /// Represents a PC-relative call or branch to a target. This can be used to
  125.   /// identify, record, and/or patch call sites.
  126.   ///
  127.   /// The fixup expression for this kind includes an implicit offset to account
  128.   /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target
  129.   /// T and addend zero is a call/branch to the start (offset zero) of T.
  130.   ///
  131.   /// Fixup expression:
  132.   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
  133.   ///
  134.   /// Errors:
  135.   ///   - The result of the fixup expression must fit into an int32, otherwise
  136.   ///     an out-of-range error will be returned.
  137.   ///
  138.   BranchPCRel32,
  139.  
  140.   /// A 32-bit PC-relative relocation.
  141.   ///
  142.   /// Represents a data/control flow instruction using PC-relative addressing
  143.   /// to a target.
  144.   ///
  145.   /// The fixup expression for this kind includes an implicit offset to account
  146.   /// for the PC (unlike the Delta edges) so that a PCRel32 with a target
  147.   /// T and addend zero is a call/branch to the start (offset zero) of T.
  148.   ///
  149.   /// Fixup expression:
  150.   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
  151.   ///
  152.   /// Errors:
  153.   ///   - The result of the fixup expression must fit into an int32, otherwise
  154.   ///     an out-of-range error will be returned.
  155.   ///
  156.   PCRel32,
  157.  
  158.   /// A 32-bit PC-relative branch to a pointer jump stub.
  159.   ///
  160.   /// The target of this relocation should be a pointer jump stub of the form:
  161.   ///
  162.   /// \code{.s}
  163.   ///   .text
  164.   ///   jmpq *tgtptr(%rip)
  165.   ///   ; ...
  166.   ///
  167.   ///   .data
  168.   ///   tgtptr:
  169.   ///     .quad 0
  170.   /// \endcode
  171.   ///
  172.   /// This edge kind has the same fixup expression as BranchPCRel32, but further
  173.   /// identifies the call/branch as being to a pointer jump stub. For edges of
  174.   /// this kind the jump stub should not be bypassed (use
  175.   /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location
  176.   /// target may be recorded to allow manipulation at runtime.
  177.   ///
  178.   /// Fixup expression:
  179.   ///   Fixup <- Target - Fixup + Addend - 4 : int32
  180.   ///
  181.   /// Errors:
  182.   ///   - The result of the fixup expression must fit into an int32, otherwise
  183.   ///     an out-of-range error will be returned.
  184.   ///
  185.   BranchPCRel32ToPtrJumpStub,
  186.  
  187.   /// A relaxable version of BranchPCRel32ToPtrJumpStub.
  188.   ///
  189.   /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
  190.   /// but identifies the call/branch as being to a pointer jump stub that may be
  191.   /// bypassed with a direct jump to the ultimate target if the ultimate target
  192.   /// is within range of the fixup location.
  193.   ///
  194.   /// Fixup expression:
  195.   ///   Fixup <- Target - Fixup + Addend - 4: int32
  196.   ///
  197.   /// Errors:
  198.   ///   - The result of the fixup expression must fit into an int32, otherwise
  199.   ///     an out-of-range error will be returned.
  200.   ///
  201.   BranchPCRel32ToPtrJumpStubBypassable,
  202.  
  203.   /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
  204.   /// entry for the original target.
  205.   ///
  206.   /// Indicates that this edge should be transformed into a Delta32 targeting
  207.   /// the GOT entry for the edge's current target, maintaining the same addend.
  208.   /// A GOT entry for the target should be created if one does not already
  209.   /// exist.
  210.   ///
  211.   /// Edges of this kind are usually handled by a GOT builder pass inserted by
  212.   /// default.
  213.   ///
  214.   /// Fixup expression:
  215.   ///   NONE
  216.   ///
  217.   /// Errors:
  218.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  219.   ///     phase will result in an assert/unreachable during the fixup phase.
  220.   ///
  221.   RequestGOTAndTransformToDelta32,
  222.  
  223.   /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
  224.   /// entry for the original target.
  225.   ///
  226.   /// Indicates that this edge should be transformed into a Delta64 targeting
  227.   /// the GOT entry for the edge's current target, maintaining the same addend.
  228.   /// A GOT entry for the target should be created if one does not already
  229.   /// exist.
  230.   ///
  231.   /// Edges of this kind are usually handled by a GOT builder pass inserted by
  232.   /// default.
  233.   ///
  234.   /// Fixup expression:
  235.   ///   NONE
  236.   ///
  237.   /// Errors:
  238.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  239.   ///     phase will result in an assert/unreachable during the fixup phase.
  240.   ///
  241.   RequestGOTAndTransformToDelta64,
  242.  
  243.   /// A GOT entry offset within GOT getter/constructor, transformed to
  244.   /// Delta64FromGOT
  245.   /// pointing at the GOT entry for the original target
  246.   ///
  247.   /// Indicates that this edge should be transformed into a Delta64FromGOT
  248.   /// targeting
  249.   /// the GOT entry for the edge's current target, maintaining the same addend.
  250.   /// A GOT entry for the target should be created if one does not already
  251.   /// exist.
  252.   ///
  253.   /// Edges of this kind are usually handled by a GOT builder pass inserted by
  254.   /// default
  255.   ///
  256.   /// Fixup expression:
  257.   ///   NONE
  258.   ///
  259.   /// Errors:
  260.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  261.   ///     phase will result in an assert/unreachable during the fixup phase
  262.   RequestGOTAndTransformToDelta64FromGOT,
  263.  
  264.   /// A PC-relative load of a GOT entry, relaxable if GOT entry target is
  265.   /// in-range of the fixup
  266.   ///
  267.   /// TODO: Explain the optimization
  268.   ///
  269.   /// Fixup expression
  270.   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
  271.   ///
  272.   /// Errors:
  273.   ///   - The result of the fixup expression must fit into an int32, otherwise
  274.   ///     an out-of-range error will be returned.
  275.   //
  276.   PCRel32GOTLoadRelaxable,
  277.  
  278.   /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target
  279.   /// is in-range of the fixup.
  280.   ///
  281.   /// If the GOT entry target is in-range of the fixup then the load from the
  282.   /// GOT may be replaced with a direct memory address calculation.
  283.   ///
  284.   /// Fixup expression:
  285.   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
  286.   ///
  287.   /// Errors:
  288.   ///   - The result of the fixup expression must fit into an int32, otherwise
  289.   ///     an out-of-range error will be returned.
  290.   ///
  291.   PCRel32GOTLoadREXRelaxable,
  292.  
  293.   /// A GOT entry getter/constructor, transformed to
  294.   /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original
  295.   /// target.
  296.   ///
  297.   /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable
  298.   /// targeting the GOT entry for the edge's current target, maintaining the
  299.   /// same addend. A GOT entry for the target should be created if one does not
  300.   /// already exist.
  301.   ///
  302.   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
  303.   /// default.
  304.   ///
  305.   /// Fixup expression:
  306.   ///   NONE
  307.   ///
  308.   /// Errors:
  309.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  310.   ///     phase will result in an assert/unreachable during the fixup phase.
  311.   ///
  312.   RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable,
  313.  
  314.   /// A GOT entry getter/constructor, transformed to
  315.   /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original
  316.   /// target.
  317.   ///
  318.   /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable
  319.   /// targeting the GOT entry for the edge's current target, maintaining the
  320.   /// same addend. A GOT entry for the target should be created if one does not
  321.   /// already exist.
  322.   ///
  323.   /// Edges of this kind are usually lowered by a GOT builder pass inserted by
  324.   /// default.
  325.   ///
  326.   /// Fixup expression:
  327.   ///   NONE
  328.   ///
  329.   /// Errors:
  330.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  331.   ///     phase will result in an assert/unreachable during the fixup phase.
  332.   ///
  333.   RequestGOTAndTransformToPCRel32GOTLoadRelaxable,
  334.  
  335.   /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry,
  336.   /// relaxable if the TLVP entry target is in-range of the fixup.
  337.   ///
  338.   /// If the TLVP entry target is in-range of the fixup then the load from the
  339.   /// TLVP may be replaced with a direct memory address calculation.
  340.   ///
  341.   /// The target of this edge must be a thread local variable entry of the form
  342.   ///   .quad <tlv getter thunk>
  343.   ///   .quad <tlv key>
  344.   ///   .quad <tlv initializer>
  345.   ///
  346.   /// Fixup expression:
  347.   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
  348.   ///
  349.   /// Errors:
  350.   ///   - The result of the fixup expression must fit into an int32, otherwise
  351.   ///     an out-of-range error will be returned.
  352.   ///   - The target must be either external, or a TLV entry of the required
  353.   ///     form, otherwise a malformed TLV entry error will be returned.
  354.   ///
  355.   PCRel32TLVPLoadREXRelaxable,
  356.  
  357.   /// TODO: Explain the generic edge kind
  358.   RequestTLSDescInGOTAndTransformToDelta32,
  359.  
  360.   /// A TLVP entry getter/constructor, transformed to
  361.   /// Delta32ToTLVPLoadREXRelaxable.
  362.   ///
  363.   /// Indicates that this edge should be transformed into a
  364.   /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's
  365.   /// current target. A TLVP entry for the target should be created if one does
  366.   /// not already exist.
  367.   ///
  368.   /// Fixup expression:
  369.   ///   NONE
  370.   ///
  371.   /// Errors:
  372.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  373.   ///     phase will result in an assert/unreachable during the fixup phase.
  374.   ///
  375.   RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable,
  376.   // First platform specific relocation.
  377.   FirstPlatformRelocation
  378. };
  379.  
  380. /// Returns a string name for the given x86-64 edge. For debugging purposes
  381. /// only.
  382. const char *getEdgeKindName(Edge::Kind K);
  383.  
  384. /// Returns true if the given uint64_t value is in range for a uint32_t.
  385. inline bool isInRangeForImmU32(uint64_t Value) {
  386.   return Value <= std::numeric_limits<uint32_t>::max();
  387. }
  388.  
  389. /// Returns true if the given int64_t value is in range for an int32_t.
  390. inline bool isInRangeForImmS32(int64_t Value) {
  391.   return (Value >= std::numeric_limits<int32_t>::min() &&
  392.           Value <= std::numeric_limits<int32_t>::max());
  393. }
  394.  
  395. /// Apply fixup expression for edge to block content.
  396. inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
  397.                         const Symbol *GOTSymbol) {
  398.   using namespace support;
  399.  
  400.   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
  401.   char *FixupPtr = BlockWorkingMem + E.getOffset();
  402.   auto FixupAddress = B.getAddress() + E.getOffset();
  403.  
  404.   switch (E.getKind()) {
  405.  
  406.   case Pointer64: {
  407.     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  408.     *(ulittle64_t *)FixupPtr = Value;
  409.     break;
  410.   }
  411.  
  412.   case Pointer32: {
  413.     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  414.     if (LLVM_LIKELY(isInRangeForImmU32(Value)))
  415.       *(ulittle32_t *)FixupPtr = Value;
  416.     else
  417.       return makeTargetOutOfRangeError(G, B, E);
  418.     break;
  419.   }
  420.   case Pointer32Signed: {
  421.     int64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  422.     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  423.       *(little32_t *)FixupPtr = Value;
  424.     else
  425.       return makeTargetOutOfRangeError(G, B, E);
  426.     break;
  427.   }
  428.  
  429.   case Pointer16: {
  430.     uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  431.     if (LLVM_LIKELY(isUInt<16>(Value)))
  432.       *(ulittle16_t *)FixupPtr = Value;
  433.     else
  434.       return makeTargetOutOfRangeError(G, B, E);
  435.     break;
  436.   }
  437.  
  438.   case PCRel32:
  439.   case BranchPCRel32:
  440.   case BranchPCRel32ToPtrJumpStub:
  441.   case BranchPCRel32ToPtrJumpStubBypassable:
  442.   case PCRel32GOTLoadRelaxable:
  443.   case PCRel32GOTLoadREXRelaxable:
  444.   case PCRel32TLVPLoadREXRelaxable: {
  445.     int64_t Value =
  446.         E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
  447.     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  448.       *(little32_t *)FixupPtr = Value;
  449.     else
  450.       return makeTargetOutOfRangeError(G, B, E);
  451.     break;
  452.   }
  453.  
  454.   case Delta64: {
  455.     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  456.     *(little64_t *)FixupPtr = Value;
  457.     break;
  458.   }
  459.  
  460.   case Delta32: {
  461.     int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  462.     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  463.       *(little32_t *)FixupPtr = Value;
  464.     else
  465.       return makeTargetOutOfRangeError(G, B, E);
  466.     break;
  467.   }
  468.  
  469.   case NegDelta64: {
  470.     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
  471.     *(little64_t *)FixupPtr = Value;
  472.     break;
  473.   }
  474.  
  475.   case NegDelta32: {
  476.     int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
  477.     if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  478.       *(little32_t *)FixupPtr = Value;
  479.     else
  480.       return makeTargetOutOfRangeError(G, B, E);
  481.     break;
  482.   }
  483.   case Delta64FromGOT: {
  484.     assert(GOTSymbol && "No GOT section symbol");
  485.     int64_t Value =
  486.         E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
  487.     *(little64_t *)FixupPtr = Value;
  488.     break;
  489.   }
  490.  
  491.   default:
  492.     return make_error<JITLinkError>(
  493.         "In graph " + G.getName() + ", section " + B.getSection().getName() +
  494.         "unsupported edge kind" + getEdgeKindName(E.getKind()));
  495.   }
  496.  
  497.   return Error::success();
  498. }
  499.  
  500. /// x86_64 pointer size.
  501. constexpr uint64_t PointerSize = 8;
  502.  
  503. /// x86-64 null pointer content.
  504. extern const char NullPointerContent[PointerSize];
  505.  
  506. /// x86-64 pointer jump stub content.
  507. ///
  508. /// Contains the instruction sequence for an indirect jump via an in-memory
  509. /// pointer:
  510. ///   jmpq *ptr(%rip)
  511. extern const char PointerJumpStubContent[6];
  512.  
  513. /// Creates a new pointer block in the given section and returns an anonymous
  514. /// symbol pointing to it.
  515. ///
  516. /// If InitialTarget is given then an Pointer64 relocation will be added to the
  517. /// block pointing at InitialTarget.
  518. ///
  519. /// The pointer block will have the following default values:
  520. ///   alignment: 64-bit
  521. ///   alignment-offset: 0
  522. ///   address: highest allowable (~7U)
  523. inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
  524.                                       Symbol *InitialTarget = nullptr,
  525.                                       uint64_t InitialAddend = 0) {
  526.   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
  527.                                  orc::ExecutorAddr(~uint64_t(7)), 8, 0);
  528.   if (InitialTarget)
  529.     B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
  530.   return G.addAnonymousSymbol(B, 0, 8, false, false);
  531. }
  532.  
  533. /// Create a jump stub block that jumps via the pointer at the given symbol.
  534. ///
  535. /// The stub block will have the following default values:
  536. ///   alignment: 8-bit
  537. ///   alignment-offset: 0
  538. ///   address: highest allowable: (~5U)
  539. inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
  540.                                          Symbol &PointerSymbol) {
  541.   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
  542.                                  orc::ExecutorAddr(~uint64_t(5)), 1, 0);
  543.   B.addEdge(Delta32, 2, PointerSymbol, -4);
  544.   return B;
  545. }
  546.  
  547. /// Create a jump stub that jumps via the pointer at the given symbol and
  548. /// an anonymous symbol pointing to it. Return the anonymous symbol.
  549. ///
  550. /// The stub block will be created by createPointerJumpStubBlock.
  551. inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
  552.                                               Section &StubSection,
  553.                                               Symbol &PointerSymbol) {
  554.   return G.addAnonymousSymbol(
  555.       createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
  556.       false);
  557. }
  558.  
  559. /// Global Offset Table Builder.
  560. class GOTTableManager : public TableManager<GOTTableManager> {
  561. public:
  562.   static StringRef getSectionName() { return "$__GOT"; }
  563.  
  564.   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
  565.     Edge::Kind KindToSet = Edge::Invalid;
  566.     switch (E.getKind()) {
  567.     case x86_64::Delta64FromGOT: {
  568.       // we need to make sure that the GOT section exists, but don't otherwise
  569.       // need to fix up this edge
  570.       getGOTSection(G);
  571.       return false;
  572.     }
  573.     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
  574.       KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
  575.       break;
  576.     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
  577.       KindToSet = x86_64::PCRel32GOTLoadRelaxable;
  578.       break;
  579.     case x86_64::RequestGOTAndTransformToDelta64:
  580.       KindToSet = x86_64::Delta64;
  581.       break;
  582.     case x86_64::RequestGOTAndTransformToDelta64FromGOT:
  583.       KindToSet = x86_64::Delta64FromGOT;
  584.       break;
  585.     case x86_64::RequestGOTAndTransformToDelta32:
  586.       KindToSet = x86_64::Delta32;
  587.       break;
  588.     default:
  589.       return false;
  590.     }
  591.     assert(KindToSet != Edge::Invalid &&
  592.            "Fell through switch, but no new kind to set");
  593.     DEBUG_WITH_TYPE("jitlink", {
  594.       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
  595.              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
  596.              << formatv("{0:x}", E.getOffset()) << ")\n";
  597.     });
  598.     E.setKind(KindToSet);
  599.     E.setTarget(getEntryForTarget(G, E.getTarget()));
  600.     return true;
  601.   }
  602.  
  603.   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
  604.     return createAnonymousPointer(G, getGOTSection(G), &Target);
  605.   }
  606.  
  607. private:
  608.   Section &getGOTSection(LinkGraph &G) {
  609.     if (!GOTSection)
  610.       GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
  611.     return *GOTSection;
  612.   }
  613.  
  614.   Section *GOTSection = nullptr;
  615. };
  616.  
  617. /// Procedure Linkage Table Builder.
  618. class PLTTableManager : public TableManager<PLTTableManager> {
  619. public:
  620.   PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
  621.  
  622.   static StringRef getSectionName() { return "$__STUBS"; }
  623.  
  624.   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
  625.     if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
  626.       DEBUG_WITH_TYPE("jitlink", {
  627.         dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
  628.                << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
  629.                << formatv("{0:x}", E.getOffset()) << ")\n";
  630.       });
  631.       // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
  632.       // be optimized when the target is in-range.
  633.       E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
  634.       E.setTarget(getEntryForTarget(G, E.getTarget()));
  635.       return true;
  636.     }
  637.     return false;
  638.   }
  639.  
  640.   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
  641.     return createAnonymousPointerJumpStub(G, getStubsSection(G),
  642.                                           GOT.getEntryForTarget(G, Target));
  643.   }
  644.  
  645. public:
  646.   Section &getStubsSection(LinkGraph &G) {
  647.     if (!PLTSection)
  648.       PLTSection = &G.createSection(getSectionName(),
  649.                                     orc::MemProt::Read | orc::MemProt::Exec);
  650.     return *PLTSection;
  651.   }
  652.  
  653.   GOTTableManager &GOT;
  654.   Section *PLTSection = nullptr;
  655. };
  656.  
  657. /// Optimize the GOT and Stub relocations if the edge target address is in range
  658. /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
  659. /// then replace GOT load with lea
  660. /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
  661. /// in range, replace a indirect jump by plt stub with a direct jump to the
  662. /// target
  663. Error optimizeGOTAndStubAccesses(LinkGraph &G);
  664.  
  665. } // namespace x86_64
  666. } // end namespace jitlink
  667. } // end namespace llvm
  668.  
  669. #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
  670.