reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
//===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing.
//
//===----------------------------------------------------------------------===//

#ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
#define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H

#include "llvm/ADT/DenseSet.h"
#include "llvm/ExecutionEngine/JITLink/JITLink.h"

#define DEBUG_TYPE "jitlink"

namespace llvm {

class MemoryBufferRef;

namespace jitlink {

/// Base class for a JIT linker.
///
/// A JITLinkerBase instance links one object file into an ongoing JIT
/// session. Symbol resolution and finalization operations are pluggable,
/// and called using continuation passing (passing a continuation for the
/// remaining linker work) to allow them to be performed asynchronously.
class JITLinkerBase {
public:
  JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes)
      : Ctx(std::move(Ctx)), Passes(std::move(Passes)) {
    assert(this->Ctx && "Ctx can not be null");
  }

  virtual ~JITLinkerBase();

protected:
  struct SegmentLayout {
    using BlocksList = std::vector<Block *>;

    BlocksList ContentBlocks;
    BlocksList ZeroFillBlocks;
  };

  using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>;

  // Phase 1:
  //   1.1: Build link graph
  //   1.2: Run pre-prune passes
  //   1.2: Prune graph
  //   1.3: Run post-prune passes
  //   1.4: Sort blocks into segments
  //   1.5: Allocate segment memory
  //   1.6: Identify externals and make an async call to resolve function
  void linkPhase1(std::unique_ptr<JITLinkerBase> Self);

  // Phase 2:
  //   2.1: Apply resolution results
  //   2.2: Fix up block contents
  //   2.3: Call OnResolved callback
  //   2.3: Make an async call to transfer and finalize memory.
  void linkPhase2(std::unique_ptr<JITLinkerBase> Self,
                  Expected<AsyncLookupResult> LookupResult,
                  SegmentLayoutMap Layout);

  // Phase 3:
  //   3.1: Call OnFinalized callback, handing off allocation.
  void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err);

  // Build a graph from the given object buffer.
  // To be implemented by the client.
  virtual Expected<std::unique_ptr<LinkGraph>>
  buildGraph(MemoryBufferRef ObjBuffer) = 0;

  // For debug dumping of the link graph.
  virtual StringRef getEdgeKindName(Edge::Kind K) const = 0;

  // Alight a JITTargetAddress to conform with block alignment requirements.
  static JITTargetAddress alignToBlock(JITTargetAddress Addr, Block &B) {
    uint64_t Delta = (B.getAlignmentOffset() - Addr) % B.getAlignment();
    return Addr + Delta;
  }

  // Alight a pointer to conform with block alignment requirements.
  static char *alignToBlock(char *P, Block &B) {
    uint64_t PAddr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(P));
    uint64_t Delta = (B.getAlignmentOffset() - PAddr) % B.getAlignment();
    return P + Delta;
  }

private:
  // Run all passes in the given pass list, bailing out immediately if any pass
  // returns an error.
  Error runPasses(LinkGraphPassList &Passes);

  // Copy block contents and apply relocations.
  // Implemented in JITLinker.
  virtual Error
  copyAndFixUpBlocks(const SegmentLayoutMap &Layout,
                     JITLinkMemoryManager::Allocation &Alloc) const = 0;

  SegmentLayoutMap layOutBlocks();
  Error allocateSegments(const SegmentLayoutMap &Layout);
  DenseSet<StringRef> getExternalSymbolNames() const;
  void applyLookupResult(AsyncLookupResult LR);
  void deallocateAndBailOut(Error Err);

  void dumpGraph(raw_ostream &OS);

  std::unique_ptr<JITLinkContext> Ctx;
  PassConfiguration Passes;
  std::unique_ptr<LinkGraph> G;
  std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc;
};

template <typename LinkerImpl> class JITLinker : public JITLinkerBase {
public:
  using JITLinkerBase::JITLinkerBase;

  /// Link constructs a LinkerImpl instance and calls linkPhase1.
  /// Link should be called with the constructor arguments for LinkerImpl, which
  /// will be forwarded to the constructor.
  template <typename... ArgTs> static void link(ArgTs &&... Args) {
    auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...);

    // Ownership of the linker is passed into the linker's doLink function to
    // allow it to be passed on to async continuations.
    //
    // FIXME: Remove LTmp once we have c++17.
    // C++17 sequencing rules guarantee that function name expressions are
    // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be
    // well formed.
    auto &LTmp = *L;
    LTmp.linkPhase1(std::move(L));
  }

private:
  const LinkerImpl &impl() const {
    return static_cast<const LinkerImpl &>(*this);
  }

  Error
  copyAndFixUpBlocks(const SegmentLayoutMap &Layout,
                     JITLinkMemoryManager::Allocation &Alloc) const override {
    LLVM_DEBUG(dbgs() << "Copying and fixing up blocks:\n");
    for (auto &KV : Layout) {
      auto &Prot = KV.first;
      auto &SegLayout = KV.second;

      auto SegMem = Alloc.getWorkingMemory(
          static_cast<sys::Memory::ProtectionFlags>(Prot));
      char *LastBlockEnd = SegMem.data();
      char *BlockDataPtr = LastBlockEnd;

      LLVM_DEBUG({
        dbgs() << "  Processing segment "
               << static_cast<sys::Memory::ProtectionFlags>(Prot) << " [ "
               << (const void *)SegMem.data() << " .. "
               << (const void *)((char *)SegMem.data() + SegMem.size())
               << " ]\n    Processing content sections:\n";
      });

      for (auto *B : SegLayout.ContentBlocks) {
        LLVM_DEBUG(dbgs() << "    " << *B << ":\n");

        // Pad to alignment/alignment-offset.
        BlockDataPtr = alignToBlock(BlockDataPtr, *B);

        LLVM_DEBUG({
          dbgs() << "      Bumped block pointer to "
                 << (const void *)BlockDataPtr << " to meet block alignment "
                 << B->getAlignment() << " and alignment offset "
                 << B->getAlignmentOffset() << "\n";
        });

        // Zero pad up to alignment.
        LLVM_DEBUG({
          if (LastBlockEnd != BlockDataPtr)
            dbgs() << "      Zero padding from " << (const void *)LastBlockEnd
                   << " to " << (const void *)BlockDataPtr << "\n";
        });

        while (LastBlockEnd != BlockDataPtr)
          *LastBlockEnd++ = 0;

        // Copy initial block content.
        LLVM_DEBUG({
          dbgs() << "      Copying block " << *B << " content, "
                 << B->getContent().size() << " bytes, from "
                 << (const void *)B->getContent().data() << " to "
                 << (const void *)BlockDataPtr << "\n";
        });
        memcpy(BlockDataPtr, B->getContent().data(), B->getContent().size());

        // Copy Block data and apply fixups.
        LLVM_DEBUG(dbgs() << "      Applying fixups.\n");
        for (auto &E : B->edges()) {

          // Skip non-relocation edges.
          if (!E.isRelocation())
            continue;

          // Dispatch to LinkerImpl for fixup.
          if (auto Err = impl().applyFixup(*B, E, BlockDataPtr))
            return Err;
        }

        // Point the block's content to the fixed up buffer.
        B->setContent(StringRef(BlockDataPtr, B->getContent().size()));

        // Update block end pointer.
        LastBlockEnd = BlockDataPtr + B->getContent().size();
        BlockDataPtr = LastBlockEnd;
      }

      // Zero pad the rest of the segment.
      LLVM_DEBUG({
        dbgs() << "    Zero padding end of segment from "
               << (const void *)LastBlockEnd << " to "
               << (const void *)((char *)SegMem.data() + SegMem.size()) << "\n";
      });
      while (LastBlockEnd != SegMem.data() + SegMem.size())
        *LastBlockEnd++ = 0;
    }

    return Error::success();
  }
};

/// Removes dead symbols/blocks/addressables.
///
/// Finds the set of symbols and addressables reachable from any symbol
/// initially marked live. All symbols/addressables not marked live at the end
/// of this process are removed.
void prune(LinkGraph &G);

} // end namespace jitlink
} // end namespace llvm

#undef DEBUG_TYPE // "jitlink"

#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H