Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

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

  1. //=== i386.h - Generic JITLink i386 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 i386 objects.
  10. //
  11. //===----------------------------------------------------------------------===//
  12.  
  13. #ifndef LLVM_EXECUTIONENGINE_JITLINK_I386_H
  14. #define LLVM_EXECUTIONENGINE_JITLINK_I386_H
  15.  
  16. #include "llvm/ExecutionEngine/JITLink/JITLink.h"
  17. #include "llvm/ExecutionEngine/JITLink/TableManager.h"
  18.  
  19. namespace llvm::jitlink::i386 {
  20. /// Represets i386 fixups
  21. enum EdgeKind_i386 : Edge::Kind {
  22.  
  23.   /// None
  24.   None = Edge::FirstRelocation,
  25.  
  26.   /// A plain 32-bit pointer value relocation.
  27.   ///
  28.   /// Fixup expression:
  29.   ///   Fixup <- Target + Addend : uint32
  30.   ///
  31.   /// Errors:
  32.   ///   - The target must reside in the low 32-bits of the address space,
  33.   ///     otherwise an out-of-range error will be returned.
  34.   ///
  35.   Pointer32,
  36.  
  37.   /// A 32-bit PC-relative relocation.
  38.   ///
  39.   /// Represents a data/control flow instruction using PC-relative addressing
  40.   /// to a target.
  41.   ///
  42.   /// The fixup expression for this kind includes an implicit offset to account
  43.   /// for the PC (unlike the Delta edges) so that a PCRel32 with a target
  44.   /// T and addend zero is a call/branch to the start (offset zero) of T.
  45.   ///
  46.   /// Fixup expression:
  47.   ///   Fixup <- Target - (Fixup + 4) + Addend : int32
  48.   ///
  49.   /// Errors:
  50.   ///   - The result of the fixup expression must fit into an int32, otherwise
  51.   ///     an out-of-range error will be returned.
  52.   ///
  53.   PCRel32,
  54.  
  55.   /// A plain 16-bit pointer value relocation.
  56.   ///
  57.   /// Fixup expression:
  58.   ///   Fixup <- Target + Addend : uint16
  59.   ///
  60.   /// Errors:
  61.   ///   - The target must reside in the low 16-bits of the address space,
  62.   ///     otherwise an out-of-range error will be returned.
  63.   ///
  64.   Pointer16,
  65.  
  66.   /// A 16-bit PC-relative relocation.
  67.   ///
  68.   /// Represents a data/control flow instruction using PC-relative addressing
  69.   /// to a target.
  70.   ///
  71.   /// The fixup expression for this kind includes an implicit offset to account
  72.   /// for the PC (unlike the Delta edges) so that a PCRel16 with a target
  73.   /// T and addend zero is a call/branch to the start (offset zero) of T.
  74.   ///
  75.   /// Fixup expression:
  76.   ///   Fixup <- Target - (Fixup + 4) + Addend : int16
  77.   ///
  78.   /// Errors:
  79.   ///   - The result of the fixup expression must fit into an int16, otherwise
  80.   ///     an out-of-range error will be returned.
  81.   ///
  82.   PCRel16,
  83.  
  84.   /// A 32-bit delta.
  85.   ///
  86.   /// Delta from the fixup to the target.
  87.   ///
  88.   /// Fixup expression:
  89.   ///   Fixup <- Target - Fixup + Addend : int64
  90.   ///
  91.   /// Errors:
  92.   ///   - The result of the fixup expression must fit into an int32, otherwise
  93.   ///     an out-of-range error will be returned.
  94.   Delta32,
  95.  
  96.   /// A 32-bit GOT delta.
  97.   ///
  98.   /// Delta from the global offset table to the target.
  99.   ///
  100.   /// Fixup expression:
  101.   ///   Fixup <- Target - GOTSymbol + Addend : int32
  102.   ///
  103.   /// Errors:
  104.   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
  105.   ///     symbol was not been defined.
  106.   Delta32FromGOT,
  107.  
  108.   /// A GOT entry offset within GOT getter/constructor, transformed to
  109.   /// Delta32FromGOT pointing at the GOT entry for the original target.
  110.   ///
  111.   /// Indicates that this edge should be transformed into a Delta32FromGOT
  112.   /// targeting the GOT entry for the edge's current target, maintaining the
  113.   /// same addend.
  114.   /// A GOT entry for the target should be created if one does not already
  115.   /// exist.
  116.   ///
  117.   /// Edges of this kind are usually handled by a GOT builder pass inserted by
  118.   /// default
  119.   ///
  120.   /// Fixup expression:
  121.   ///   NONE
  122.   ///
  123.   /// Errors:
  124.   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  125.   ///     phase will result in an assert/unreachable during the fixup phase
  126.   RequestGOTAndTransformToDelta32FromGOT,
  127. };
  128.  
  129. /// Returns a string name for the given i386 edge. For debugging purposes
  130. /// only
  131. const char *getEdgeKindName(Edge::Kind K);
  132.  
  133. /// Returns true if the given uint32_t value is in range for a uint16_t.
  134. inline bool isInRangeForImmU16(uint32_t Value) {
  135.   return Value <= std::numeric_limits<uint16_t>::max();
  136. }
  137.  
  138. /// Returns true if the given int32_t value is in range for an int16_t.
  139. inline bool isInRangeForImmS16(int32_t Value) {
  140.   return (Value >= std::numeric_limits<int16_t>::min() &&
  141.           Value <= std::numeric_limits<int16_t>::max());
  142. }
  143.  
  144. /// Apply fixup expression for edge to block content.
  145. inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
  146.                         const Symbol *GOTSymbol) {
  147.   using namespace i386;
  148.   using namespace llvm::support;
  149.  
  150.   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
  151.   char *FixupPtr = BlockWorkingMem + E.getOffset();
  152.   auto FixupAddress = B.getAddress() + E.getOffset();
  153.  
  154.   switch (E.getKind()) {
  155.   case i386::None: {
  156.     break;
  157.   }
  158.  
  159.   case i386::Pointer32: {
  160.     uint32_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  161.     *(ulittle32_t *)FixupPtr = Value;
  162.     break;
  163.   }
  164.  
  165.   case i386::PCRel32: {
  166.     int32_t Value =
  167.         E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
  168.     *(little32_t *)FixupPtr = Value;
  169.     break;
  170.   }
  171.  
  172.   case i386::Pointer16: {
  173.     uint32_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  174.     if (LLVM_LIKELY(isInRangeForImmU16(Value)))
  175.       *(ulittle16_t *)FixupPtr = Value;
  176.     else
  177.       return makeTargetOutOfRangeError(G, B, E);
  178.     break;
  179.   }
  180.  
  181.   case i386::PCRel16: {
  182.     int32_t Value =
  183.         E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
  184.     if (LLVM_LIKELY(isInRangeForImmS16(Value)))
  185.       *(little16_t *)FixupPtr = Value;
  186.     else
  187.       return makeTargetOutOfRangeError(G, B, E);
  188.     break;
  189.   }
  190.  
  191.   case i386::Delta32: {
  192.     int32_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  193.     *(little32_t *)FixupPtr = Value;
  194.     break;
  195.   }
  196.  
  197.   case i386::Delta32FromGOT: {
  198.     assert(GOTSymbol && "No GOT section symbol");
  199.     int32_t Value =
  200.         E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
  201.     *(little32_t *)FixupPtr = Value;
  202.     break;
  203.   }
  204.  
  205.   default:
  206.     return make_error<JITLinkError>(
  207.         "In graph " + G.getName() + ", section " + B.getSection().getName() +
  208.         "unsupported edge kind" + getEdgeKindName(E.getKind()));
  209.   }
  210.  
  211.   return Error::success();
  212. }
  213.  
  214. /// i386 pointer size.
  215. constexpr uint32_t PointerSize = 4;
  216.  
  217. /// i386 null pointer content.
  218. extern const char NullPointerContent[PointerSize];
  219.  
  220. /// Creates a new pointer block in the given section and returns an anonymous
  221. /// symbol pointing to it.
  222. ///
  223. /// If InitialTarget is given then an Pointer32 relocation will be added to the
  224. /// block pointing at InitialTarget.
  225. ///
  226. /// The pointer block will have the following default values:
  227. ///   alignment: 32-bit
  228. ///   alignment-offset: 0
  229. ///   address: highest allowable (~7U)
  230. inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
  231.                                       Symbol *InitialTarget = nullptr,
  232.                                       uint64_t InitialAddend = 0) {
  233.   auto &B = G.createContentBlock(PointerSection, NullPointerContent,
  234.                                  orc::ExecutorAddr(), 8, 0);
  235.   if (InitialTarget)
  236.     B.addEdge(Pointer32, 0, *InitialTarget, InitialAddend);
  237.   return G.addAnonymousSymbol(B, 0, PointerSize, false, false);
  238. }
  239.  
  240. /// Global Offset Table Builder.
  241. class GOTTableManager : public TableManager<GOTTableManager> {
  242. public:
  243.   static StringRef getSectionName() { return "$__GOT"; }
  244.  
  245.   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
  246.     Edge::Kind KindToSet = Edge::Invalid;
  247.     switch (E.getKind()) {
  248.     case i386::Delta32FromGOT: {
  249.       // we need to make sure that the GOT section exists, but don't otherwise
  250.       // need to fix up this edge
  251.       getGOTSection(G);
  252.       return false;
  253.     }
  254.     case i386::RequestGOTAndTransformToDelta32FromGOT:
  255.       KindToSet = i386::Delta32FromGOT;
  256.       break;
  257.     default:
  258.       return false;
  259.     }
  260.     assert(KindToSet != Edge::Invalid &&
  261.            "Fell through switch, but no new kind to set");
  262.     DEBUG_WITH_TYPE("jitlink", {
  263.       dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
  264.              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
  265.              << formatv("{0:x}", E.getOffset()) << ")\n";
  266.     });
  267.     E.setKind(KindToSet);
  268.     E.setTarget(getEntryForTarget(G, E.getTarget()));
  269.     return true;
  270.   }
  271.  
  272.   Symbol &createEntry(LinkGraph &G, Symbol &Target) {
  273.     return createAnonymousPointer(G, getGOTSection(G), &Target);
  274.   }
  275.  
  276. private:
  277.   Section &getGOTSection(LinkGraph &G) {
  278.     if (!GOTSection)
  279.       GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
  280.     return *GOTSection;
  281.   }
  282.  
  283.   Section *GOTSection = nullptr;
  284. };
  285.  
  286. } // namespace llvm::jitlink::i386
  287.  
  288. #endif // LLVM_EXECUTIONENGINE_JITLINK_I386_H
  289.